@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.
Files changed (383) hide show
  1. package/blueprints/action/crud.md +1 -1
  2. package/blueprints/channel/discord.md +1 -1
  3. package/blueprints/provider/stripe.md +1 -1
  4. package/blueprints/sandbox/docker.md +1 -1
  5. package/corpus/README.md +2 -2
  6. package/corpus/core/CHANGELOG.md +31 -0
  7. package/corpus/core/blueprints/action/crud.md +1 -1
  8. package/corpus/core/blueprints/channel/discord.md +1 -1
  9. package/corpus/core/blueprints/provider/stripe.md +1 -1
  10. package/corpus/core/blueprints/sandbox/docker.md +1 -1
  11. package/corpus/core/docs/content/faq.mdx +17 -0
  12. package/corpus/core/docs/content/notifications.mdx +12 -6
  13. package/corpus/core/package.json +6 -5
  14. package/corpus/core/src/agent/production-agent.ts +140 -46
  15. package/corpus/core/src/agent/run-manager.ts +23 -2
  16. package/corpus/core/src/agent/run-store.ts +2 -2
  17. package/corpus/core/src/agent/tool-search.ts +71 -4
  18. package/corpus/core/src/cli/add.ts +1 -1
  19. package/corpus/core/src/cli/create.ts +8 -3
  20. package/corpus/core/src/cli/index.ts +25 -4
  21. package/corpus/core/src/cli/upgrade.ts +798 -0
  22. package/corpus/core/src/client/AssistantChat.tsx +1 -1
  23. package/corpus/core/src/client/HighlightedCodeBlock.tsx +20 -3
  24. package/corpus/core/src/client/agent-chat-adapter.ts +31 -6
  25. package/corpus/core/src/client/chat/message-components.tsx +85 -8
  26. package/corpus/core/src/client/chat/tool-call-display.tsx +355 -144
  27. package/corpus/core/src/client/code-agent-chat-adapter.ts +2 -9
  28. package/corpus/core/src/client/extensions/ExtensionSlot.tsx +7 -0
  29. package/corpus/core/src/client/settings/SettingsPanel.tsx +533 -389
  30. package/corpus/core/src/client/settings/SettingsSection.tsx +154 -17
  31. package/corpus/core/src/client/sse-event-processor.ts +29 -2
  32. package/corpus/core/src/extensions/actions.ts +113 -5
  33. package/corpus/core/src/jobs/scheduler.ts +30 -1
  34. package/corpus/core/src/localization/default-messages.ts +21 -0
  35. package/corpus/core/src/notifications/channels.ts +88 -25
  36. package/corpus/core/src/notifications/registry.ts +17 -3
  37. package/corpus/core/src/notifications/types.ts +4 -1
  38. package/corpus/core/src/server/agent-chat-plugin.ts +7 -3
  39. package/corpus/core/src/server/request-context.ts +7 -0
  40. package/corpus/core/src/styles/agent-conversation.css +1 -1
  41. package/corpus/core/src/templates/default/.agents/skills/self-modifying-code/SKILL.md +20 -2
  42. package/corpus/core/src/templates/default/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  43. package/corpus/core/src/templates/default/AGENTS.md +10 -3
  44. package/corpus/core/src/templates/default/app/i18n/ar-SA.ts +21 -0
  45. package/corpus/core/src/templates/default/app/i18n/de-DE.ts +21 -0
  46. package/corpus/core/src/templates/default/app/i18n/en-US.ts +21 -0
  47. package/corpus/core/src/templates/default/app/i18n/es-ES.ts +21 -0
  48. package/corpus/core/src/templates/default/app/i18n/fr-FR.ts +21 -0
  49. package/corpus/core/src/templates/default/app/i18n/hi-IN.ts +20 -0
  50. package/corpus/core/src/templates/default/app/i18n/ja-JP.ts +21 -0
  51. package/corpus/core/src/templates/default/app/i18n/ko-KR.ts +20 -0
  52. package/corpus/core/src/templates/default/app/i18n/pt-BR.ts +21 -0
  53. package/corpus/core/src/templates/default/app/i18n/zh-CN.ts +20 -0
  54. package/corpus/core/src/templates/default/app/i18n/zh-TW.ts +19 -0
  55. package/corpus/core/src/templates/default/package.json +4 -3
  56. package/corpus/core/src/templates/headless/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  57. package/corpus/core/src/templates/headless/AGENTS.md +9 -3
  58. package/corpus/core/src/templates/headless/package.json +4 -3
  59. package/corpus/core/src/templates/workspace-core/.agents/skills/self-modifying-code/SKILL.md +20 -2
  60. package/corpus/core/src/templates/workspace-core/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  61. package/corpus/core/src/templates/workspace-core/package.json +6 -6
  62. package/corpus/core/src/templates/workspace-root/AGENTS.md +10 -4
  63. package/corpus/core/src/templates/workspace-root/package.json +3 -2
  64. package/corpus/core/src/triggers/dispatcher.ts +30 -2
  65. package/corpus/core/src/vite/client.ts +96 -1
  66. package/corpus/templates/analytics/.agents/skills/self-modifying-code/SKILL.md +20 -2
  67. package/corpus/templates/analytics/.agents/skills/session-replay/SKILL.md +20 -2
  68. package/corpus/templates/analytics/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  69. package/corpus/templates/analytics/AGENTS.md +7 -5
  70. package/corpus/templates/analytics/actions/save-monitor.ts +14 -0
  71. package/corpus/templates/analytics/app/components/dashboard/DataTable.tsx +41 -6
  72. package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +122 -11
  73. package/corpus/templates/analytics/app/global.css +26 -10
  74. package/corpus/templates/analytics/app/i18n/zh-TW.ts +2 -0
  75. package/corpus/templates/analytics/app/i18n-data.ts +25 -0
  76. package/corpus/templates/analytics/app/pages/monitoring/MonitoringPage.tsx +8 -2
  77. package/corpus/templates/analytics/app/pages/monitoring/uptime/MonitorFormPage.tsx +151 -32
  78. package/corpus/templates/analytics/app/pages/monitoring/uptime/i18n.ts +17 -2
  79. package/corpus/templates/analytics/app/pages/monitoring/uptime/types.ts +4 -0
  80. package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +461 -286
  81. package/corpus/templates/analytics/app/pages/sessions/SessionDevToolsPanel.tsx +285 -294
  82. package/corpus/templates/analytics/changelog/2026-07-08-console-details-expand-inline-under-each-row-and-the-event-t.md +6 -0
  83. package/corpus/templates/analytics/changelog/2026-07-08-dashboard-tables-keep-their-size-while-loading.md +6 -0
  84. package/corpus/templates/analytics/changelog/2026-07-08-monitoring-uptime-and-errors-tabs-now-clearly-show-which-view-is-active.md +6 -0
  85. package/corpus/templates/analytics/changelog/2026-07-08-session-replay-keeps-a-usable-stage-when-dev-tools-is-open-a.md +6 -0
  86. package/corpus/templates/analytics/changelog/2026-07-08-session-replay-resumes-after-scrubbing-and-expands-console-r.md +6 -0
  87. package/corpus/templates/analytics/changelog/2026-07-08-session-replay-uses-stock-rrweb-sizing-again-so-recorded.md +6 -0
  88. package/corpus/templates/analytics/changelog/2026-07-08-session-replays-wait-for-full-load-keep-a-normal-viewport-an.md +6 -0
  89. package/corpus/templates/analytics/changelog/2026-07-08-sidebar-dashboard-menus-now-open-above-the-dashboard-canvas.md +6 -0
  90. 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
  91. package/corpus/templates/analytics/docs/uptime-monitoring.md +13 -11
  92. package/corpus/templates/analytics/package.json +2 -2
  93. package/corpus/templates/analytics/server/db/schema-monitoring.ts +4 -0
  94. package/corpus/templates/analytics/server/lib/uptime-monitors.ts +60 -12
  95. package/corpus/templates/analytics/server/plugins/db.ts +10 -0
  96. package/corpus/templates/assets/.agents/skills/self-modifying-code/SKILL.md +20 -2
  97. package/corpus/templates/assets/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  98. package/corpus/templates/assets/package.json +2 -2
  99. package/corpus/templates/brain/.agents/skills/self-modifying-code/SKILL.md +20 -2
  100. package/corpus/templates/brain/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  101. package/corpus/templates/brain/package.json +2 -2
  102. package/corpus/templates/calendar/.agents/skills/self-modifying-code/SKILL.md +20 -2
  103. package/corpus/templates/calendar/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  104. package/corpus/templates/calendar/AGENTS.md +10 -0
  105. package/corpus/templates/calendar/actions/create-event.ts +5 -1
  106. package/corpus/templates/calendar/actions/event-action-helpers.ts +41 -0
  107. package/corpus/templates/calendar/actions/get-attendee-timezones.ts +28 -0
  108. package/corpus/templates/calendar/actions/set-attendee-timezone.ts +68 -0
  109. package/corpus/templates/calendar/app/components/calendar/EventAttendeesSection.tsx +150 -11
  110. package/corpus/templates/calendar/app/components/calendar/EventDetailPanel.tsx +36 -1
  111. package/corpus/templates/calendar/app/components/calendar/EventDetailPopover.tsx +32 -0
  112. package/corpus/templates/calendar/app/hooks/use-attendee-timezones.ts +24 -0
  113. package/corpus/templates/calendar/app/i18n/zh-TW.ts +2 -0
  114. package/corpus/templates/calendar/app/i18n-data.ts +20 -0
  115. package/corpus/templates/calendar/app/lib/attendee-local-time.ts +122 -0
  116. package/corpus/templates/calendar/changelog/2026-07-08-event-details-now-support-extension-widgets-and-you-can-see-.md +6 -0
  117. package/corpus/templates/calendar/changelog/2026-07-08-when-you-invite-guests-to-a-new-event-you-now-appear-in.md +6 -0
  118. package/corpus/templates/calendar/package.json +2 -2
  119. package/corpus/templates/calendar/server/handlers/events.ts +5 -1
  120. package/corpus/templates/calendar/shared/api.ts +6 -0
  121. package/corpus/templates/chat/.agents/skills/self-modifying-code/SKILL.md +20 -2
  122. package/corpus/templates/chat/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  123. package/corpus/templates/chat/package.json +2 -2
  124. package/corpus/templates/clips/.agents/skills/meetings/SKILL.md +6 -2
  125. package/corpus/templates/clips/.agents/skills/self-modifying-code/SKILL.md +20 -2
  126. package/corpus/templates/clips/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  127. package/corpus/templates/clips/actions/create-meeting.ts +8 -3
  128. package/corpus/templates/clips/actions/list-meetings.ts +31 -3
  129. package/corpus/templates/clips/changelog/2026-07-08-after-finishing-a-desktop-recording-reopening-clips-restor.md +6 -0
  130. package/corpus/templates/clips/changelog/2026-07-08-clips-now-pops-up-to-take-notes-when-you-join-an-adhoc-zoom-.md +6 -0
  131. package/corpus/templates/clips/changelog/2026-07-08-desktop-clip-recordings-are-louder-after-capture-mic-only.md +6 -0
  132. package/corpus/templates/clips/changelog/2026-07-08-desktop-meeting-notes-stay-active-from-tray-and-shortcut-controls.md +6 -0
  133. package/corpus/templates/clips/changelog/2026-07-08-desktop-meeting-popovers-can-start-notes-and-join-the-meetin.md +6 -0
  134. package/corpus/templates/clips/changelog/2026-07-08-meeting-notes-keep-their-recording-state-when-the-desktop.md +6 -0
  135. package/corpus/templates/clips/changelog/2026-07-08-meeting-reminder-dropdowns-now-expand-fully-instead-of-being.md +6 -0
  136. package/corpus/templates/clips/changelog/2026-07-08-meeting-reminders-now-appear-1-minute-before-start-stay-unti.md +6 -0
  137. package/corpus/templates/clips/changelog/2026-07-08-the-desktop-meetings-panel-has-room-for-its-drop-shadow-and-.md +6 -0
  138. package/corpus/templates/clips/chrome-extension/package.json +2 -2
  139. package/corpus/templates/clips/desktop/package.json +2 -2
  140. package/corpus/templates/clips/desktop/src/app.tsx +214 -37
  141. package/corpus/templates/clips/desktop/src/hooks/useMeetingTranscription.ts +30 -6
  142. package/corpus/templates/clips/desktop/src/lib/meeting-notification-timing.ts +83 -0
  143. package/corpus/templates/clips/desktop/src/lib/native-recording-warm.ts +21 -0
  144. package/corpus/templates/clips/desktop/src/lib/recorder.ts +98 -20
  145. package/corpus/templates/clips/desktop/src/overlays/meeting-notification.tsx +197 -50
  146. package/corpus/templates/clips/desktop/src/styles.css +150 -53
  147. package/corpus/templates/clips/desktop/src-tauri/src/adhoc_meetings_watcher.rs +362 -0
  148. package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +41 -7
  149. package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +9 -2
  150. package/corpus/templates/clips/desktop/src-tauri/src/meetings_watcher.rs +89 -11
  151. package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +71 -17
  152. package/corpus/templates/clips/desktop/src-tauri/src/native_speech.rs +36 -1
  153. package/corpus/templates/clips/desktop/src-tauri/src/notifications.rs +62 -10
  154. package/corpus/templates/clips/desktop/src-tauri/src/shortcuts.rs +3 -3
  155. package/corpus/templates/clips/desktop/src-tauri/src/silence_detector.rs +1 -25
  156. package/corpus/templates/clips/desktop/src-tauri/src/state.rs +5 -0
  157. package/corpus/templates/clips/desktop/src-tauri/src/tray.rs +18 -6
  158. package/corpus/templates/clips/desktop/src-tauri/src/util.rs +36 -1
  159. package/corpus/templates/clips/package.json +2 -2
  160. package/corpus/templates/content/.agents/skills/self-modifying-code/SKILL.md +20 -2
  161. package/corpus/templates/content/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  162. package/corpus/templates/content/actions/_batch-utils.ts +8 -0
  163. package/corpus/templates/content/actions/_builder-cms-read-client.ts +7 -5
  164. package/corpus/templates/content/actions/_content-database-personal-view.ts +80 -0
  165. package/corpus/templates/content/actions/_database-source-utils.ts +776 -319
  166. package/corpus/templates/content/actions/_database-utils.ts +6 -1
  167. package/corpus/templates/content/actions/_property-utils.ts +168 -0
  168. package/corpus/templates/content/actions/add-content-database-source-field-property.ts +19 -12
  169. package/corpus/templates/content/actions/bind-content-database-source-field.ts +19 -12
  170. package/corpus/templates/content/actions/delete-document.ts +9 -13
  171. package/corpus/templates/content/actions/get-content-database-personal-view.ts +27 -0
  172. package/corpus/templates/content/actions/refresh-content-database-source.ts +5 -5
  173. package/corpus/templates/content/actions/update-content-database-personal-view.ts +31 -0
  174. package/corpus/templates/content/actions/update-content-database-view.ts +3 -0
  175. package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +1 -1
  176. package/corpus/templates/content/app/components/editor/body-hydration.ts +35 -11
  177. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +2631 -551
  178. package/corpus/templates/content/app/components/editor/database/filter-sort.ts +220 -18
  179. package/corpus/templates/content/app/hooks/use-content-database.ts +32 -0
  180. package/corpus/templates/content/app/hooks/use-documents.ts +8 -2
  181. package/corpus/templates/content/app/i18n/zh-TW.ts +16 -0
  182. package/corpus/templates/content/app/i18n-data.ts +154 -0
  183. package/corpus/templates/content/changelog/2026-07-08-builder-source-sync-now-completes-reliably-on-hosted-databases.md +6 -0
  184. package/corpus/templates/content/changelog/2026-07-08-database-filters-now-support-notion-style-reset-save-for-eve.md +6 -0
  185. package/corpus/templates/content/changelog/2026-07-08-date-filters-can-now-target-a-between-range.md +6 -0
  186. package/corpus/templates/content/changelog/2026-07-08-fixed-builder-database-sync-so-large-sources-continue-past-t.md +6 -0
  187. package/corpus/templates/content/package.json +2 -2
  188. package/corpus/templates/content/parity/matrix.md +1 -1
  189. package/corpus/templates/content/parity/matrix.ts +2 -0
  190. package/corpus/templates/content/server/plugins/db.ts +19 -0
  191. package/corpus/templates/content/shared/api.ts +24 -0
  192. package/corpus/templates/design/.agents/skills/self-modifying-code/SKILL.md +20 -2
  193. package/corpus/templates/design/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  194. package/corpus/templates/design/package.json +2 -2
  195. package/corpus/templates/dispatch/.agents/skills/self-modifying-code/SKILL.md +20 -2
  196. package/corpus/templates/dispatch/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  197. package/corpus/templates/dispatch/app/i18n/zh-TW.ts +34 -1
  198. package/corpus/templates/dispatch/app/i18n-data.ts +387 -10
  199. package/corpus/templates/dispatch/app/routes/automations.tsx +1 -0
  200. package/corpus/templates/dispatch/changelog/2026-07-08-added-an-automations-page-to-review-pause-and-create.md +6 -0
  201. package/corpus/templates/dispatch/changelog/2026-07-08-destinations-now-shows-outbound-delivery-queue-health.md +6 -0
  202. package/corpus/templates/dispatch/package.json +2 -2
  203. package/corpus/templates/forms/.agents/skills/self-modifying-code/SKILL.md +20 -2
  204. package/corpus/templates/forms/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  205. package/corpus/templates/forms/package.json +2 -2
  206. package/corpus/templates/macros/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  207. package/corpus/templates/macros/package.json +2 -2
  208. package/corpus/templates/mail/.agents/skills/self-modifying-code/SKILL.md +20 -2
  209. package/corpus/templates/mail/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  210. package/corpus/templates/mail/app/hooks/use-emails.ts +56 -44
  211. package/corpus/templates/mail/app/lib/gmail-mutation-queue.ts +325 -0
  212. package/corpus/templates/mail/changelog/2026-07-08-rapid-archive-and-mark-read-now-batch-gmail-updates-so-the-i.md +6 -0
  213. package/corpus/templates/mail/package.json +2 -2
  214. package/corpus/templates/plan/.agents/skills/self-modifying-code/SKILL.md +20 -2
  215. package/corpus/templates/plan/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  216. package/corpus/templates/plan/package.json +2 -2
  217. package/corpus/templates/slides/.agents/skills/self-modifying-code/SKILL.md +20 -2
  218. package/corpus/templates/slides/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  219. package/corpus/templates/slides/app/components/editor/ImageDropPromptPopover.tsx +46 -29
  220. package/corpus/templates/slides/app/context/DeckContext.tsx +45 -18
  221. package/corpus/templates/slides/app/i18n/ar-SA.ts +4 -0
  222. package/corpus/templates/slides/app/i18n/de-DE.ts +4 -0
  223. package/corpus/templates/slides/app/i18n/en-US.ts +4 -0
  224. package/corpus/templates/slides/app/i18n/es-ES.ts +4 -0
  225. package/corpus/templates/slides/app/i18n/fr-FR.ts +4 -0
  226. package/corpus/templates/slides/app/i18n/hi-IN.ts +4 -0
  227. package/corpus/templates/slides/app/i18n/ja-JP.ts +4 -0
  228. package/corpus/templates/slides/app/i18n/ko-KR.ts +4 -0
  229. package/corpus/templates/slides/app/i18n/pt-BR.ts +4 -0
  230. package/corpus/templates/slides/app/i18n/zh-CN.ts +4 -0
  231. package/corpus/templates/slides/app/i18n/zh-TW.ts +4 -0
  232. package/corpus/templates/slides/app/lib/image-drop-to-agent.ts +115 -0
  233. package/corpus/templates/slides/app/pages/DeckEditor.tsx +22 -13
  234. package/corpus/templates/slides/changelog/2026-07-08-dropping-an-image-onto-a-slide-and-sending-it-to-the-agent-w.md +6 -0
  235. package/corpus/templates/slides/changelog/2026-07-08-undo-works-after-the-agent-edits-a-slide-so-you-can-reverse.md +6 -0
  236. package/corpus/templates/slides/package.json +2 -2
  237. package/corpus/templates/videos/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  238. package/corpus/templates/voice/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  239. package/dist/agent/production-agent.d.ts +5 -1
  240. package/dist/agent/production-agent.d.ts.map +1 -1
  241. package/dist/agent/production-agent.js +112 -42
  242. package/dist/agent/production-agent.js.map +1 -1
  243. package/dist/agent/run-manager.d.ts.map +1 -1
  244. package/dist/agent/run-manager.js +23 -2
  245. package/dist/agent/run-manager.js.map +1 -1
  246. package/dist/agent/run-store.js +2 -2
  247. package/dist/agent/run-store.js.map +1 -1
  248. package/dist/agent/tool-search.d.ts +2 -0
  249. package/dist/agent/tool-search.d.ts.map +1 -1
  250. package/dist/agent/tool-search.js +60 -4
  251. package/dist/agent/tool-search.js.map +1 -1
  252. package/dist/catalog.json +2 -2
  253. package/dist/cli/add.js +1 -1
  254. package/dist/cli/add.js.map +1 -1
  255. package/dist/cli/create.d.ts.map +1 -1
  256. package/dist/cli/create.js +8 -3
  257. package/dist/cli/create.js.map +1 -1
  258. package/dist/cli/index.js +24 -4
  259. package/dist/cli/index.js.map +1 -1
  260. package/dist/cli/upgrade.d.ts +100 -0
  261. package/dist/cli/upgrade.d.ts.map +1 -0
  262. package/dist/cli/upgrade.js +678 -0
  263. package/dist/cli/upgrade.js.map +1 -0
  264. package/dist/client/AssistantChat.js +1 -1
  265. package/dist/client/AssistantChat.js.map +1 -1
  266. package/dist/client/HighlightedCodeBlock.d.ts +2 -0
  267. package/dist/client/HighlightedCodeBlock.d.ts.map +1 -1
  268. package/dist/client/HighlightedCodeBlock.js +10 -1
  269. package/dist/client/HighlightedCodeBlock.js.map +1 -1
  270. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  271. package/dist/client/agent-chat-adapter.js +32 -4
  272. package/dist/client/agent-chat-adapter.js.map +1 -1
  273. package/dist/client/chat/message-components.d.ts.map +1 -1
  274. package/dist/client/chat/message-components.js +61 -8
  275. package/dist/client/chat/message-components.js.map +1 -1
  276. package/dist/client/chat/tool-call-display.d.ts +12 -0
  277. package/dist/client/chat/tool-call-display.d.ts.map +1 -1
  278. package/dist/client/chat/tool-call-display.js +136 -42
  279. package/dist/client/chat/tool-call-display.js.map +1 -1
  280. package/dist/client/code-agent-chat-adapter.js +2 -9
  281. package/dist/client/code-agent-chat-adapter.js.map +1 -1
  282. package/dist/client/extensions/ExtensionSlot.js +6 -0
  283. package/dist/client/extensions/ExtensionSlot.js.map +1 -1
  284. package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
  285. package/dist/client/settings/SettingsPanel.js +52 -19
  286. package/dist/client/settings/SettingsPanel.js.map +1 -1
  287. package/dist/client/settings/SettingsSection.d.ts +19 -4
  288. package/dist/client/settings/SettingsSection.d.ts.map +1 -1
  289. package/dist/client/settings/SettingsSection.js +33 -4
  290. package/dist/client/settings/SettingsSection.js.map +1 -1
  291. package/dist/client/sse-event-processor.d.ts +9 -0
  292. package/dist/client/sse-event-processor.d.ts.map +1 -1
  293. package/dist/client/sse-event-processor.js +20 -2
  294. package/dist/client/sse-event-processor.js.map +1 -1
  295. package/dist/collab/routes.d.ts +1 -1
  296. package/dist/collab/struct-routes.d.ts +1 -1
  297. package/dist/extensions/actions.d.ts.map +1 -1
  298. package/dist/extensions/actions.js +85 -5
  299. package/dist/extensions/actions.js.map +1 -1
  300. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  301. package/dist/jobs/scheduler.js +26 -1
  302. package/dist/jobs/scheduler.js.map +1 -1
  303. package/dist/localization/default-messages.d.ts +19 -0
  304. package/dist/localization/default-messages.d.ts.map +1 -1
  305. package/dist/localization/default-messages.js +19 -0
  306. package/dist/localization/default-messages.js.map +1 -1
  307. package/dist/notifications/channels.d.ts +8 -3
  308. package/dist/notifications/channels.d.ts.map +1 -1
  309. package/dist/notifications/channels.js +61 -22
  310. package/dist/notifications/channels.js.map +1 -1
  311. package/dist/notifications/registry.d.ts.map +1 -1
  312. package/dist/notifications/registry.js +14 -3
  313. package/dist/notifications/registry.js.map +1 -1
  314. package/dist/notifications/routes.d.ts +1 -1
  315. package/dist/notifications/types.d.ts +4 -1
  316. package/dist/notifications/types.d.ts.map +1 -1
  317. package/dist/notifications/types.js.map +1 -1
  318. package/dist/observability/routes.d.ts +1 -1
  319. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  320. package/dist/resources/handlers.d.ts +3 -3
  321. package/dist/server/agent-chat-plugin.d.ts +5 -1
  322. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  323. package/dist/server/agent-chat-plugin.js +2 -2
  324. package/dist/server/agent-chat-plugin.js.map +1 -1
  325. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  326. package/dist/server/request-context.d.ts +7 -0
  327. package/dist/server/request-context.d.ts.map +1 -1
  328. package/dist/server/request-context.js.map +1 -1
  329. package/dist/styles/agent-conversation.css +1 -1
  330. package/dist/templates/default/.agents/skills/self-modifying-code/SKILL.md +20 -2
  331. package/dist/templates/default/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  332. package/dist/templates/default/AGENTS.md +10 -3
  333. package/dist/templates/default/app/i18n/ar-SA.ts +21 -0
  334. package/dist/templates/default/app/i18n/de-DE.ts +21 -0
  335. package/dist/templates/default/app/i18n/en-US.ts +21 -0
  336. package/dist/templates/default/app/i18n/es-ES.ts +21 -0
  337. package/dist/templates/default/app/i18n/fr-FR.ts +21 -0
  338. package/dist/templates/default/app/i18n/hi-IN.ts +20 -0
  339. package/dist/templates/default/app/i18n/ja-JP.ts +21 -0
  340. package/dist/templates/default/app/i18n/ko-KR.ts +20 -0
  341. package/dist/templates/default/app/i18n/pt-BR.ts +21 -0
  342. package/dist/templates/default/app/i18n/zh-CN.ts +20 -0
  343. package/dist/templates/default/app/i18n/zh-TW.ts +19 -0
  344. package/dist/templates/default/package.json +4 -3
  345. package/dist/templates/headless/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  346. package/dist/templates/headless/AGENTS.md +9 -3
  347. package/dist/templates/headless/package.json +4 -3
  348. package/dist/templates/workspace-core/.agents/skills/self-modifying-code/SKILL.md +20 -2
  349. package/dist/templates/workspace-core/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  350. package/dist/templates/workspace-core/package.json +6 -6
  351. package/dist/templates/workspace-root/AGENTS.md +10 -4
  352. package/dist/templates/workspace-root/package.json +3 -2
  353. package/dist/triggers/dispatcher.js +27 -2
  354. package/dist/triggers/dispatcher.js.map +1 -1
  355. package/dist/vite/client.d.ts.map +1 -1
  356. package/dist/vite/client.js +70 -1
  357. package/dist/vite/client.js.map +1 -1
  358. package/docs/content/faq.mdx +17 -0
  359. package/docs/content/notifications.mdx +12 -6
  360. package/package.json +7 -6
  361. package/src/templates/default/.agents/skills/self-modifying-code/SKILL.md +20 -2
  362. package/src/templates/default/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  363. package/src/templates/default/AGENTS.md +10 -3
  364. package/src/templates/default/app/i18n/ar-SA.ts +21 -0
  365. package/src/templates/default/app/i18n/de-DE.ts +21 -0
  366. package/src/templates/default/app/i18n/en-US.ts +21 -0
  367. package/src/templates/default/app/i18n/es-ES.ts +21 -0
  368. package/src/templates/default/app/i18n/fr-FR.ts +21 -0
  369. package/src/templates/default/app/i18n/hi-IN.ts +20 -0
  370. package/src/templates/default/app/i18n/ja-JP.ts +21 -0
  371. package/src/templates/default/app/i18n/ko-KR.ts +20 -0
  372. package/src/templates/default/app/i18n/pt-BR.ts +21 -0
  373. package/src/templates/default/app/i18n/zh-CN.ts +20 -0
  374. package/src/templates/default/app/i18n/zh-TW.ts +19 -0
  375. package/src/templates/default/package.json +4 -3
  376. package/src/templates/headless/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  377. package/src/templates/headless/AGENTS.md +9 -3
  378. package/src/templates/headless/package.json +4 -3
  379. package/src/templates/workspace-core/.agents/skills/self-modifying-code/SKILL.md +20 -2
  380. package/src/templates/workspace-core/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  381. package/src/templates/workspace-core/package.json +6 -6
  382. package/src/templates/workspace-root/AGENTS.md +10 -4
  383. package/src/templates/workspace-root/package.json +3 -2
@@ -73,6 +73,15 @@ export default defineAction({
73
73
  .describe(
74
74
  "If set, only return upcoming meetings starting within this many minutes. Used by the desktop reminder watcher.",
75
75
  ),
76
+ includeStartedWithinMin: z.coerce
77
+ .number()
78
+ .int()
79
+ .min(0)
80
+ .max(60)
81
+ .optional()
82
+ .describe(
83
+ "Also include meetings that started within this many minutes (desktop reminder hold window). Default 0.",
84
+ ),
76
85
  }),
77
86
  http: { method: "GET" },
78
87
  run: async (args) => {
@@ -92,6 +101,11 @@ export default defineAction({
92
101
  now.getTime() + args.upcomingWithinMin * 60 * 1000,
93
102
  ).toISOString()
94
103
  : null;
104
+ const startedWithinMin = args.includeStartedWithinMin ?? 0;
105
+ const upcomingWindowMinIso =
106
+ startedWithinMin > 0
107
+ ? new Date(now.getTime() - startedWithinMin * 60 * 1000).toISOString()
108
+ : nowIso;
95
109
 
96
110
  const whereClauses = [accessFilter(schema.meetings, schema.meetingShares)];
97
111
 
@@ -102,11 +116,12 @@ export default defineAction({
102
116
  }
103
117
 
104
118
  if (args.view === "upcoming") {
105
- // Scheduled in the future and not yet finished.
119
+ // Scheduled in the future (or recently started, for desktop hold window)
120
+ // and not yet finished.
106
121
  whereClauses.push(
107
122
  and(
108
123
  isNotNull(schema.meetings.scheduledStart),
109
- gte(schema.meetings.scheduledStart, nowIso),
124
+ gte(schema.meetings.scheduledStart, upcomingWindowMinIso),
110
125
  isNull(schema.meetings.actualStart),
111
126
  isNull(schema.meetings.actualEnd),
112
127
  upcomingWindowMaxIso
@@ -209,7 +224,10 @@ export default defineAction({
209
224
  ? new Date(now.getTime() - THIRTY_DAYS_MS).toISOString()
210
225
  : args.view === "all"
211
226
  ? new Date(now.getTime() - THIRTY_DAYS_MS).toISOString()
212
- : new Date(now.getTime() - 60 * 1000).toISOString();
227
+ : startedWithinMin > 0
228
+ ? upcomingWindowMinIso
229
+ : // Small cushion for clock skew when listing pure upcoming.
230
+ new Date(now.getTime() - 60 * 1000).toISOString();
213
231
  const timeMax =
214
232
  args.view === "past"
215
233
  ? nowIso
@@ -253,6 +271,16 @@ export default defineAction({
253
271
  const endMs = Date.parse(endIso);
254
272
  if (Number.isNaN(startMs) || Number.isNaN(endMs)) continue;
255
273
  if (args.view === "upcoming" && endMs < now.getTime()) continue;
274
+ // Only clamp already-started events when the desktop hold window
275
+ // is active — the normal Meetings list still shows in-progress
276
+ // calendar events until they end.
277
+ if (
278
+ args.view === "upcoming" &&
279
+ startedWithinMin > 0 &&
280
+ startMs < Date.parse(upcomingWindowMinIso)
281
+ ) {
282
+ continue;
283
+ }
256
284
  if (args.view === "past" && endMs >= now.getTime()) continue;
257
285
  if (
258
286
  upcomingWindowMaxIso &&
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-07-08
4
+ ---
5
+
6
+ After finishing a desktop recording, reopening Clips restores the camera preview and Start Recording works again instead of doing nothing.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: added
3
+ date: 2026-07-08
4
+ ---
5
+
6
+ Clips now pops up to take notes when you join an adhoc Zoom or Teams call, like Granola.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-07-08
4
+ ---
5
+
6
+ Desktop clip recordings are louder after capture — mic-only clips skip the half-volume downmix and get a stronger pre-gain before loudness normalization; mic+system clips get makeup gain so the centered mix is not systematically quieter.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-07-08
4
+ ---
5
+
6
+ Desktop meeting notes stay active when you open the tray or shortcut controls, and the stop action targets the live meeting.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-07-08
4
+ ---
5
+
6
+ Meeting reminders in the desktop popover can start notes and join the call in one click.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-07-08
4
+ ---
5
+
6
+ Meeting notes keep their recording state when the desktop popover is closed and reopened.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-07-08
4
+ ---
5
+
6
+ Meeting reminder dropdowns now expand fully instead of being cut off.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-07-08
4
+ ---
5
+
6
+ Meeting reminders now appear 1 minute before start, stay until 5 minutes in, and use a Granola-style Join & open Clips button
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-07-08
4
+ ---
5
+
6
+ The desktop Meetings panel has room for its drop shadow and a little more space below the last meeting.
@@ -7,7 +7,7 @@
7
7
  "dev": "vite build --watch",
8
8
  "dev:hot": "tsx scripts/dev.ts",
9
9
  "build": "vite build",
10
- "typecheck": "tsgo --noEmit",
10
+ "typecheck": "tsc --noEmit",
11
11
  "package": "pnpm build && tsx scripts/package.ts"
12
12
  },
13
13
  "dependencies": {
@@ -15,9 +15,9 @@
15
15
  },
16
16
  "devDependencies": {
17
17
  "@types/chrome": "^0.2.0",
18
- "@typescript/native-preview": "catalog:",
19
18
  "tsx": "catalog:",
20
19
  "typescript": "catalog:",
20
+ "typescript-7": "catalog:",
21
21
  "vite": "catalog:"
22
22
  }
23
23
  }
@@ -31,9 +31,9 @@
31
31
  "@tauri-apps/cli": "^2.11.2",
32
32
  "@types/react": "^19.2.14",
33
33
  "@types/react-dom": "^19.2.3",
34
- "@typescript/native-preview": "catalog:",
35
34
  "@vitejs/plugin-react": "catalog:",
36
- "typescript": "^6.0.3",
35
+ "typescript": "catalog:",
36
+ "typescript-7": "catalog:",
37
37
  "vite": "catalog:"
38
38
  }
39
39
  }
@@ -713,6 +713,7 @@ export function App() {
713
713
  const [meetingStartMessage, setMeetingStartMessage] = useState<string | null>(
714
714
  null,
715
715
  );
716
+ const [activeMeetingId, setActiveMeetingId] = useState<string | null>(null);
716
717
  const [readinessOpen, setReadinessOpen] = useState<boolean>(
717
718
  () => !loadBool(READINESS_REVIEWED_KEY, false),
718
719
  );
@@ -1140,6 +1141,7 @@ export function App() {
1140
1141
  }, [authStatus, callClipsAction]);
1141
1142
 
1142
1143
  const startMeetingNotes = useCallback((meeting: PopoverMeeting) => {
1144
+ setActiveMeetingId(meeting.id);
1143
1145
  setMeetingStartMessage(`Starting notes for ${meeting.title}…`);
1144
1146
  emit("meetings:start-transcription", {
1145
1147
  meetingId: meeting.id,
@@ -1147,10 +1149,98 @@ export function App() {
1147
1149
  reason: "user",
1148
1150
  }).catch((err) => {
1149
1151
  console.error("[clips-popover] start meeting notes failed:", err);
1152
+ setActiveMeetingId(null);
1150
1153
  setMeetingStartMessage("Could not start notes. Try again from Meetings.");
1151
1154
  });
1152
1155
  }, []);
1153
1156
 
1157
+ const startMeetingNotesAndJoin = useCallback(
1158
+ (meeting: PopoverMeeting) => {
1159
+ if (meeting.joinUrl) {
1160
+ openExternal(meeting.joinUrl).catch((err) => {
1161
+ console.error("[clips-popover] open meeting join url failed:", err);
1162
+ });
1163
+ }
1164
+ startMeetingNotes(meeting);
1165
+ },
1166
+ [startMeetingNotes],
1167
+ );
1168
+
1169
+ const showActiveMeetingPill = useCallback((meetingId: string) => {
1170
+ invoke("recording_pill_show", { meetingId, mode: "meeting" }).catch(
1171
+ (err) => {
1172
+ console.error("[clips-popover] show meeting pill failed:", err);
1173
+ },
1174
+ );
1175
+ emit("clips:pill-context", { meetingId, mode: "meeting" }).catch(() => {});
1176
+ }, []);
1177
+
1178
+ useEffect(() => {
1179
+ invoke<string | null>("get_active_meeting_id")
1180
+ .then((meetingId) => {
1181
+ if (meetingId) setActiveMeetingId(meetingId);
1182
+ })
1183
+ .catch(() => {});
1184
+
1185
+ let stopped = false;
1186
+ const unlistens: Array<() => void> = [];
1187
+ const track = (promise: Promise<() => void>) => {
1188
+ promise
1189
+ .then((unlisten) => {
1190
+ if (stopped) {
1191
+ unlisten();
1192
+ return;
1193
+ }
1194
+ unlistens.push(unlisten);
1195
+ })
1196
+ .catch(() => {});
1197
+ };
1198
+ track(
1199
+ listen<{ meetingId?: string | null }>(
1200
+ "meetings:transcription-started",
1201
+ (event) => {
1202
+ if (event.payload?.meetingId) {
1203
+ setActiveMeetingId(event.payload.meetingId);
1204
+ }
1205
+ },
1206
+ ),
1207
+ );
1208
+ track(
1209
+ listen<{ meetingId?: string | null }>(
1210
+ "meetings:transcription-stopped",
1211
+ (event) => {
1212
+ setActiveMeetingId((current) =>
1213
+ !event.payload?.meetingId || event.payload.meetingId === current
1214
+ ? null
1215
+ : current,
1216
+ );
1217
+ },
1218
+ ),
1219
+ );
1220
+ track(
1221
+ listen<{ meetingId?: string | null }>(
1222
+ "meetings:transcription-error",
1223
+ (event) => {
1224
+ setActiveMeetingId((current) =>
1225
+ !event.payload?.meetingId || event.payload.meetingId === current
1226
+ ? null
1227
+ : current,
1228
+ );
1229
+ },
1230
+ ),
1231
+ );
1232
+ return () => {
1233
+ stopped = true;
1234
+ unlistens.forEach((unlisten) => unlisten());
1235
+ unlistens.length = 0;
1236
+ };
1237
+ }, []);
1238
+
1239
+ useEffect(() => {
1240
+ if (!popoverVisible || !activeMeetingId) return;
1241
+ showActiveMeetingPill(activeMeetingId);
1242
+ }, [activeMeetingId, popoverVisible, showActiveMeetingPill]);
1243
+
1154
1244
  useMeetingTranscription({
1155
1245
  callClipsAction,
1156
1246
  serverUrl,
@@ -1286,6 +1376,9 @@ export function App() {
1286
1376
  if (e.key === "Escape") {
1287
1377
  // Don't close mid-recording — user would lose the recorder handle.
1288
1378
  if (isRecording) return;
1379
+ // Reset nested views before hide so the next tray open lands on the
1380
+ // main recorder UI instead of resuming scrolled settings/meetings.
1381
+ setPopoverView("recorder");
1289
1382
  hidePopover();
1290
1383
  }
1291
1384
  }
@@ -1328,7 +1421,11 @@ export function App() {
1328
1421
  track(
1329
1422
  listen<boolean>("clips:popover-visible", (ev) => {
1330
1423
  console.log("[clips-popover] popover-visible =", ev.payload);
1331
- setPopoverVisible(!!ev.payload);
1424
+ const visible = !!ev.payload;
1425
+ setPopoverVisible(visible);
1426
+ // Leaving settings/meetings/dictation mid-scroll should not resume on
1427
+ // the next open — always return to the main recorder surface.
1428
+ if (!visible) setPopoverView("recorder");
1332
1429
  }),
1333
1430
  );
1334
1431
  // The bubble window emits `clips:bubble-closed` when the user clicks
@@ -1415,6 +1512,10 @@ export function App() {
1415
1512
  // tracks (which causes the laggy / black / silently-failing recording
1416
1513
  // symptoms). Reset to false once the recording is fully torn down.
1417
1514
  const bubbleStreamTransferredToRecorder = useRef(false);
1515
+ // Bumped when the native stop path releases the camera mid-session so the
1516
+ // bubble effect re-acquires even if bubbleActive/cameraId are unchanged
1517
+ // (post-stop reopen with a blank "Default Camera" preview).
1518
+ const [bubbleSessionEpoch, setBubbleSessionEpoch] = useState(0);
1418
1519
  const wantsCamera = mode !== "screen" && cameraOn;
1419
1520
  const nativeFullscreenRecordingActive =
1420
1521
  mode !== "camera" && shouldUseNativeFullscreenRecording(source);
@@ -1623,14 +1724,21 @@ export function App() {
1623
1724
  invoke("hide_overlays").catch(() => {});
1624
1725
  }
1625
1726
  };
1626
- }, [bubbleActive, cameraId]);
1727
+ }, [bubbleActive, cameraId, bubbleSessionEpoch]);
1627
1728
 
1628
1729
  useEffect(() => {
1629
1730
  let unlisten: (() => void) | null = null;
1630
1731
  let cancelled = false;
1631
1732
  listen("clips:release-camera", () => {
1632
1733
  console.log(`[popover] releasing camera`);
1734
+ // Native stop closes the bubble and kills tracks while React may still
1735
+ // hold a live RecorderHandle during finalize/upload. Clear ownership so
1736
+ // the bubble session can re-acquire a fresh preview, and so Start is not
1737
+ // stuck on an ended stream.
1738
+ bubbleStreamTransferredToRecorder.current = false;
1633
1739
  bubbleStreamRef.current?.getTracks().forEach((t) => t.stop());
1740
+ bubbleStreamRef.current = null;
1741
+ setBubbleSessionEpoch((epoch) => epoch + 1);
1634
1742
  })
1635
1743
  .then((u) => {
1636
1744
  if (cancelled) u();
@@ -1643,6 +1751,24 @@ export function App() {
1643
1751
  };
1644
1752
  }, []);
1645
1753
 
1754
+ // If the popover reopens while camera is still wanted, and the previous
1755
+ // bubble stream is gone or all tracks have ended (common after native stop
1756
+ // + mid-upload reopen), bump the session epoch so the bubble effect
1757
+ // re-acquires getUserMedia + WebRTC instead of showing a blank "Default
1758
+ // Camera" label with a silent Start.
1759
+ useEffect(() => {
1760
+ if (!popoverVisible || !wantsCamera) return;
1761
+ if (recordingFlowGateRef.current || recordingFlowActive) return;
1762
+ const tracks = bubbleStreamRef.current?.getTracks() ?? [];
1763
+ const needsFreshBubble =
1764
+ tracks.length === 0 ||
1765
+ tracks.every((track) => track.readyState === "ended");
1766
+ if (!needsFreshBubble) return;
1767
+ bubbleStreamTransferredToRecorder.current = false;
1768
+ bubbleStreamRef.current = null;
1769
+ setBubbleSessionEpoch((epoch) => epoch + 1);
1770
+ }, [popoverVisible, wantsCamera, recordingFlowActive]);
1771
+
1646
1772
  // ---- auto-size popover to content --------------------------------------
1647
1773
  // The Tauri window is fixed-size via tauri.conf.json, but our content
1648
1774
  // height varies (more rows when a camera is on, Recent list toggle, etc.).
@@ -1859,7 +1985,25 @@ export function App() {
1859
1985
  async function handleStartRecording(options?: {
1860
1986
  ignoreActiveRecorder?: boolean;
1861
1987
  }) {
1862
- if (recorder && !options?.ignoreActiveRecorder) return;
1988
+ if (recorder && !options?.ignoreActiveRecorder) {
1989
+ console.warn(
1990
+ "[clips-popover] handleStartRecording ignored — recorder already active",
1991
+ );
1992
+ setRecError(
1993
+ "Still finishing the last recording. Wait a moment, then try again.",
1994
+ );
1995
+ return;
1996
+ }
1997
+ const bubbleTracks = bubbleStreamRef.current?.getTracks() ?? [];
1998
+ const bubbleStreamDead =
1999
+ bubbleTracks.length > 0 &&
2000
+ bubbleTracks.every((track) => track.readyState === "ended");
2001
+ if (bubbleStreamDead) {
2002
+ console.warn("[clips-popover] clearing ended bubble stream before start");
2003
+ bubbleStreamTransferredToRecorder.current = false;
2004
+ bubbleStreamRef.current = null;
2005
+ setBubbleSessionEpoch((epoch) => epoch + 1);
2006
+ }
1863
2007
  if (localRecordingMode === "off") {
1864
2008
  if (videoStorageStatus === "checking") {
1865
2009
  setRecError("Checking video storage. Try again in a moment.");
@@ -2202,11 +2346,28 @@ export function App() {
2202
2346
  };
2203
2347
  track(
2204
2348
  listen("clips:recorder-stop", async () => {
2349
+ // Detach the React Start/bubble gate immediately. Native stop already
2350
+ // released the camera and cleared Rust `is_recording_active` mid-
2351
+ // finalize; keeping `recorder` set through the whole upload made
2352
+ // reopen show a blank preview and made Start a silent no-op.
2353
+ const handle = recorder;
2354
+ bubbleStreamTransferredToRecorder.current = false;
2355
+ bubbleStreamRef.current = null;
2356
+ recordingFlowGateRef.current = false;
2357
+ (window as unknown as { clipsForceAlive?: boolean }).clipsForceAlive =
2358
+ false;
2359
+ setRecordingFlowActive(false);
2360
+ setRecorder(null);
2361
+ // Force a fresh bubble session even when bubbleActive stays true
2362
+ // (popover still open / camera still on). Without this epoch bump the
2363
+ // effect does not re-run and reopen shows ended tracks until Start
2364
+ // discovers them.
2365
+ setBubbleSessionEpoch((epoch) => epoch + 1);
2366
+
2205
2367
  let stopFailed = false;
2206
2368
  let stopResult: RecorderStopResult | null = null;
2207
2369
  try {
2208
- stopResult = await recorder.stop();
2209
- if (cancelled) return;
2370
+ stopResult = await handle.stop();
2210
2371
  if (stopResult.localOnly) {
2211
2372
  setLocalRecordingNotice({
2212
2373
  folderPath: stopResult.localFolder,
@@ -2217,36 +2378,20 @@ export function App() {
2217
2378
  }
2218
2379
  } catch (err) {
2219
2380
  stopFailed = true;
2220
- if (!cancelled) {
2221
- setRecError(err instanceof Error ? err.message : String(err));
2222
- await loadPendingUploads();
2223
- }
2381
+ setRecError(err instanceof Error ? err.message : String(err));
2382
+ await loadPendingUploads();
2224
2383
  } finally {
2225
- if (!cancelled) {
2226
- // Clear the force-alive flag — recording is done, the pump
2227
- // can honor document.hidden normally again.
2228
- (
2229
- window as unknown as { clipsForceAlive?: boolean }
2230
- ).clipsForceAlive = false;
2231
- // Recorder has stopped its tracks; next popover session can
2232
- // acquire the camera cleanly again.
2233
- bubbleStreamTransferredToRecorder.current = false;
2234
- bubbleStreamRef.current = null;
2235
- recordingFlowGateRef.current = false;
2236
- setRecorder(null);
2237
- setRecordingFlowActive(false);
2238
- invoke("set_recording_state", { active: false }).catch(() => {});
2239
- if (stopFailed || stopResult?.localOnly) {
2240
- invoke("show_popover").catch(() => {});
2241
- } else {
2242
- // Close the popover — recorder.stop() already opened the
2243
- // recording's page in the default browser. The popover doesn't
2244
- // need to hang around.
2245
- getCurrentWindow()
2246
- .hide()
2247
- .catch(() => {});
2248
- emit("clips:popover-visible", false).catch(() => {});
2249
- }
2384
+ invoke("set_recording_state", { active: false }).catch(() => {});
2385
+ if (stopFailed || stopResult?.localOnly) {
2386
+ invoke("show_popover").catch(() => {});
2387
+ } else {
2388
+ // Close the popover recorder.stop() already opened the
2389
+ // recording's page in the default browser. The popover doesn't
2390
+ // need to hang around.
2391
+ getCurrentWindow()
2392
+ .hide()
2393
+ .catch(() => {});
2394
+ emit("clips:popover-visible", false).catch(() => {});
2250
2395
  }
2251
2396
  }
2252
2397
  }),
@@ -2265,6 +2410,7 @@ export function App() {
2265
2410
  recordingFlowGateRef.current = false;
2266
2411
  setRecorder(null);
2267
2412
  setRecordingFlowActive(false);
2413
+ setBubbleSessionEpoch((epoch) => epoch + 1);
2268
2414
  invoke("set_recording_state", { active: false }).catch(() => {});
2269
2415
  invoke("show_popover").catch(() => {});
2270
2416
  }
@@ -2285,6 +2431,7 @@ export function App() {
2285
2431
  recordingFlowGateRef.current = false;
2286
2432
  setRecorder(null);
2287
2433
  setRecordingFlowActive(false);
2434
+ setBubbleSessionEpoch((epoch) => epoch + 1);
2288
2435
  invoke("set_recording_state", { active: false }).catch(() => {});
2289
2436
  // Starting a new browser capture must come from a fresh click in
2290
2437
  // this webview. The toolbar click arrives here through async Tauri
@@ -2362,6 +2509,7 @@ export function App() {
2362
2509
  loading={meetingsLoading}
2363
2510
  error={meetingsError}
2364
2511
  startMessage={meetingStartMessage}
2512
+ activeMeetingId={activeMeetingId}
2365
2513
  meetingsEnabled={featureConfig?.meetingsEnabled !== false}
2366
2514
  onBack={() => setPopoverView("recorder")}
2367
2515
  onRefresh={fetchUpcomingMeetings}
@@ -2371,6 +2519,8 @@ export function App() {
2371
2519
  }
2372
2520
  onOpenSettings={() => setPopoverView("settings")}
2373
2521
  onStartNotes={startMeetingNotes}
2522
+ onStartNotesAndJoin={startMeetingNotesAndJoin}
2523
+ onShowActiveMeeting={showActiveMeetingPill}
2374
2524
  />
2375
2525
  </div>
2376
2526
  );
@@ -3269,6 +3419,7 @@ function MeetingsPopoverView({
3269
3419
  loading,
3270
3420
  error,
3271
3421
  startMessage,
3422
+ activeMeetingId,
3272
3423
  meetingsEnabled,
3273
3424
  onBack,
3274
3425
  onRefresh,
@@ -3276,11 +3427,14 @@ function MeetingsPopoverView({
3276
3427
  onOpenMeeting,
3277
3428
  onOpenSettings,
3278
3429
  onStartNotes,
3430
+ onStartNotesAndJoin,
3431
+ onShowActiveMeeting,
3279
3432
  }: {
3280
3433
  meetings: PopoverMeeting[];
3281
3434
  loading: boolean;
3282
3435
  error: string | null;
3283
3436
  startMessage: string | null;
3437
+ activeMeetingId: string | null;
3284
3438
  meetingsEnabled: boolean;
3285
3439
  onBack: () => void;
3286
3440
  onRefresh: () => void;
@@ -3288,6 +3442,8 @@ function MeetingsPopoverView({
3288
3442
  onOpenMeeting: (meetingId: string) => void;
3289
3443
  onOpenSettings: () => void;
3290
3444
  onStartNotes: (meeting: PopoverMeeting) => void;
3445
+ onStartNotesAndJoin: (meeting: PopoverMeeting) => void;
3446
+ onShowActiveMeeting: (meetingId: string) => void;
3291
3447
  }) {
3292
3448
  return (
3293
3449
  <div className="setup popover-view">
@@ -3345,6 +3501,8 @@ function MeetingsPopoverView({
3345
3501
  <div className="popover-list">
3346
3502
  {meetings.map((meeting) => {
3347
3503
  const canStart = meetingCanStartNotes(meeting);
3504
+ const hasJoin = Boolean(meeting.joinUrl);
3505
+ const isActive = activeMeetingId === meeting.id;
3348
3506
  return (
3349
3507
  <div className="popover-list-item" key={meeting.id}>
3350
3508
  <div className="popover-list-icon">
@@ -3357,13 +3515,32 @@ function MeetingsPopoverView({
3357
3515
  {meeting.platform ? ` · ${meeting.platform}` : ""}
3358
3516
  </div>
3359
3517
  </div>
3360
- {canStart ? (
3518
+ {isActive ? (
3519
+ <button
3520
+ type="button"
3521
+ className="popover-list-action popover-list-action-active"
3522
+ onClick={() => onShowActiveMeeting(meeting.id)}
3523
+ title="Meeting notes are recording"
3524
+ >
3525
+ <span className="popover-list-action-dot" aria-hidden />
3526
+ Recording
3527
+ </button>
3528
+ ) : canStart ? (
3361
3529
  <button
3362
3530
  type="button"
3363
3531
  className="popover-list-action popover-list-action-primary"
3364
- onClick={() => onStartNotes(meeting)}
3532
+ onClick={() =>
3533
+ hasJoin
3534
+ ? onStartNotesAndJoin(meeting)
3535
+ : onStartNotes(meeting)
3536
+ }
3537
+ title={
3538
+ hasJoin
3539
+ ? "Start notes and join the meeting"
3540
+ : "Start meeting notes"
3541
+ }
3365
3542
  >
3366
- Start notes
3543
+ {hasJoin ? "Start + join" : "Start notes"}
3367
3544
  </button>
3368
3545
  ) : (
3369
3546
  <button
@@ -245,6 +245,14 @@ export function useMeetingTranscription({
245
245
  const existing = sessionRef.current;
246
246
  if (existing) {
247
247
  if (!existing.stopping && existing.meetingId === meetingId) {
248
+ await invoke("recording_pill_show", {
249
+ meetingId: existing.meetingId,
250
+ mode: "meeting",
251
+ }).catch(() => {});
252
+ emit("clips:pill-context", {
253
+ meetingId: existing.meetingId,
254
+ mode: "meeting",
255
+ }).catch(() => {});
248
256
  emit("meetings:hide-notification", { meetingId }).catch(() => {});
249
257
  return;
250
258
  }
@@ -282,7 +290,13 @@ export function useMeetingTranscription({
282
290
  };
283
291
  sessionRef.current = session;
284
292
  await invoke("set_recording_state", { active: true }).catch(() => {});
285
- await invoke("set_meeting_active", { active: true }).catch(() => {});
293
+ await invoke("set_meeting_active", {
294
+ active: true,
295
+ meetingId: resolvedMeetingId,
296
+ }).catch(() => {});
297
+ emit("meetings:transcription-started", {
298
+ meetingId: resolvedMeetingId,
299
+ }).catch(() => {});
286
300
 
287
301
  const scheduleFlush = () => {
288
302
  if (session.flushTimer) window.clearTimeout(session.flushTimer);
@@ -363,12 +377,19 @@ export function useMeetingTranscription({
363
377
  };
364
378
 
365
379
  // Resume the engine that initial start settled on (no fallback here —
366
- // the engine choice was already made below).
380
+ // the engine choice was already made below). Keep voice processing
381
+ // off: AEC/ducking on the shared mic can make Zoom/Meet callers hear
382
+ // the local user at a whisper while Clips is transcribed.
367
383
  const startAudio = async () => {
368
- await restartTranscriptionEngine(session.engine, {
369
- deviceId: selectedMicId,
370
- label: selectedMicLabel,
371
- });
384
+ await restartTranscriptionEngine(
385
+ session.engine,
386
+ {
387
+ deviceId: selectedMicId,
388
+ label: selectedMicLabel,
389
+ },
390
+ true,
391
+ false,
392
+ );
372
393
  };
373
394
 
374
395
  // Pause/resume state machine — see app.tsx for full explanation.
@@ -538,6 +559,9 @@ export function useMeetingTranscription({
538
559
 
539
560
  session.engine = await startTranscriptionEngine({
540
561
  mic: { deviceId: selectedMicId, label: selectedMicLabel },
562
+ // Match clip recordings: VoiceProcessingIO AEC/ducking on the shared
563
+ // mic can tank live meeting volume for remote participants.
564
+ voiceProcessing: false,
541
565
  });
542
566
 
543
567
  await invoke("silence_detector_start", {