mirror of
https://github.com/rowboatlabs/rowboat.git
synced 2026-07-24 21:41:08 +02:00
feat(x): ambient meeting detection + take-notes popup (Granola parity phase 2)
- mic-monitor Swift helper: polls CoreAudio for mic-in-use, with owning PIDs on macOS 14.4+ (process-object API) so calls attribute to the app that actually holds the mic (Chrome vs Zoom vs Slack); no TCC permission needed. Compiled best-effort by bundle.mjs; exits when stdin closes - core meetings/detector: 5s mic debounce, PID→process attribution with running-app fallback, Granola labels (Huddle/Call/Meeting detected), calendar merge (event start −15min through end), once per mic session (30s idle reset), suppressed while Rowboat itself captures (recording or assistant voice call), gated by a meeting_detection notification category (Settings > Notifications) - popup: lean Granola-style bar (title + platform + Take notes pill, floating ×) in a transparent non-activating panel at screen-saver level with fullscreen-auxiliary behavior — floats over fullscreen meetings on the cursor's display; activation policy restored immediately so the Dock icon survives and Take Notes can foreground Rowboat - Take Notes routes into the existing take-meeting-notes flow with a synthetic or matched calendar event (source: detected); never records without a click - tray icon bumped to 18pt
This commit is contained in:
parent
9b0776596d
commit
66865b4f6b
13 changed files with 942 additions and 12 deletions
|
|
@ -734,6 +734,9 @@ const ipcSchemas = {
|
|||
// When true, the renderer should also open the meeting URL (Zoom/Meet/etc.)
|
||||
// in addition to triggering the take-notes flow.
|
||||
openMeeting: z.boolean().optional(),
|
||||
// Origin recorded in the note frontmatter: 'calendar-sync' (default) for
|
||||
// notification/deep-link starts, 'detected' for ambient meeting detection.
|
||||
source: z.string().optional(),
|
||||
}),
|
||||
res: z.null(),
|
||||
},
|
||||
|
|
@ -783,6 +786,48 @@ const ipcSchemas = {
|
|||
success: z.literal(true),
|
||||
}),
|
||||
},
|
||||
// Renderer → main: assistant voice/video call holds the mic — suppresses
|
||||
// ambient meeting detection (it would otherwise see our own capture).
|
||||
'voice:setCallActive': {
|
||||
req: z.object({
|
||||
active: z.boolean(),
|
||||
}),
|
||||
res: z.object({
|
||||
success: z.literal(true),
|
||||
}),
|
||||
},
|
||||
// --- Ambient meeting detection popup (own always-on-top window) ---
|
||||
// Main → popup: the detection to display.
|
||||
'meetingDetect:payload': {
|
||||
req: z.object({
|
||||
title: z.string(),
|
||||
message: z.string(),
|
||||
// Calendar-linked detections render a solid accent bar; ad-hoc ones a
|
||||
// dashed one (Granola's affordance).
|
||||
hasCalendarEvent: z.boolean(),
|
||||
}),
|
||||
res: z.null(),
|
||||
},
|
||||
// Popup → main: fetch the payload (the push can race listener registration).
|
||||
'meetingDetect:getPayload': {
|
||||
req: z.null(),
|
||||
res: z.object({
|
||||
payload: z
|
||||
.object({
|
||||
title: z.string(),
|
||||
message: z.string(),
|
||||
hasCalendarEvent: z.boolean(),
|
||||
})
|
||||
.nullable(),
|
||||
}),
|
||||
},
|
||||
// Popup → main: user clicked a button.
|
||||
'meetingDetect:action': {
|
||||
req: z.object({
|
||||
action: z.enum(['take-notes', 'dismiss']),
|
||||
}),
|
||||
res: z.object({}),
|
||||
},
|
||||
'granola:getConfig': {
|
||||
req: z.null(),
|
||||
res: z.object({
|
||||
|
|
|
|||
|
|
@ -7,12 +7,14 @@ import { z } from 'zod';
|
|||
* - new_email: a new email arrived during incremental Gmail sync
|
||||
* - agent_permission: an agent is requesting permission to run a tool
|
||||
* - background_task: a background task agent pinged via the notify-user tool
|
||||
* - meeting_detection: popup when Rowboat detects you're in a call/meeting
|
||||
*/
|
||||
export const NotificationCategorySchema = z.enum([
|
||||
'chat_completion',
|
||||
'new_email',
|
||||
'agent_permission',
|
||||
'background_task',
|
||||
'meeting_detection',
|
||||
]);
|
||||
|
||||
export const NotificationCategoriesSchema = z.object({
|
||||
|
|
@ -20,6 +22,7 @@ export const NotificationCategoriesSchema = z.object({
|
|||
new_email: z.boolean(),
|
||||
agent_permission: z.boolean(),
|
||||
background_task: z.boolean(),
|
||||
meeting_detection: z.boolean(),
|
||||
});
|
||||
|
||||
export const NotificationSettingsSchema = z.object({
|
||||
|
|
@ -32,6 +35,7 @@ export const DEFAULT_NOTIFICATION_SETTINGS: NotificationSettings = {
|
|||
new_email: true,
|
||||
agent_permission: true,
|
||||
background_task: true,
|
||||
meeting_detection: true,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue