@agent-native/core 0.91.1 → 0.92.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/blueprints/action/crud.md +1 -1
- package/blueprints/channel/discord.md +1 -1
- package/blueprints/provider/stripe.md +1 -1
- package/blueprints/sandbox/docker.md +1 -1
- package/corpus/README.md +2 -2
- package/corpus/core/CHANGELOG.md +31 -0
- package/corpus/core/blueprints/action/crud.md +1 -1
- package/corpus/core/blueprints/channel/discord.md +1 -1
- package/corpus/core/blueprints/provider/stripe.md +1 -1
- package/corpus/core/blueprints/sandbox/docker.md +1 -1
- package/corpus/core/docs/content/faq.mdx +17 -0
- package/corpus/core/docs/content/notifications.mdx +12 -6
- package/corpus/core/package.json +6 -5
- package/corpus/core/src/agent/production-agent.ts +140 -46
- package/corpus/core/src/agent/run-manager.ts +23 -2
- package/corpus/core/src/agent/run-store.ts +2 -2
- package/corpus/core/src/agent/tool-search.ts +71 -4
- package/corpus/core/src/cli/add.ts +1 -1
- package/corpus/core/src/cli/create.ts +8 -3
- package/corpus/core/src/cli/index.ts +25 -4
- package/corpus/core/src/cli/upgrade.ts +798 -0
- package/corpus/core/src/client/AssistantChat.tsx +1 -1
- package/corpus/core/src/client/HighlightedCodeBlock.tsx +20 -3
- package/corpus/core/src/client/agent-chat-adapter.ts +31 -6
- package/corpus/core/src/client/chat/message-components.tsx +85 -8
- package/corpus/core/src/client/chat/tool-call-display.tsx +355 -144
- package/corpus/core/src/client/code-agent-chat-adapter.ts +2 -9
- package/corpus/core/src/client/extensions/ExtensionSlot.tsx +7 -0
- package/corpus/core/src/client/settings/SettingsPanel.tsx +533 -389
- package/corpus/core/src/client/settings/SettingsSection.tsx +154 -17
- package/corpus/core/src/client/sse-event-processor.ts +29 -2
- package/corpus/core/src/extensions/actions.ts +113 -5
- package/corpus/core/src/jobs/scheduler.ts +30 -1
- package/corpus/core/src/localization/default-messages.ts +21 -0
- package/corpus/core/src/notifications/channels.ts +88 -25
- package/corpus/core/src/notifications/registry.ts +17 -3
- package/corpus/core/src/notifications/types.ts +4 -1
- package/corpus/core/src/server/agent-chat-plugin.ts +7 -3
- package/corpus/core/src/server/request-context.ts +7 -0
- package/corpus/core/src/styles/agent-conversation.css +1 -1
- package/corpus/core/src/templates/default/.agents/skills/self-modifying-code/SKILL.md +20 -2
- package/corpus/core/src/templates/default/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
- package/corpus/core/src/templates/default/AGENTS.md +10 -3
- package/corpus/core/src/templates/default/app/i18n/ar-SA.ts +21 -0
- package/corpus/core/src/templates/default/app/i18n/de-DE.ts +21 -0
- package/corpus/core/src/templates/default/app/i18n/en-US.ts +21 -0
- package/corpus/core/src/templates/default/app/i18n/es-ES.ts +21 -0
- package/corpus/core/src/templates/default/app/i18n/fr-FR.ts +21 -0
- package/corpus/core/src/templates/default/app/i18n/hi-IN.ts +20 -0
- package/corpus/core/src/templates/default/app/i18n/ja-JP.ts +21 -0
- package/corpus/core/src/templates/default/app/i18n/ko-KR.ts +20 -0
- package/corpus/core/src/templates/default/app/i18n/pt-BR.ts +21 -0
- package/corpus/core/src/templates/default/app/i18n/zh-CN.ts +20 -0
- package/corpus/core/src/templates/default/app/i18n/zh-TW.ts +19 -0
- package/corpus/core/src/templates/default/package.json +4 -3
- package/corpus/core/src/templates/headless/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
- package/corpus/core/src/templates/headless/AGENTS.md +9 -3
- package/corpus/core/src/templates/headless/package.json +4 -3
- package/corpus/core/src/templates/workspace-core/.agents/skills/self-modifying-code/SKILL.md +20 -2
- package/corpus/core/src/templates/workspace-core/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
- package/corpus/core/src/templates/workspace-core/package.json +6 -6
- package/corpus/core/src/templates/workspace-root/AGENTS.md +10 -4
- package/corpus/core/src/templates/workspace-root/package.json +3 -2
- package/corpus/core/src/triggers/dispatcher.ts +30 -2
- package/corpus/core/src/vite/client.ts +96 -1
- package/corpus/templates/analytics/.agents/skills/self-modifying-code/SKILL.md +20 -2
- package/corpus/templates/analytics/.agents/skills/session-replay/SKILL.md +20 -2
- package/corpus/templates/analytics/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
- package/corpus/templates/analytics/AGENTS.md +7 -5
- package/corpus/templates/analytics/actions/save-monitor.ts +14 -0
- package/corpus/templates/analytics/app/components/dashboard/DataTable.tsx +41 -6
- package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +122 -11
- package/corpus/templates/analytics/app/global.css +26 -10
- package/corpus/templates/analytics/app/i18n/zh-TW.ts +2 -0
- package/corpus/templates/analytics/app/i18n-data.ts +25 -0
- package/corpus/templates/analytics/app/pages/monitoring/MonitoringPage.tsx +8 -2
- package/corpus/templates/analytics/app/pages/monitoring/uptime/MonitorFormPage.tsx +151 -32
- package/corpus/templates/analytics/app/pages/monitoring/uptime/i18n.ts +17 -2
- package/corpus/templates/analytics/app/pages/monitoring/uptime/types.ts +4 -0
- package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +461 -286
- package/corpus/templates/analytics/app/pages/sessions/SessionDevToolsPanel.tsx +285 -294
- package/corpus/templates/analytics/changelog/2026-07-08-console-details-expand-inline-under-each-row-and-the-event-t.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-dashboard-tables-keep-their-size-while-loading.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-monitoring-uptime-and-errors-tabs-now-clearly-show-which-view-is-active.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-session-replay-keeps-a-usable-stage-when-dev-tools-is-open-a.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-session-replay-resumes-after-scrubbing-and-expands-console-r.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-session-replay-uses-stock-rrweb-sizing-again-so-recorded.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-session-replays-wait-for-full-load-keep-a-normal-viewport-an.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-sidebar-dashboard-menus-now-open-above-the-dashboard-canvas.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-uptime-alerting-clarifies-in-app-inbox-vs-email-and-lets-you-paste-slack-or-webhook-urls-per-monitor.md +6 -0
- package/corpus/templates/analytics/docs/uptime-monitoring.md +13 -11
- package/corpus/templates/analytics/package.json +2 -2
- package/corpus/templates/analytics/server/db/schema-monitoring.ts +4 -0
- package/corpus/templates/analytics/server/lib/uptime-monitors.ts +60 -12
- package/corpus/templates/analytics/server/plugins/db.ts +10 -0
- package/corpus/templates/assets/.agents/skills/self-modifying-code/SKILL.md +20 -2
- package/corpus/templates/assets/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
- package/corpus/templates/assets/package.json +2 -2
- package/corpus/templates/brain/.agents/skills/self-modifying-code/SKILL.md +20 -2
- package/corpus/templates/brain/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
- package/corpus/templates/brain/package.json +2 -2
- package/corpus/templates/calendar/.agents/skills/self-modifying-code/SKILL.md +20 -2
- package/corpus/templates/calendar/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
- package/corpus/templates/calendar/AGENTS.md +10 -0
- package/corpus/templates/calendar/actions/create-event.ts +5 -1
- package/corpus/templates/calendar/actions/event-action-helpers.ts +41 -0
- package/corpus/templates/calendar/actions/get-attendee-timezones.ts +28 -0
- package/corpus/templates/calendar/actions/set-attendee-timezone.ts +68 -0
- package/corpus/templates/calendar/app/components/calendar/EventAttendeesSection.tsx +150 -11
- package/corpus/templates/calendar/app/components/calendar/EventDetailPanel.tsx +36 -1
- package/corpus/templates/calendar/app/components/calendar/EventDetailPopover.tsx +32 -0
- package/corpus/templates/calendar/app/hooks/use-attendee-timezones.ts +24 -0
- package/corpus/templates/calendar/app/i18n/zh-TW.ts +2 -0
- package/corpus/templates/calendar/app/i18n-data.ts +20 -0
- package/corpus/templates/calendar/app/lib/attendee-local-time.ts +122 -0
- package/corpus/templates/calendar/changelog/2026-07-08-event-details-now-support-extension-widgets-and-you-can-see-.md +6 -0
- package/corpus/templates/calendar/changelog/2026-07-08-when-you-invite-guests-to-a-new-event-you-now-appear-in.md +6 -0
- package/corpus/templates/calendar/package.json +2 -2
- package/corpus/templates/calendar/server/handlers/events.ts +5 -1
- package/corpus/templates/calendar/shared/api.ts +6 -0
- package/corpus/templates/chat/.agents/skills/self-modifying-code/SKILL.md +20 -2
- package/corpus/templates/chat/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
- package/corpus/templates/chat/package.json +2 -2
- package/corpus/templates/clips/.agents/skills/meetings/SKILL.md +6 -2
- package/corpus/templates/clips/.agents/skills/self-modifying-code/SKILL.md +20 -2
- package/corpus/templates/clips/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
- package/corpus/templates/clips/actions/create-meeting.ts +8 -3
- package/corpus/templates/clips/actions/list-meetings.ts +31 -3
- package/corpus/templates/clips/changelog/2026-07-08-after-finishing-a-desktop-recording-reopening-clips-restor.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-08-clips-now-pops-up-to-take-notes-when-you-join-an-adhoc-zoom-.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-08-desktop-clip-recordings-are-louder-after-capture-mic-only.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-08-desktop-meeting-notes-stay-active-from-tray-and-shortcut-controls.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-08-desktop-meeting-popovers-can-start-notes-and-join-the-meetin.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-08-meeting-notes-keep-their-recording-state-when-the-desktop.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-08-meeting-reminder-dropdowns-now-expand-fully-instead-of-being.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-08-meeting-reminders-now-appear-1-minute-before-start-stay-unti.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-08-the-desktop-meetings-panel-has-room-for-its-drop-shadow-and-.md +6 -0
- package/corpus/templates/clips/chrome-extension/package.json +2 -2
- package/corpus/templates/clips/desktop/package.json +2 -2
- package/corpus/templates/clips/desktop/src/app.tsx +214 -37
- package/corpus/templates/clips/desktop/src/hooks/useMeetingTranscription.ts +30 -6
- package/corpus/templates/clips/desktop/src/lib/meeting-notification-timing.ts +83 -0
- package/corpus/templates/clips/desktop/src/lib/native-recording-warm.ts +21 -0
- package/corpus/templates/clips/desktop/src/lib/recorder.ts +98 -20
- package/corpus/templates/clips/desktop/src/overlays/meeting-notification.tsx +197 -50
- package/corpus/templates/clips/desktop/src/styles.css +150 -53
- package/corpus/templates/clips/desktop/src-tauri/src/adhoc_meetings_watcher.rs +362 -0
- package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +41 -7
- package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +9 -2
- package/corpus/templates/clips/desktop/src-tauri/src/meetings_watcher.rs +89 -11
- package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +71 -17
- package/corpus/templates/clips/desktop/src-tauri/src/native_speech.rs +36 -1
- package/corpus/templates/clips/desktop/src-tauri/src/notifications.rs +62 -10
- package/corpus/templates/clips/desktop/src-tauri/src/shortcuts.rs +3 -3
- package/corpus/templates/clips/desktop/src-tauri/src/silence_detector.rs +1 -25
- package/corpus/templates/clips/desktop/src-tauri/src/state.rs +5 -0
- package/corpus/templates/clips/desktop/src-tauri/src/tray.rs +18 -6
- package/corpus/templates/clips/desktop/src-tauri/src/util.rs +36 -1
- package/corpus/templates/clips/package.json +2 -2
- package/corpus/templates/content/.agents/skills/self-modifying-code/SKILL.md +20 -2
- package/corpus/templates/content/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
- package/corpus/templates/content/actions/_batch-utils.ts +8 -0
- package/corpus/templates/content/actions/_builder-cms-read-client.ts +7 -5
- package/corpus/templates/content/actions/_content-database-personal-view.ts +80 -0
- package/corpus/templates/content/actions/_database-source-utils.ts +776 -319
- package/corpus/templates/content/actions/_database-utils.ts +6 -1
- package/corpus/templates/content/actions/_property-utils.ts +168 -0
- package/corpus/templates/content/actions/add-content-database-source-field-property.ts +19 -12
- package/corpus/templates/content/actions/bind-content-database-source-field.ts +19 -12
- package/corpus/templates/content/actions/delete-document.ts +9 -13
- package/corpus/templates/content/actions/get-content-database-personal-view.ts +27 -0
- package/corpus/templates/content/actions/refresh-content-database-source.ts +5 -5
- package/corpus/templates/content/actions/update-content-database-personal-view.ts +31 -0
- package/corpus/templates/content/actions/update-content-database-view.ts +3 -0
- package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +1 -1
- package/corpus/templates/content/app/components/editor/body-hydration.ts +35 -11
- package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +2631 -551
- package/corpus/templates/content/app/components/editor/database/filter-sort.ts +220 -18
- package/corpus/templates/content/app/hooks/use-content-database.ts +32 -0
- package/corpus/templates/content/app/hooks/use-documents.ts +8 -2
- package/corpus/templates/content/app/i18n/zh-TW.ts +16 -0
- package/corpus/templates/content/app/i18n-data.ts +154 -0
- package/corpus/templates/content/changelog/2026-07-08-builder-source-sync-now-completes-reliably-on-hosted-databases.md +6 -0
- package/corpus/templates/content/changelog/2026-07-08-database-filters-now-support-notion-style-reset-save-for-eve.md +6 -0
- package/corpus/templates/content/changelog/2026-07-08-date-filters-can-now-target-a-between-range.md +6 -0
- package/corpus/templates/content/changelog/2026-07-08-fixed-builder-database-sync-so-large-sources-continue-past-t.md +6 -0
- package/corpus/templates/content/package.json +2 -2
- package/corpus/templates/content/parity/matrix.md +1 -1
- package/corpus/templates/content/parity/matrix.ts +2 -0
- package/corpus/templates/content/server/plugins/db.ts +19 -0
- package/corpus/templates/content/shared/api.ts +24 -0
- package/corpus/templates/design/.agents/skills/self-modifying-code/SKILL.md +20 -2
- package/corpus/templates/design/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
- package/corpus/templates/design/package.json +2 -2
- package/corpus/templates/dispatch/.agents/skills/self-modifying-code/SKILL.md +20 -2
- package/corpus/templates/dispatch/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
- package/corpus/templates/dispatch/app/i18n/zh-TW.ts +34 -1
- package/corpus/templates/dispatch/app/i18n-data.ts +387 -10
- package/corpus/templates/dispatch/app/routes/automations.tsx +1 -0
- package/corpus/templates/dispatch/changelog/2026-07-08-added-an-automations-page-to-review-pause-and-create.md +6 -0
- package/corpus/templates/dispatch/changelog/2026-07-08-destinations-now-shows-outbound-delivery-queue-health.md +6 -0
- package/corpus/templates/dispatch/package.json +2 -2
- package/corpus/templates/forms/.agents/skills/self-modifying-code/SKILL.md +20 -2
- package/corpus/templates/forms/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
- package/corpus/templates/forms/package.json +2 -2
- package/corpus/templates/macros/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
- package/corpus/templates/macros/package.json +2 -2
- package/corpus/templates/mail/.agents/skills/self-modifying-code/SKILL.md +20 -2
- package/corpus/templates/mail/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
- package/corpus/templates/mail/app/hooks/use-emails.ts +56 -44
- package/corpus/templates/mail/app/lib/gmail-mutation-queue.ts +325 -0
- package/corpus/templates/mail/changelog/2026-07-08-rapid-archive-and-mark-read-now-batch-gmail-updates-so-the-i.md +6 -0
- package/corpus/templates/mail/package.json +2 -2
- package/corpus/templates/plan/.agents/skills/self-modifying-code/SKILL.md +20 -2
- package/corpus/templates/plan/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
- package/corpus/templates/plan/package.json +2 -2
- package/corpus/templates/slides/.agents/skills/self-modifying-code/SKILL.md +20 -2
- package/corpus/templates/slides/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
- package/corpus/templates/slides/app/components/editor/ImageDropPromptPopover.tsx +46 -29
- package/corpus/templates/slides/app/context/DeckContext.tsx +45 -18
- package/corpus/templates/slides/app/i18n/ar-SA.ts +4 -0
- package/corpus/templates/slides/app/i18n/de-DE.ts +4 -0
- package/corpus/templates/slides/app/i18n/en-US.ts +4 -0
- package/corpus/templates/slides/app/i18n/es-ES.ts +4 -0
- package/corpus/templates/slides/app/i18n/fr-FR.ts +4 -0
- package/corpus/templates/slides/app/i18n/hi-IN.ts +4 -0
- package/corpus/templates/slides/app/i18n/ja-JP.ts +4 -0
- package/corpus/templates/slides/app/i18n/ko-KR.ts +4 -0
- package/corpus/templates/slides/app/i18n/pt-BR.ts +4 -0
- package/corpus/templates/slides/app/i18n/zh-CN.ts +4 -0
- package/corpus/templates/slides/app/i18n/zh-TW.ts +4 -0
- package/corpus/templates/slides/app/lib/image-drop-to-agent.ts +115 -0
- package/corpus/templates/slides/app/pages/DeckEditor.tsx +22 -13
- package/corpus/templates/slides/changelog/2026-07-08-dropping-an-image-onto-a-slide-and-sending-it-to-the-agent-w.md +6 -0
- package/corpus/templates/slides/changelog/2026-07-08-undo-works-after-the-agent-edits-a-slide-so-you-can-reverse.md +6 -0
- package/corpus/templates/slides/package.json +2 -2
- package/corpus/templates/videos/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
- package/corpus/templates/voice/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
- package/dist/agent/production-agent.d.ts +5 -1
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +112 -42
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/run-manager.d.ts.map +1 -1
- package/dist/agent/run-manager.js +23 -2
- package/dist/agent/run-manager.js.map +1 -1
- package/dist/agent/run-store.js +2 -2
- package/dist/agent/run-store.js.map +1 -1
- package/dist/agent/tool-search.d.ts +2 -0
- package/dist/agent/tool-search.d.ts.map +1 -1
- package/dist/agent/tool-search.js +60 -4
- package/dist/agent/tool-search.js.map +1 -1
- package/dist/catalog.json +2 -2
- package/dist/cli/add.js +1 -1
- package/dist/cli/add.js.map +1 -1
- package/dist/cli/create.d.ts.map +1 -1
- package/dist/cli/create.js +8 -3
- package/dist/cli/create.js.map +1 -1
- package/dist/cli/index.js +24 -4
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/upgrade.d.ts +100 -0
- package/dist/cli/upgrade.d.ts.map +1 -0
- package/dist/cli/upgrade.js +678 -0
- package/dist/cli/upgrade.js.map +1 -0
- package/dist/client/AssistantChat.js +1 -1
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/HighlightedCodeBlock.d.ts +2 -0
- package/dist/client/HighlightedCodeBlock.d.ts.map +1 -1
- package/dist/client/HighlightedCodeBlock.js +10 -1
- package/dist/client/HighlightedCodeBlock.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +32 -4
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/client/chat/message-components.d.ts.map +1 -1
- package/dist/client/chat/message-components.js +61 -8
- package/dist/client/chat/message-components.js.map +1 -1
- package/dist/client/chat/tool-call-display.d.ts +12 -0
- package/dist/client/chat/tool-call-display.d.ts.map +1 -1
- package/dist/client/chat/tool-call-display.js +136 -42
- package/dist/client/chat/tool-call-display.js.map +1 -1
- package/dist/client/code-agent-chat-adapter.js +2 -9
- package/dist/client/code-agent-chat-adapter.js.map +1 -1
- package/dist/client/extensions/ExtensionSlot.js +6 -0
- package/dist/client/extensions/ExtensionSlot.js.map +1 -1
- package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
- package/dist/client/settings/SettingsPanel.js +52 -19
- package/dist/client/settings/SettingsPanel.js.map +1 -1
- package/dist/client/settings/SettingsSection.d.ts +19 -4
- package/dist/client/settings/SettingsSection.d.ts.map +1 -1
- package/dist/client/settings/SettingsSection.js +33 -4
- package/dist/client/settings/SettingsSection.js.map +1 -1
- package/dist/client/sse-event-processor.d.ts +9 -0
- package/dist/client/sse-event-processor.d.ts.map +1 -1
- package/dist/client/sse-event-processor.js +20 -2
- package/dist/client/sse-event-processor.js.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/extensions/actions.d.ts.map +1 -1
- package/dist/extensions/actions.js +85 -5
- package/dist/extensions/actions.js.map +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/jobs/scheduler.js +26 -1
- package/dist/jobs/scheduler.js.map +1 -1
- package/dist/localization/default-messages.d.ts +19 -0
- package/dist/localization/default-messages.d.ts.map +1 -1
- package/dist/localization/default-messages.js +19 -0
- package/dist/localization/default-messages.js.map +1 -1
- package/dist/notifications/channels.d.ts +8 -3
- package/dist/notifications/channels.d.ts.map +1 -1
- package/dist/notifications/channels.js +61 -22
- package/dist/notifications/channels.js.map +1 -1
- package/dist/notifications/registry.d.ts.map +1 -1
- package/dist/notifications/registry.js +14 -3
- package/dist/notifications/registry.js.map +1 -1
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/notifications/types.d.ts +4 -1
- package/dist/notifications/types.d.ts.map +1 -1
- package/dist/notifications/types.js.map +1 -1
- package/dist/observability/routes.d.ts +1 -1
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/resources/handlers.d.ts +3 -3
- package/dist/server/agent-chat-plugin.d.ts +5 -1
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +2 -2
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/request-context.d.ts +7 -0
- package/dist/server/request-context.d.ts.map +1 -1
- package/dist/server/request-context.js.map +1 -1
- package/dist/styles/agent-conversation.css +1 -1
- package/dist/templates/default/.agents/skills/self-modifying-code/SKILL.md +20 -2
- package/dist/templates/default/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
- package/dist/templates/default/AGENTS.md +10 -3
- package/dist/templates/default/app/i18n/ar-SA.ts +21 -0
- package/dist/templates/default/app/i18n/de-DE.ts +21 -0
- package/dist/templates/default/app/i18n/en-US.ts +21 -0
- package/dist/templates/default/app/i18n/es-ES.ts +21 -0
- package/dist/templates/default/app/i18n/fr-FR.ts +21 -0
- package/dist/templates/default/app/i18n/hi-IN.ts +20 -0
- package/dist/templates/default/app/i18n/ja-JP.ts +21 -0
- package/dist/templates/default/app/i18n/ko-KR.ts +20 -0
- package/dist/templates/default/app/i18n/pt-BR.ts +21 -0
- package/dist/templates/default/app/i18n/zh-CN.ts +20 -0
- package/dist/templates/default/app/i18n/zh-TW.ts +19 -0
- package/dist/templates/default/package.json +4 -3
- package/dist/templates/headless/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
- package/dist/templates/headless/AGENTS.md +9 -3
- package/dist/templates/headless/package.json +4 -3
- package/dist/templates/workspace-core/.agents/skills/self-modifying-code/SKILL.md +20 -2
- package/dist/templates/workspace-core/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
- package/dist/templates/workspace-core/package.json +6 -6
- package/dist/templates/workspace-root/AGENTS.md +10 -4
- package/dist/templates/workspace-root/package.json +3 -2
- package/dist/triggers/dispatcher.js +27 -2
- package/dist/triggers/dispatcher.js.map +1 -1
- package/dist/vite/client.d.ts.map +1 -1
- package/dist/vite/client.js +70 -1
- package/dist/vite/client.js.map +1 -1
- package/docs/content/faq.mdx +17 -0
- package/docs/content/notifications.mdx +12 -6
- package/package.json +7 -6
- package/src/templates/default/.agents/skills/self-modifying-code/SKILL.md +20 -2
- package/src/templates/default/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
- package/src/templates/default/AGENTS.md +10 -3
- package/src/templates/default/app/i18n/ar-SA.ts +21 -0
- package/src/templates/default/app/i18n/de-DE.ts +21 -0
- package/src/templates/default/app/i18n/en-US.ts +21 -0
- package/src/templates/default/app/i18n/es-ES.ts +21 -0
- package/src/templates/default/app/i18n/fr-FR.ts +21 -0
- package/src/templates/default/app/i18n/hi-IN.ts +20 -0
- package/src/templates/default/app/i18n/ja-JP.ts +21 -0
- package/src/templates/default/app/i18n/ko-KR.ts +20 -0
- package/src/templates/default/app/i18n/pt-BR.ts +21 -0
- package/src/templates/default/app/i18n/zh-CN.ts +20 -0
- package/src/templates/default/app/i18n/zh-TW.ts +19 -0
- package/src/templates/default/package.json +4 -3
- package/src/templates/headless/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
- package/src/templates/headless/AGENTS.md +9 -3
- package/src/templates/headless/package.json +4 -3
- package/src/templates/workspace-core/.agents/skills/self-modifying-code/SKILL.md +20 -2
- package/src/templates/workspace-core/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
- package/src/templates/workspace-core/package.json +6 -6
- package/src/templates/workspace-root/AGENTS.md +10 -4
- package/src/templates/workspace-root/package.json +3 -2
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Meeting reminder visibility policy (Granola-aligned).
|
|
3
|
+
*
|
|
4
|
+
* Show the overlay from 1 minute before start through 5 minutes after start,
|
|
5
|
+
* unless the user dismisses it or takes an action.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export const MEETING_NOTIFY_LEAD_MS = 60_000;
|
|
9
|
+
export const MEETING_NOTIFY_HOLD_AFTER_START_MS = 5 * 60_000;
|
|
10
|
+
|
|
11
|
+
/** True when `now` is inside the show window for a meeting that starts at `startMs`. */
|
|
12
|
+
export function isMeetingNotificationWindowOpen(
|
|
13
|
+
startMs: number,
|
|
14
|
+
nowMs: number = Date.now(),
|
|
15
|
+
): boolean {
|
|
16
|
+
if (!Number.isFinite(startMs)) return false;
|
|
17
|
+
const earliest = startMs - MEETING_NOTIFY_LEAD_MS;
|
|
18
|
+
const latest = startMs + MEETING_NOTIFY_HOLD_AFTER_START_MS;
|
|
19
|
+
return nowMs >= earliest && nowMs <= latest;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Milliseconds until the overlay should auto-hide, assuming it is currently
|
|
24
|
+
* visible. Returns 0 when the window has already closed.
|
|
25
|
+
*/
|
|
26
|
+
export function meetingNotificationAutoHideMs(
|
|
27
|
+
startMs: number,
|
|
28
|
+
nowMs: number = Date.now(),
|
|
29
|
+
): number {
|
|
30
|
+
if (!Number.isFinite(startMs)) return 0;
|
|
31
|
+
const latest = startMs + MEETING_NOTIFY_HOLD_AFTER_START_MS;
|
|
32
|
+
return Math.max(0, latest - nowMs);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export type MeetingJoinProvider = "zoom" | "meet" | "teams" | "webex" | "other";
|
|
36
|
+
|
|
37
|
+
export function detectMeetingJoinProvider(
|
|
38
|
+
joinUrl: string | null | undefined,
|
|
39
|
+
platform?: string | null,
|
|
40
|
+
): MeetingJoinProvider {
|
|
41
|
+
const haystack = `${platform ?? ""} ${joinUrl ?? ""}`.toLowerCase();
|
|
42
|
+
if (haystack.includes("zoom")) return "zoom";
|
|
43
|
+
if (haystack.includes("meet.google") || /\bmeet\b/.test(haystack))
|
|
44
|
+
return "meet";
|
|
45
|
+
if (haystack.includes("teams.microsoft") || haystack.includes("teams"))
|
|
46
|
+
return "teams";
|
|
47
|
+
if (haystack.includes("webex")) return "webex";
|
|
48
|
+
return "other";
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function joinProviderLabel(provider: MeetingJoinProvider): string {
|
|
52
|
+
switch (provider) {
|
|
53
|
+
case "zoom":
|
|
54
|
+
return "Zoom";
|
|
55
|
+
case "meet":
|
|
56
|
+
return "Meet";
|
|
57
|
+
case "teams":
|
|
58
|
+
return "Teams";
|
|
59
|
+
case "webex":
|
|
60
|
+
return "Webex";
|
|
61
|
+
default:
|
|
62
|
+
return "meeting";
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Format a local time range like "9:00 AM - 9:30 AM". */
|
|
67
|
+
export function formatMeetingTimeRange(
|
|
68
|
+
startIso: string | null | undefined,
|
|
69
|
+
endIso: string | null | undefined,
|
|
70
|
+
locale?: string,
|
|
71
|
+
): string | null {
|
|
72
|
+
if (!startIso) return null;
|
|
73
|
+
const start = Date.parse(startIso);
|
|
74
|
+
if (!Number.isFinite(start)) return null;
|
|
75
|
+
const end = endIso ? Date.parse(endIso) : NaN;
|
|
76
|
+
const fmt = new Intl.DateTimeFormat(locale, {
|
|
77
|
+
hour: "numeric",
|
|
78
|
+
minute: "2-digit",
|
|
79
|
+
});
|
|
80
|
+
const startLabel = fmt.format(new Date(start));
|
|
81
|
+
if (!Number.isFinite(end)) return startLabel;
|
|
82
|
+
return `${startLabel} - ${fmt.format(new Date(end))}`;
|
|
83
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hosted native start sequencing: overlap Whisper start, create-recording, and
|
|
3
|
+
* deferred SCK warm so Skip no longer waits serially on Whisper then warm.
|
|
4
|
+
* Begin/attach must still wait for this promise (transcription settled).
|
|
5
|
+
*/
|
|
6
|
+
export function planNativeFullscreenWarmOverlap<
|
|
7
|
+
TRecording extends { id: string },
|
|
8
|
+
>(input: {
|
|
9
|
+
createRecording: () => Promise<TRecording>;
|
|
10
|
+
startTranscription: () => Promise<unknown>;
|
|
11
|
+
warmMic: (recordingId: string) => Promise<unknown>;
|
|
12
|
+
}): Promise<TRecording> {
|
|
13
|
+
const transcriptionPromise = input.startTranscription();
|
|
14
|
+
return (async () => {
|
|
15
|
+
const created = await input.createRecording();
|
|
16
|
+
// Deferred-output warm may overlap remaining Whisper startup; frames are
|
|
17
|
+
// not written until begin attaches the recording output.
|
|
18
|
+
await Promise.all([transcriptionPromise, input.warmMic(created.id)]);
|
|
19
|
+
return created;
|
|
20
|
+
})();
|
|
21
|
+
}
|
|
@@ -69,6 +69,7 @@ import {
|
|
|
69
69
|
getAudioStreamWithFallback,
|
|
70
70
|
getCameraStreamWithFallback,
|
|
71
71
|
} from "./media-capture-constraints";
|
|
72
|
+
import { planNativeFullscreenWarmOverlap } from "./native-recording-warm";
|
|
72
73
|
import { buildCaptureTitle, type CaptureTitleResult } from "./recording-title";
|
|
73
74
|
import {
|
|
74
75
|
startTranscriptionCapture,
|
|
@@ -77,6 +78,7 @@ import {
|
|
|
77
78
|
} from "./transcription-capture";
|
|
78
79
|
|
|
79
80
|
export type { LocalExportedFile } from "./local-export";
|
|
81
|
+
export { planNativeFullscreenWarmOverlap } from "./native-recording-warm";
|
|
80
82
|
|
|
81
83
|
export type CaptureMode = "screen" | "screen-camera" | "camera";
|
|
82
84
|
export type CaptureSource = "full-screen" | "window" | "region";
|
|
@@ -1677,6 +1679,11 @@ async function openNativeUploadUrl(
|
|
|
1677
1679
|
}
|
|
1678
1680
|
}
|
|
1679
1681
|
|
|
1682
|
+
/**
|
|
1683
|
+
* Hosted native start sequencing helper: overlap Whisper start, create-recording,
|
|
1684
|
+
* and deferred SCK warm so Skip no longer waits serially on Whisper then warm.
|
|
1685
|
+
* `begin` / attach still waits for transcription to settle first.
|
|
1686
|
+
*/
|
|
1680
1687
|
function abortCreatedRecordingOnCountdownCancel(
|
|
1681
1688
|
err: unknown,
|
|
1682
1689
|
recordingPromise: Promise<{ id: string }>,
|
|
@@ -1847,19 +1854,42 @@ async function startNativeFullscreenRecording(
|
|
|
1847
1854
|
}).catch((err) => {
|
|
1848
1855
|
console.warn("[clips-recorder] mic warm failed:", err);
|
|
1849
1856
|
});
|
|
1857
|
+
const clickStartedAt = Date.now();
|
|
1850
1858
|
if (localOnly) {
|
|
1859
|
+
// Local recordings have no create-recording round-trip; still overlap
|
|
1860
|
+
// Whisper startup with countdown + deferred SCK warm.
|
|
1851
1861
|
const countdownPromise = runRecordingCountdown(true);
|
|
1852
1862
|
id = localFolderName;
|
|
1853
|
-
|
|
1863
|
+
const transcriptionPromise = startNativeTranscriptionBeforeRecording();
|
|
1864
|
+
const warmPromise = (async () => {
|
|
1865
|
+
const warmStartedAt = Date.now();
|
|
1866
|
+
await warmMic(id);
|
|
1867
|
+
console.log(
|
|
1868
|
+
`[clips-recorder] native warm durations: warmMs=${Date.now() - warmStartedAt}`,
|
|
1869
|
+
);
|
|
1870
|
+
})();
|
|
1871
|
+
try {
|
|
1872
|
+
await Promise.all([
|
|
1873
|
+
countdownPromise,
|
|
1874
|
+
transcriptionPromise,
|
|
1875
|
+
warmPromise,
|
|
1876
|
+
]);
|
|
1877
|
+
} catch (err) {
|
|
1878
|
+
await transcriptionPromise.catch(() => {});
|
|
1879
|
+
throw err;
|
|
1880
|
+
}
|
|
1854
1881
|
} else {
|
|
1855
1882
|
const captureTitlePromise = captureTitleForRecording({
|
|
1856
1883
|
mode: params.mode,
|
|
1857
1884
|
source: params.source,
|
|
1858
1885
|
});
|
|
1859
1886
|
const countdownPromise = runRecordingCountdown(true);
|
|
1887
|
+
// Kick Whisper off immediately (no recording id needed) so Skip no longer
|
|
1888
|
+
// serializes create → Whisper → SCK warm on the critical path.
|
|
1889
|
+
const transcriptionPromise = startNativeTranscriptionBeforeRecording();
|
|
1860
1890
|
const recordingPromise = (async () => {
|
|
1861
1891
|
const captureTitle = await captureTitlePromise;
|
|
1862
|
-
|
|
1892
|
+
const createStartedAt = Date.now();
|
|
1863
1893
|
try {
|
|
1864
1894
|
return await createServerRecording(
|
|
1865
1895
|
params.serverUrl,
|
|
@@ -1873,26 +1903,47 @@ async function startNativeFullscreenRecording(
|
|
|
1873
1903
|
},
|
|
1874
1904
|
);
|
|
1875
1905
|
} finally {
|
|
1876
|
-
console.
|
|
1906
|
+
console.log(
|
|
1907
|
+
`[clips-recorder] createServerRecording durationMs=${Date.now() - createStartedAt}`,
|
|
1908
|
+
);
|
|
1877
1909
|
}
|
|
1878
1910
|
})();
|
|
1879
|
-
//
|
|
1880
|
-
//
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1911
|
+
// Once create returns an id, warm SCK with deferred_output in parallel
|
|
1912
|
+
// with any remaining Whisper startup. Begin/attach still waits on
|
|
1913
|
+
// transcription settling first (AVAudioEngine after SCK writing can mute
|
|
1914
|
+
// the SCK mic leg).
|
|
1915
|
+
const warmAndId = planNativeFullscreenWarmOverlap({
|
|
1916
|
+
createRecording: async () => {
|
|
1917
|
+
const createRes = await recordingPromise;
|
|
1918
|
+
uploadMode = createRes.uploadMode;
|
|
1919
|
+
id = createRes.id;
|
|
1920
|
+
return createRes;
|
|
1921
|
+
},
|
|
1922
|
+
startTranscription: async () => {
|
|
1923
|
+
const transcriptionStartedAt = Date.now();
|
|
1924
|
+
try {
|
|
1925
|
+
await transcriptionPromise;
|
|
1926
|
+
} finally {
|
|
1927
|
+
console.log(
|
|
1928
|
+
`[clips-recorder] transcription warm durationMs=${Date.now() - transcriptionStartedAt}`,
|
|
1929
|
+
);
|
|
1930
|
+
}
|
|
1931
|
+
},
|
|
1932
|
+
warmMic: async (recordingId) => {
|
|
1933
|
+
const warmStartedAt = Date.now();
|
|
1934
|
+
try {
|
|
1935
|
+
await warmMic(recordingId);
|
|
1936
|
+
} finally {
|
|
1937
|
+
console.log(
|
|
1938
|
+
`[clips-recorder] native warm durationMs=${Date.now() - warmStartedAt}`,
|
|
1939
|
+
);
|
|
1940
|
+
}
|
|
1941
|
+
},
|
|
1942
|
+
});
|
|
1893
1943
|
try {
|
|
1894
|
-
const [,
|
|
1895
|
-
id =
|
|
1944
|
+
const [, createRes] = await Promise.all([countdownPromise, warmAndId]);
|
|
1945
|
+
id = createRes.id;
|
|
1946
|
+
uploadMode = createRes.uploadMode ?? uploadMode;
|
|
1896
1947
|
} catch (err) {
|
|
1897
1948
|
abortCreatedRecordingOnCountdownCancel(
|
|
1898
1949
|
err,
|
|
@@ -1905,11 +1956,16 @@ async function startNativeFullscreenRecording(
|
|
|
1905
1956
|
|
|
1906
1957
|
await audioCue.playBeforeCapture();
|
|
1907
1958
|
// Phase 2: attach the recording output now that the mic is warm (or do a
|
|
1908
|
-
// normal immediate start if warming was skipped/failed).
|
|
1959
|
+
// normal immediate start if warming was skipped/failed). Transcription has
|
|
1960
|
+
// already been awaited above so AVAudioEngine won't reconfigure mid-write.
|
|
1961
|
+
const beginStartedAt = Date.now();
|
|
1909
1962
|
await invoke("native_fullscreen_recording_begin", {
|
|
1910
1963
|
recordingId: id,
|
|
1911
1964
|
...captureAudioParams,
|
|
1912
1965
|
});
|
|
1966
|
+
console.log(
|
|
1967
|
+
`[clips-recorder] native begin durationMs=${Date.now() - beginStartedAt} clickToLiveMs=${Date.now() - clickStartedAt}`,
|
|
1968
|
+
);
|
|
1913
1969
|
await transcriptionCapture?.resetTimeline().catch((err) => {
|
|
1914
1970
|
console.warn(
|
|
1915
1971
|
"[clips-recorder] transcription timeline reset failed:",
|
|
@@ -2021,7 +2077,26 @@ async function startNativeFullscreenRecording(
|
|
|
2021
2077
|
stopPromise = (async () => {
|
|
2022
2078
|
stopped = true;
|
|
2023
2079
|
console.log("[clips-recorder] native full-screen stop requested");
|
|
2080
|
+
// Tear chrome down immediately with finalizing so the live camera bubble /
|
|
2081
|
+
// toolbar don't linger while ScreencaptureKit finalize + upload run.
|
|
2082
|
+
// hide_recording_chrome leaves the bubble; close_bubble destroys it.
|
|
2083
|
+
// Order matters: show finalizing first, and never call hide_overlays here
|
|
2084
|
+
// because that also closes the finalizing window.
|
|
2024
2085
|
if (!localOnly) showFinalizingFeedback();
|
|
2086
|
+
await invoke("hide_recording_chrome").catch((err) =>
|
|
2087
|
+
console.error(
|
|
2088
|
+
"[clips-recorder] immediate hide_recording_chrome after stop failed:",
|
|
2089
|
+
err,
|
|
2090
|
+
),
|
|
2091
|
+
);
|
|
2092
|
+
if (wantsCamera) {
|
|
2093
|
+
await invoke("close_bubble").catch((err) =>
|
|
2094
|
+
console.error(
|
|
2095
|
+
"[clips-recorder] immediate close_bubble after stop failed:",
|
|
2096
|
+
err,
|
|
2097
|
+
),
|
|
2098
|
+
);
|
|
2099
|
+
}
|
|
2025
2100
|
clearSegmentRotator();
|
|
2026
2101
|
if (tickHandle) {
|
|
2027
2102
|
clearInterval(tickHandle);
|
|
@@ -3226,6 +3301,9 @@ async function startRecordingInner(
|
|
|
3226
3301
|
label: params.micLabel,
|
|
3227
3302
|
},
|
|
3228
3303
|
wantsSystemAudio,
|
|
3304
|
+
// Match native path: VoiceProcessingIO AEC/ducking on a shared mic
|
|
3305
|
+
// can tank live call volume and attenuate the recorded mic leg.
|
|
3306
|
+
{ voiceProcessing: false },
|
|
3229
3307
|
)
|
|
3230
3308
|
: null;
|
|
3231
3309
|
// Stop/Cancel can fire during the await above — at that point stop()/cancel()
|
|
@@ -1,16 +1,33 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
IconAlertCircle,
|
|
3
|
+
IconChevronDown,
|
|
4
|
+
IconNotes,
|
|
5
|
+
IconVideo,
|
|
6
|
+
IconX,
|
|
7
|
+
} from "@tabler/icons-react";
|
|
2
8
|
import { invoke } from "@tauri-apps/api/core";
|
|
9
|
+
import { LogicalSize } from "@tauri-apps/api/dpi";
|
|
3
10
|
import { emit, listen } from "@tauri-apps/api/event";
|
|
4
11
|
import { getCurrentWindow } from "@tauri-apps/api/window";
|
|
5
12
|
import { open as openExternal } from "@tauri-apps/plugin-shell";
|
|
6
13
|
import { useEffect, useRef, useState } from "react";
|
|
7
14
|
|
|
15
|
+
import {
|
|
16
|
+
detectMeetingJoinProvider,
|
|
17
|
+
joinProviderLabel,
|
|
18
|
+
meetingNotificationAutoHideMs,
|
|
19
|
+
type MeetingJoinProvider,
|
|
20
|
+
} from "../lib/meeting-notification-timing";
|
|
21
|
+
|
|
8
22
|
interface NotificationData {
|
|
9
23
|
type: "calendar" | "adhoc";
|
|
10
24
|
title: string;
|
|
11
25
|
subtitle: string;
|
|
12
26
|
meetingId: string;
|
|
13
27
|
joinUrl?: string | null;
|
|
28
|
+
platform?: string | null;
|
|
29
|
+
scheduledStart?: string | null;
|
|
30
|
+
scheduledEnd?: string | null;
|
|
14
31
|
autoStart?: boolean;
|
|
15
32
|
}
|
|
16
33
|
|
|
@@ -19,12 +36,14 @@ interface TranscriptionStatusPayload {
|
|
|
19
36
|
error?: string;
|
|
20
37
|
}
|
|
21
38
|
|
|
22
|
-
const DEFAULT_AUTO_HIDE_MS = 30_000;
|
|
23
39
|
const SNOOZE_MS = 5 * 60_000;
|
|
40
|
+
const FALLBACK_AUTO_HIDE_MS = 6 * 60_000;
|
|
41
|
+
const NOTIFICATION_WINDOW_WIDTH = 440;
|
|
42
|
+
const NOTIFICATION_COLLAPSED_HEIGHT = 120;
|
|
43
|
+
const NOTIFICATION_MENU_HEIGHT = 224;
|
|
24
44
|
|
|
25
45
|
/**
|
|
26
|
-
* Open a meeting join URL via the Tauri shell plugin.
|
|
27
|
-
* notification's dedicated Join CTA (notes start is a separate action).
|
|
46
|
+
* Open a meeting join URL via the Tauri shell plugin.
|
|
28
47
|
*/
|
|
29
48
|
async function openJoinUrl(url: string | null | undefined): Promise<void> {
|
|
30
49
|
if (!url) return;
|
|
@@ -35,40 +54,90 @@ async function openJoinUrl(url: string | null | undefined): Promise<void> {
|
|
|
35
54
|
}
|
|
36
55
|
}
|
|
37
56
|
|
|
57
|
+
function resizeNotificationWindow(expanded: boolean) {
|
|
58
|
+
const height = expanded
|
|
59
|
+
? NOTIFICATION_MENU_HEIGHT
|
|
60
|
+
: NOTIFICATION_COLLAPSED_HEIGHT;
|
|
61
|
+
getCurrentWindow()
|
|
62
|
+
.setSize(new LogicalSize(NOTIFICATION_WINDOW_WIDTH, height))
|
|
63
|
+
.catch((err) => {
|
|
64
|
+
console.warn("[clips-meeting-notif] resize failed", err);
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function ProviderGlyph({ provider }: { provider: MeetingJoinProvider }) {
|
|
69
|
+
// Lightweight glyphs — keep the overlay free of extra assets. Zoom blue
|
|
70
|
+
// camera / Meet green / Teams purple, otherwise a generic video icon.
|
|
71
|
+
if (provider === "zoom") {
|
|
72
|
+
return (
|
|
73
|
+
<span
|
|
74
|
+
className="meeting-notification-provider meeting-notification-provider-zoom"
|
|
75
|
+
aria-hidden
|
|
76
|
+
>
|
|
77
|
+
<IconVideo size={14} stroke={2.2} />
|
|
78
|
+
</span>
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
if (provider === "meet") {
|
|
82
|
+
return (
|
|
83
|
+
<span
|
|
84
|
+
className="meeting-notification-provider meeting-notification-provider-meet"
|
|
85
|
+
aria-hidden
|
|
86
|
+
>
|
|
87
|
+
<IconVideo size={14} stroke={2.2} />
|
|
88
|
+
</span>
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
if (provider === "teams") {
|
|
92
|
+
return (
|
|
93
|
+
<span
|
|
94
|
+
className="meeting-notification-provider meeting-notification-provider-teams"
|
|
95
|
+
aria-hidden
|
|
96
|
+
>
|
|
97
|
+
<IconVideo size={14} stroke={2.2} />
|
|
98
|
+
</span>
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
return (
|
|
102
|
+
<span
|
|
103
|
+
className="meeting-notification-provider meeting-notification-provider-other"
|
|
104
|
+
aria-hidden
|
|
105
|
+
>
|
|
106
|
+
<IconNotes size={14} stroke={2.2} />
|
|
107
|
+
</span>
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
|
|
38
111
|
/**
|
|
39
112
|
* Granola-style meeting notification — small card in the top-right corner.
|
|
40
|
-
* Variants:
|
|
41
113
|
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
* - Ad-hoc call: dashed left bar (slate), "Call detected", app name,
|
|
45
|
-
* same controls.
|
|
114
|
+
* Primary split button: join the call and open Clips notes in one click.
|
|
115
|
+
* Chevron exposes secondary actions (join only / notes only / snooze).
|
|
46
116
|
*
|
|
47
|
-
* Data arrives via Tauri event `meetings:show-notification`.
|
|
48
|
-
*
|
|
49
|
-
* persistent popover transcription session surface inline beneath the title
|
|
50
|
-
* so the user isn't left wondering why nothing happened.
|
|
117
|
+
* Data arrives via Tauri event `meetings:show-notification`. Visibility holds
|
|
118
|
+
* from 1 minute before start until 5 minutes after, unless dismissed.
|
|
51
119
|
*/
|
|
52
120
|
export function MeetingNotification() {
|
|
53
121
|
const [data, setData] = useState<NotificationData | null>(null);
|
|
54
122
|
const [showClose, setShowClose] = useState(false);
|
|
123
|
+
const [menuOpen, setMenuOpen] = useState(false);
|
|
55
124
|
const [error, setError] = useState<string | null>(null);
|
|
56
125
|
const [pending, setPending] = useState(false);
|
|
57
126
|
const autoHideTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
58
127
|
const dataRef = useRef<NotificationData | null>(null);
|
|
59
128
|
|
|
60
|
-
// Keep a ref to the latest data so the transcription-status listeners can
|
|
61
|
-
// match incoming events against the meeting currently on screen without
|
|
62
|
-
// re-subscribing on every render.
|
|
63
129
|
useEffect(() => {
|
|
64
130
|
dataRef.current = data;
|
|
65
131
|
}, [data]);
|
|
66
132
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
133
|
+
useEffect(() => {
|
|
134
|
+
resizeNotificationWindow(Boolean(data && menuOpen));
|
|
135
|
+
}, [data, menuOpen]);
|
|
136
|
+
|
|
137
|
+
useEffect(() => {
|
|
138
|
+
return () => resizeNotificationWindow(false);
|
|
139
|
+
}, []);
|
|
140
|
+
|
|
72
141
|
useEffect(() => {
|
|
73
142
|
const win = getCurrentWindow();
|
|
74
143
|
if (data) {
|
|
@@ -84,8 +153,15 @@ export function MeetingNotification() {
|
|
|
84
153
|
) {
|
|
85
154
|
setData(payload);
|
|
86
155
|
setError(null);
|
|
156
|
+
setMenuOpen(false);
|
|
87
157
|
setPending(!!payload.autoStart && !options?.hydrated);
|
|
88
|
-
|
|
158
|
+
const startMs = payload.scheduledStart
|
|
159
|
+
? Date.parse(payload.scheduledStart)
|
|
160
|
+
: NaN;
|
|
161
|
+
const hideMs = Number.isFinite(startMs)
|
|
162
|
+
? meetingNotificationAutoHideMs(startMs)
|
|
163
|
+
: FALLBACK_AUTO_HIDE_MS;
|
|
164
|
+
scheduleAutoHide(hideMs);
|
|
89
165
|
}
|
|
90
166
|
|
|
91
167
|
useEffect(() => {
|
|
@@ -112,6 +188,15 @@ export function MeetingNotification() {
|
|
|
112
188
|
}),
|
|
113
189
|
);
|
|
114
190
|
|
|
191
|
+
// Cold overlay boot: hydrate any payload stored before this webview
|
|
192
|
+
// mounted (calendar or adhoc).
|
|
193
|
+
invoke<NotificationData | null>("take_pending_meeting_notification")
|
|
194
|
+
.then((pending) => {
|
|
195
|
+
if (stopped || !pending) return;
|
|
196
|
+
showNotification(pending, { hydrated: true });
|
|
197
|
+
})
|
|
198
|
+
.catch(() => {});
|
|
199
|
+
|
|
115
200
|
trackListen(
|
|
116
201
|
listen<TranscriptionStatusPayload>("meetings:hide-notification", (ev) => {
|
|
117
202
|
if (ev.payload.meetingId !== dataRef.current?.meetingId) return;
|
|
@@ -154,14 +239,30 @@ export function MeetingNotification() {
|
|
|
154
239
|
|
|
155
240
|
function scheduleAutoHide(ms: number) {
|
|
156
241
|
clearAutoHide();
|
|
242
|
+
if (ms <= 0) {
|
|
243
|
+
hideNotification();
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
157
246
|
autoHideTimerRef.current = setTimeout(() => hideNotification(), ms);
|
|
158
247
|
}
|
|
159
248
|
|
|
249
|
+
function resumeAutoHide() {
|
|
250
|
+
const current = dataRef.current;
|
|
251
|
+
const startMs = current?.scheduledStart
|
|
252
|
+
? Date.parse(current.scheduledStart)
|
|
253
|
+
: NaN;
|
|
254
|
+
const hideMs = Number.isFinite(startMs)
|
|
255
|
+
? meetingNotificationAutoHideMs(startMs)
|
|
256
|
+
: FALLBACK_AUTO_HIDE_MS;
|
|
257
|
+
scheduleAutoHide(hideMs);
|
|
258
|
+
}
|
|
259
|
+
|
|
160
260
|
function hideNotification() {
|
|
161
261
|
clearAutoHide();
|
|
162
262
|
setData(null);
|
|
163
263
|
setError(null);
|
|
164
264
|
setPending(false);
|
|
265
|
+
setMenuOpen(false);
|
|
165
266
|
dataRef.current = null;
|
|
166
267
|
}
|
|
167
268
|
|
|
@@ -169,6 +270,7 @@ export function MeetingNotification() {
|
|
|
169
270
|
if (!data || pending) return;
|
|
170
271
|
setPending(true);
|
|
171
272
|
setError(null);
|
|
273
|
+
setMenuOpen(false);
|
|
172
274
|
emit("meetings:start-transcription", {
|
|
173
275
|
meetingId: data.meetingId,
|
|
174
276
|
joinUrl: data.joinUrl,
|
|
@@ -181,14 +283,23 @@ export function MeetingNotification() {
|
|
|
181
283
|
|
|
182
284
|
async function joinMeeting() {
|
|
183
285
|
if (!data?.joinUrl) return;
|
|
286
|
+
setMenuOpen(false);
|
|
184
287
|
await openJoinUrl(data.joinUrl);
|
|
185
288
|
}
|
|
186
289
|
|
|
290
|
+
/** Granola primary: join the call and start Clips notes together. */
|
|
291
|
+
async function joinAndOpenClips() {
|
|
292
|
+
if (!data || pending) return;
|
|
293
|
+
setMenuOpen(false);
|
|
294
|
+
if (data.joinUrl) {
|
|
295
|
+
await openJoinUrl(data.joinUrl);
|
|
296
|
+
}
|
|
297
|
+
await takeNotes();
|
|
298
|
+
}
|
|
299
|
+
|
|
187
300
|
function snooze() {
|
|
188
301
|
if (!data) return;
|
|
189
|
-
|
|
190
|
-
// delay even though this overlay window closes right away. A setTimeout
|
|
191
|
-
// here would be torn down with the window and never fire.
|
|
302
|
+
setMenuOpen(false);
|
|
192
303
|
invoke("meetings_snooze", {
|
|
193
304
|
meetingId: data.meetingId,
|
|
194
305
|
minutes: Math.round(SNOOZE_MS / 60_000),
|
|
@@ -202,6 +313,14 @@ export function MeetingNotification() {
|
|
|
202
313
|
|
|
203
314
|
const isCalendar = data.type === "calendar";
|
|
204
315
|
const hasJoin = Boolean(data.joinUrl);
|
|
316
|
+
const provider = detectMeetingJoinProvider(data.joinUrl, data.platform);
|
|
317
|
+
const providerName = joinProviderLabel(provider);
|
|
318
|
+
const primaryLabel = hasJoin
|
|
319
|
+
? provider === "other"
|
|
320
|
+
? "Join meeting"
|
|
321
|
+
: `Join ${providerName}`
|
|
322
|
+
: "Start notes";
|
|
323
|
+
const secondaryLabel = hasJoin ? "& open Clips" : null;
|
|
205
324
|
|
|
206
325
|
return (
|
|
207
326
|
<div
|
|
@@ -212,14 +331,11 @@ export function MeetingNotification() {
|
|
|
212
331
|
}}
|
|
213
332
|
onMouseLeave={() => {
|
|
214
333
|
setShowClose(false);
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
scheduleAutoHide(DEFAULT_AUTO_HIDE_MS);
|
|
334
|
+
setMenuOpen(false);
|
|
335
|
+
resumeAutoHide();
|
|
218
336
|
}}
|
|
219
337
|
>
|
|
220
|
-
<div
|
|
221
|
-
className={`meeting-notification${hasJoin ? " meeting-notification-with-join" : ""}`}
|
|
222
|
-
>
|
|
338
|
+
<div className="meeting-notification">
|
|
223
339
|
<div
|
|
224
340
|
className={`meeting-notification-bar ${isCalendar ? "meeting-notification-bar-calendar" : "meeting-notification-bar-adhoc"}`}
|
|
225
341
|
/>
|
|
@@ -233,34 +349,65 @@ export function MeetingNotification() {
|
|
|
233
349
|
</div>
|
|
234
350
|
) : null}
|
|
235
351
|
</div>
|
|
236
|
-
<div className="meeting-notification-
|
|
352
|
+
<div className="meeting-notification-split">
|
|
237
353
|
<button
|
|
238
|
-
className="meeting-notification-
|
|
239
|
-
onClick={takeNotes}
|
|
354
|
+
className="meeting-notification-split-main"
|
|
355
|
+
onClick={hasJoin ? joinAndOpenClips : takeNotes}
|
|
240
356
|
disabled={pending}
|
|
241
357
|
data-no-drag
|
|
242
358
|
>
|
|
243
|
-
{
|
|
359
|
+
<ProviderGlyph provider={provider} />
|
|
360
|
+
<span className="meeting-notification-split-copy">
|
|
361
|
+
<span className="meeting-notification-split-primary">
|
|
362
|
+
{pending ? "Starting…" : primaryLabel}
|
|
363
|
+
</span>
|
|
364
|
+
{secondaryLabel && !pending ? (
|
|
365
|
+
<span className="meeting-notification-split-secondary">
|
|
366
|
+
{secondaryLabel}
|
|
367
|
+
</span>
|
|
368
|
+
) : null}
|
|
369
|
+
</span>
|
|
244
370
|
</button>
|
|
245
|
-
{hasJoin ? (
|
|
246
|
-
<button
|
|
247
|
-
className="meeting-notification-btn meeting-notification-btn-secondary"
|
|
248
|
-
onClick={joinMeeting}
|
|
249
|
-
data-no-drag
|
|
250
|
-
>
|
|
251
|
-
Join
|
|
252
|
-
</button>
|
|
253
|
-
) : null}
|
|
254
371
|
<button
|
|
255
|
-
className="meeting-notification-
|
|
256
|
-
onClick={
|
|
372
|
+
className="meeting-notification-split-chevron"
|
|
373
|
+
onClick={() => setMenuOpen((open) => !open)}
|
|
374
|
+
aria-label="More actions"
|
|
375
|
+
aria-expanded={menuOpen}
|
|
257
376
|
data-no-drag
|
|
258
|
-
aria-label="Snooze 5 minutes"
|
|
259
|
-
title="Snooze 5 min"
|
|
260
377
|
>
|
|
261
|
-
<
|
|
262
|
-
<span>5m</span>
|
|
378
|
+
<IconChevronDown size={14} aria-hidden="true" />
|
|
263
379
|
</button>
|
|
380
|
+
{menuOpen ? (
|
|
381
|
+
<div className="meeting-notification-menu" role="menu">
|
|
382
|
+
{hasJoin ? (
|
|
383
|
+
<button
|
|
384
|
+
role="menuitem"
|
|
385
|
+
className="meeting-notification-menu-item"
|
|
386
|
+
onClick={joinMeeting}
|
|
387
|
+
data-no-drag
|
|
388
|
+
>
|
|
389
|
+
Join only
|
|
390
|
+
</button>
|
|
391
|
+
) : null}
|
|
392
|
+
<button
|
|
393
|
+
role="menuitem"
|
|
394
|
+
className="meeting-notification-menu-item"
|
|
395
|
+
onClick={takeNotes}
|
|
396
|
+
disabled={pending}
|
|
397
|
+
data-no-drag
|
|
398
|
+
>
|
|
399
|
+
Start notes only
|
|
400
|
+
</button>
|
|
401
|
+
<button
|
|
402
|
+
role="menuitem"
|
|
403
|
+
className="meeting-notification-menu-item"
|
|
404
|
+
onClick={snooze}
|
|
405
|
+
data-no-drag
|
|
406
|
+
>
|
|
407
|
+
Snooze 5 min
|
|
408
|
+
</button>
|
|
409
|
+
</div>
|
|
410
|
+
) : null}
|
|
264
411
|
</div>
|
|
265
412
|
{showClose ? (
|
|
266
413
|
<button
|