@agent-native/core 0.169.1 → 0.170.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 (459) hide show
  1. package/agent-native.eject.json +4 -1
  2. package/bin/agent-native.js +23 -5
  3. package/corpus/README.md +1 -1
  4. package/corpus/templates/analytics/.agents/skills/secrets/SKILL.md +11 -4
  5. package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +1 -1
  6. package/corpus/templates/analytics/app/i18n-data.ts +28 -0
  7. package/corpus/templates/analytics/app/pages/Agents.tsx +25 -1
  8. package/corpus/templates/analytics/app/routes/$.tsx +10 -0
  9. package/corpus/templates/analytics/app/routes.ts +3 -1
  10. package/corpus/templates/analytics/changelog/2026-08-22-fixed-the-agent-native-templates-first-party-dashboard-panel.md +6 -0
  11. package/corpus/templates/analytics/changelog/2026-08-22-org-admin-panels-no-longer-report-a-database-error-as-a-per.md +9 -0
  12. package/corpus/templates/analytics/changelog/2026-08-22-slack-requests-report-invalid-inputs.md +6 -0
  13. package/corpus/templates/analytics/changelog/2026-08-22-unknown-analytics-links-now-return-a-real-not-found-status.md +6 -0
  14. package/corpus/templates/analytics/docs/schemas/first-party-analytics.md +2 -1
  15. package/corpus/templates/analytics/docs/schemas/tracked-events.md +2 -0
  16. package/corpus/templates/analytics/scripts/emit-netlify-dashboard-report-cron.ts +29 -7
  17. package/corpus/templates/analytics/server/handlers/slack.ts +59 -5
  18. package/corpus/templates/analytics/server/lib/db-admin-connections.ts +11 -6
  19. package/corpus/templates/analytics/server/lib/first-party-analytics.ts +132 -2
  20. package/corpus/templates/analytics/server/lib/slack.ts +4 -2
  21. package/corpus/templates/analytics/vitest.config.ts +6 -1
  22. package/corpus/templates/assets/.agents/skills/secrets/SKILL.md +11 -4
  23. package/corpus/templates/assets/app/routes/library.tsx +5 -3
  24. package/corpus/templates/assets/app/routes.ts +3 -1
  25. package/corpus/templates/assets/changelog/2026-08-22-library-page-loads-again-instead-of-crashing-on-open.md +6 -0
  26. package/corpus/templates/assets/vitest.config.ts +6 -1
  27. package/corpus/templates/brain/.agents/skills/secrets/SKILL.md +11 -4
  28. package/corpus/templates/brain/app/components/ui/pointer-lock.ts +1 -0
  29. package/corpus/templates/brain/app/routes/sources.tsx +8 -3
  30. package/corpus/templates/brain/changelog/2026-08-22-tuning-or-adding-a-source-no-longer-leaves-the-sources-page.md +6 -0
  31. package/corpus/templates/brain/vitest.config.ts +1 -0
  32. package/corpus/templates/calendar/.agents/skills/secrets/SKILL.md +11 -4
  33. package/corpus/templates/calendar/actions/list-booking-links.ts +83 -4
  34. package/corpus/templates/calendar/actions/update-booking-link.ts +4 -3
  35. package/corpus/templates/calendar/app/components/calendar/EventDetailPanel.tsx +11 -3
  36. package/corpus/templates/calendar/app/components/calendar/EventDetailPopover.tsx +1 -1
  37. package/corpus/templates/calendar/app/components/calendar/GoogleConnectBanner.tsx +103 -44
  38. package/corpus/templates/calendar/app/components/calendar/OutOfOfficeEvent.tsx +28 -24
  39. package/corpus/templates/calendar/app/components/layout/AppLayout.tsx +9 -2
  40. package/corpus/templates/calendar/app/components/layout/Sidebar.tsx +47 -58
  41. package/corpus/templates/calendar/app/hooks/use-booking-links.ts +5 -1
  42. package/corpus/templates/calendar/app/lib/event-layout.ts +52 -26
  43. package/corpus/templates/calendar/app/pages/BookingLinksPage.tsx +126 -98
  44. package/corpus/templates/calendar/app/pages/CalendarView.tsx +1 -0
  45. package/corpus/templates/calendar/app/pages/Settings.tsx +88 -81
  46. package/corpus/templates/calendar/app/routes.ts +3 -1
  47. package/corpus/templates/calendar/changelog/2026-08-22-booking-link-visibility-respects-shared-access.md +6 -0
  48. package/corpus/templates/calendar/changelog/2026-08-22-clicking-an-out-of-office-event-s-marker-no-longer-creates-a.md +6 -0
  49. package/corpus/templates/calendar/changelog/2026-08-22-event-detail-views-now-show-your-calendar-timezone.md +6 -0
  50. package/corpus/templates/calendar/changelog/2026-08-22-google-calendar-can-now-connect-with-the-shared-google-oauth.md +6 -0
  51. package/corpus/templates/calendar/changelog/2026-08-22-overlapping-events-now-show-each-others-boundaries.md +6 -0
  52. package/corpus/templates/calendar/changelog/2026-08-22-public-booking-pages-now-offer-time-slots-from-the-host-s-we.md +6 -0
  53. package/corpus/templates/calendar/server/handlers/bookings.ts +5 -7
  54. package/corpus/templates/calendar/server/handlers/google-auth.ts +10 -2
  55. package/corpus/templates/calendar/server/lib/google-calendar.ts +139 -14
  56. package/corpus/templates/calendar/server/onboarding.ts +85 -0
  57. package/corpus/templates/calendar/server/plugins/agent-chat.ts +2 -0
  58. package/corpus/templates/calendar/shared/api.ts +9 -1
  59. package/corpus/templates/chat/.agents/skills/secrets/SKILL.md +11 -4
  60. package/corpus/templates/chat/app/routes.ts +3 -1
  61. package/corpus/templates/chat/vitest.config.ts +8 -0
  62. package/corpus/templates/clips/.agents/skills/secrets/SKILL.md +11 -4
  63. package/corpus/templates/clips/actions/get-meeting.ts +9 -4
  64. package/corpus/templates/clips/actions/list-recordings.ts +16 -3
  65. package/corpus/templates/clips/actions/search-meetings.ts +1 -0
  66. package/corpus/templates/clips/actions/view-screen.ts +8 -1
  67. package/corpus/templates/clips/app/components/meetings/meeting-history-row.tsx +32 -1
  68. package/corpus/templates/clips/app/components/player/delete-recording-menu.tsx +1 -1
  69. package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +29 -1
  70. package/corpus/templates/clips/app/i18n/en-US.ts +5 -0
  71. package/corpus/templates/clips/app/routes/_app.meetings.$meetingId.tsx +33 -4
  72. package/corpus/templates/clips/app/routes/_app.meetings._index.tsx +1 -0
  73. package/corpus/templates/clips/app/routes/access-request.approve.tsx +16 -9
  74. package/corpus/templates/clips/app/routes/embed.$shareId.tsx +17 -7
  75. package/corpus/templates/clips/app/routes/share.$shareId.tsx +17 -7
  76. package/corpus/templates/clips/changelog/2026-08-21-camera-bubble-black-circle.md +6 -0
  77. package/corpus/templates/clips/changelog/2026-08-22-screen-recordings-respect-the-microphone-toggle.md +6 -0
  78. package/corpus/templates/clips/changelog/2026-08-22-the-recordings-library-no-longer-fails-right-after-server-start.md +6 -0
  79. package/corpus/templates/clips/changelog/2026-08-23-the-agent-can-see-your-library-right-after-server-start.md +6 -0
  80. package/corpus/templates/clips/chrome-extension/src/background.ts +1 -2
  81. package/corpus/templates/clips/chrome-extension/src/native-transcription.ts +39 -7
  82. package/corpus/templates/clips/chrome-extension/src/offscreen.ts +21 -25
  83. package/corpus/templates/clips/desktop/src/app.tsx +53 -24
  84. package/corpus/templates/clips/desktop/src/lib/bubble-playback.ts +68 -0
  85. package/corpus/templates/clips/desktop/src/lib/recorder.ts +3 -0
  86. package/corpus/templates/clips/desktop/src/lib/transcription-capture.ts +72 -14
  87. package/corpus/templates/clips/desktop/src/lib/updater.ts +8 -3
  88. package/corpus/templates/clips/desktop/src/overlays/bubble.tsx +162 -20
  89. package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +43 -6
  90. package/corpus/templates/clips/desktop/src-tauri/src/native_screen/custom_capture.rs +150 -13
  91. package/corpus/templates/clips/desktop/src-tauri/src/tray.rs +12 -0
  92. package/corpus/templates/clips/server/lib/calendar-event-meetings.ts +28 -3
  93. package/corpus/templates/clips/server/lib/emails.ts +17 -33
  94. package/corpus/templates/content/.agents/skills/secrets/SKILL.md +11 -4
  95. package/corpus/templates/content/app/components/editor/VisualEditor.tsx +140 -15
  96. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +12 -14
  97. package/corpus/templates/content/app/components/ui/pointer-lock.ts +1 -0
  98. package/corpus/templates/content/app/hooks/use-content-database.ts +18 -2
  99. package/corpus/templates/content/app/hooks/use-local-storage.ts +38 -22
  100. package/corpus/templates/content/app/i18n-data.ts +25 -0
  101. package/corpus/templates/content/app/routes.ts +3 -1
  102. package/corpus/templates/content/changelog/2026-08-22-code-blocks-inserted-from-the-slash-menu-no-longer-get-stuck.md +6 -0
  103. package/corpus/templates/content/changelog/2026-08-22-the-sidebar-page-tree-no-longer-flashes-empty-after-creating-a-page.md +6 -0
  104. package/corpus/templates/content/docs/solutions/2026-08-21-content-mermaid-rendering-shape.md +233 -0
  105. package/corpus/templates/content/server/plugins/agent-chat.ts +9 -2
  106. package/corpus/templates/content/vitest.config.ts +7 -1
  107. package/corpus/templates/crm/.agents/skills/secrets/SKILL.md +11 -4
  108. package/corpus/templates/design/.agents/skills/secrets/SKILL.md +11 -4
  109. package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +1383 -88
  110. package/corpus/templates/design/actions/generate-design.ts +98 -47
  111. package/corpus/templates/design/actions/get-design-system.ts +6 -1
  112. package/corpus/templates/design/actions/refresh-design-system-with-builder.ts +146 -0
  113. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +70 -26
  114. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +284 -136
  115. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +2057 -141
  116. package/corpus/templates/design/app/components/design/editor/DesignBottomToolbar.tsx +6 -2
  117. package/corpus/templates/design/app/components/design/editor/DesignWorkspaceRail.tsx +4 -4
  118. package/corpus/templates/design/app/components/design/keyboard-shortcuts.ts +10 -1
  119. package/corpus/templates/design/app/components/design/multi-screen/alt-hover-measurement.ts +19 -2
  120. package/corpus/templates/design/app/components/design/multi-screen/types.ts +9 -2
  121. package/corpus/templates/design/app/components/layout/Header.tsx +15 -0
  122. package/corpus/templates/design/app/components/layout/Layout.tsx +7 -2
  123. package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +11 -4
  124. package/corpus/templates/design/app/i18n-data.ts +1 -0
  125. package/corpus/templates/design/app/i18n-keyboard-shortcuts.ts +12 -0
  126. package/corpus/templates/design/app/lib/design-system-data.ts +68 -0
  127. package/corpus/templates/design/app/pages/DesignEditor.tsx +77 -35
  128. package/corpus/templates/design/app/pages/DesignSystems.tsx +136 -42
  129. package/corpus/templates/design/app/pages/Index.tsx +2 -0
  130. package/corpus/templates/design/app/pages/Templates.tsx +0 -10
  131. package/corpus/templates/design/app/pages/design-editor/code-layer-state.ts +10 -0
  132. package/corpus/templates/design/app/pages/design-editor/collab-sync.ts +50 -0
  133. package/corpus/templates/design/app/pages/design-editor/commands/apply-design-editor-command.ts +1 -1
  134. package/corpus/templates/design/app/pages/design-editor/commands/apply-file-content-update.ts +10 -8
  135. package/corpus/templates/design/app/pages/design-editor/commands/apply-local-content-update.ts +6 -6
  136. package/corpus/templates/design/app/pages/design-editor/commands/apply-pending-visual-styles-with-agent.ts +1 -1
  137. package/corpus/templates/design/app/pages/design-editor/commands/commit-visual-styles.ts +18 -7
  138. package/corpus/templates/design/app/pages/design-editor/commands/escape-hotkey.ts +4 -90
  139. package/corpus/templates/design/app/pages/design-editor/commands/layer-marquee-selection-change.ts +2 -1
  140. package/corpus/templates/design/app/pages/design-editor/commands/layer-selection-change.ts +4 -3
  141. package/corpus/templates/design/app/pages/design-editor/commands/screen-element-select.ts +12 -2
  142. package/corpus/templates/design/app/pages/design-editor/commands/screen-visual-style-change.ts +9 -2
  143. package/corpus/templates/design/app/pages/design-editor/commands/send-runtime-layer-move-semantic-handoff.ts +1 -1
  144. package/corpus/templates/design/app/pages/design-editor/commands/send-runtime-layer-semantic-handoff.ts +1 -1
  145. package/corpus/templates/design/app/pages/design-editor/commands/send-runtime-layer-state-semantic-handoff.ts +1 -1
  146. package/corpus/templates/design/app/pages/design-editor/commands/start-sidebar-resize.ts +1 -1
  147. package/corpus/templates/design/app/pages/design-editor/editor-state.ts +11 -1
  148. package/corpus/templates/design/app/pages/design-editor/effects/adopt-db-file-content.ts +11 -19
  149. package/corpus/templates/design/app/pages/design-editor/effects/observe-collab-text.ts +6 -6
  150. package/corpus/templates/design/app/pages/design-editor/effects/publish-agent-selection-context.ts +1 -1
  151. package/corpus/templates/design/app/pages/design-editor/effects/seed-collab-content.ts +12 -15
  152. package/corpus/templates/design/app/pages/design-editor/selection-state.ts +5 -59
  153. package/corpus/templates/design/app/pages/design-editor/tool-state.ts +8 -0
  154. package/corpus/templates/design/app/pages/design-editor/types.ts +3 -3
  155. package/corpus/templates/design/app/routes.ts +3 -1
  156. package/corpus/templates/design/changelog/2026-08-20-canvas-edits-patch-the-frame-instead-of-rebuilding-it.md +6 -0
  157. package/corpus/templates/design/changelog/2026-08-21-builder-design-system-imports-reconcile-after-indexing.md +6 -0
  158. package/corpus/templates/design/changelog/2026-08-21-draw-mode-needs-shift-y.md +6 -0
  159. package/corpus/templates/design/changelog/2026-08-21-eyedropper-shortcut.md +6 -0
  160. package/corpus/templates/design/changelog/2026-08-21-figma-style-alignment-guides-and-snapping.md +6 -0
  161. package/corpus/templates/design/changelog/2026-08-21-group-transforms-keep-the-selection.md +6 -0
  162. package/corpus/templates/design/changelog/2026-08-21-inspector-fields-keep-focus-on-enter.md +6 -0
  163. package/corpus/templates/design/changelog/2026-08-21-pen-alt-keeps-the-incoming-handle.md +6 -0
  164. package/corpus/templates/design/changelog/2026-08-21-pen-on-the-board-creates-one-vector.md +6 -0
  165. package/corpus/templates/design/changelog/2026-08-21-scale-a-multi-selection-from-the-group-handles.md +6 -0
  166. package/corpus/templates/design/changelog/2026-08-21-scale-resizes-text-with-the-object.md +6 -0
  167. package/corpus/templates/design/changelog/2026-08-21-selecting-another-object-keeps-the-scale-tool-armed.md +6 -0
  168. package/corpus/templates/design/changelog/2026-08-21-the-shape-tool-remembers-the-shape-you-picked.md +6 -0
  169. package/corpus/templates/design/changelog/2026-08-21-vectors-drawn-in-a-frame-land-where-you-drew-them.md +6 -0
  170. package/corpus/templates/design/changelog/2026-08-22-multi-screen-generation-no-longer-loses-a-saved-screens-layo.md +6 -0
  171. package/corpus/templates/design/changelog/2026-08-22-rename-and-search-fields-are-labeled-for-screen-readers.md +6 -0
  172. package/corpus/templates/design/package.json +2 -0
  173. package/corpus/templates/design/server/lib/builder-design-system-proxy.ts +311 -0
  174. package/corpus/templates/design/shared/canvas-math.ts +612 -206
  175. package/corpus/templates/design/shared/pen-path.ts +37 -0
  176. package/corpus/templates/design/vitest.config.ts +7 -1
  177. package/corpus/templates/dispatch/.agents/skills/secrets/SKILL.md +11 -4
  178. package/corpus/templates/dispatch/actions/list-workspace-connections.ts +34 -3
  179. package/corpus/templates/dispatch/app/routes/integrations.tsx +55 -21
  180. package/corpus/templates/dispatch/app/routes.ts +3 -1
  181. package/corpus/templates/factory/.agents/skills/secrets/SKILL.md +11 -4
  182. package/corpus/templates/factory/.env.example +2 -7
  183. package/corpus/templates/factory/AGENTS.md +3 -0
  184. package/corpus/templates/factory/README.md +5 -3
  185. package/corpus/templates/factory/actions/create-factory.ts +16 -3
  186. package/corpus/templates/factory/actions/get-slack-feedback-context.ts +2 -0
  187. package/corpus/templates/factory/actions/get-triage-item.ts +2 -0
  188. package/corpus/templates/factory/actions/list-factory-audit.ts +116 -36
  189. package/corpus/templates/factory/actions/list-factory-automations.ts +2 -1
  190. package/corpus/templates/factory/actions/list-triage-items.ts +22 -19
  191. package/corpus/templates/factory/actions/run-factory-automation.ts +7 -3
  192. package/corpus/templates/factory/actions/save-factory-automation.ts +5 -2
  193. package/corpus/templates/factory/actions/save-triage-config.ts +2 -8
  194. package/corpus/templates/factory/actions/start-builder-for-item.ts +21 -0
  195. package/corpus/templates/factory/app/components/factory/FactoryAuditView.tsx +229 -297
  196. package/corpus/templates/factory/app/components/factory/FactorySettingsView.tsx +397 -247
  197. package/corpus/templates/factory/app/components/factory/FactorySourceSettingsGroup.tsx +33 -0
  198. package/corpus/templates/factory/app/components/factory/NewFactoryForm.tsx +202 -162
  199. package/corpus/templates/factory/app/i18n/en-US.ts +32 -4
  200. package/corpus/templates/factory/app/routes/factory.tsx +84 -11
  201. package/corpus/templates/factory/app/routes.ts +3 -1
  202. package/corpus/templates/factory/changelog/2026-08-21-activity-runs-use-automation-display-names.md +6 -0
  203. package/corpus/templates/factory/changelog/2026-08-21-create-and-settings-source-cards.md +6 -0
  204. package/corpus/templates/factory/changelog/2026-08-21-keep-automations-visible-while-running.md +6 -0
  205. package/corpus/templates/factory/changelog/2026-08-21-nested-factory-automations-can-poll.md +6 -0
  206. package/corpus/templates/factory/changelog/2026-08-21-settings-sticky-unsaved-bar.md +6 -0
  207. package/corpus/templates/factory/server/connectors/credentials.ts +10 -5
  208. package/corpus/templates/factory/server/lib/factory-audit-report.ts +412 -0
  209. package/corpus/templates/factory/server/lib/factory-config-reconcile.ts +321 -0
  210. package/corpus/templates/factory/server/lib/factory-scope.ts +25 -2
  211. package/corpus/templates/factory/server/lib/require-factory-automation.ts +13 -4
  212. package/corpus/templates/factory/server/plugins/factory-migrations.ts +148 -4
  213. package/corpus/templates/factory/server/plugins/factory-scheduler-job.ts +4 -6
  214. package/corpus/templates/factory/vitest.config.ts +17 -2
  215. package/corpus/templates/forms/.agents/skills/secrets/SKILL.md +11 -4
  216. package/corpus/templates/forms/app/routes/_app.settings.tsx +4 -1
  217. package/corpus/templates/forms/changelog/2026-08-22-the-extensions-link-now-opens-the-extensions-tab-instead-o.md +6 -0
  218. package/corpus/templates/forms/server/lib/public-form-ssr.ts +11 -1
  219. package/corpus/templates/forms/vitest.config.ts +1 -0
  220. package/corpus/templates/macros/.agents/skills/secrets/SKILL.md +11 -4
  221. package/corpus/templates/macros/app/routes.ts +3 -1
  222. package/corpus/templates/macros/vitest.config.ts +6 -1
  223. package/corpus/templates/mail/.agents/skills/secrets/SKILL.md +11 -4
  224. package/corpus/templates/mail/actions/manage-gmail-filters.ts +10 -2
  225. package/corpus/templates/mail/app/components/GoogleConnectBanner.tsx +100 -37
  226. package/corpus/templates/mail/app/components/email/IntegrationsSidebar.tsx +14 -2
  227. package/corpus/templates/mail/app/components/layout/AppLayout.tsx +66 -36
  228. package/corpus/templates/mail/app/hooks/use-google-auth.ts +2 -0
  229. package/corpus/templates/mail/app/lib/google-oauth-setup.ts +17 -0
  230. package/corpus/templates/mail/app/pages/InboxPage.tsx +69 -9
  231. package/corpus/templates/mail/app/routes/$.tsx +9 -0
  232. package/corpus/templates/mail/app/routes/$view.$threadId.tsx +23 -1
  233. package/corpus/templates/mail/app/routes/$view.tsx +47 -1
  234. package/corpus/templates/mail/app/routes.ts +3 -1
  235. package/corpus/templates/mail/changelog/2026-08-22-gmail-can-now-connect-with-the-shared-google-oauth.md +6 -0
  236. package/corpus/templates/mail/changelog/2026-08-22-gmail-filters-now-shows-the-real-error.md +6 -0
  237. package/corpus/templates/mail/changelog/2026-08-22-unknown-mail-urls-now-show-the-404-page.md +6 -0
  238. package/corpus/templates/mail/server/handlers/google-auth.ts +11 -2
  239. package/corpus/templates/mail/server/lib/google-auth.ts +92 -12
  240. package/corpus/templates/mail/server/onboarding.ts +66 -18
  241. package/corpus/templates/mail/vitest.config.ts +6 -1
  242. package/corpus/templates/plan/.agents/skills/secrets/SKILL.md +11 -4
  243. package/corpus/templates/plan/app/routes/settings.tsx +4 -1
  244. package/corpus/templates/plan/app/routes.ts +3 -1
  245. package/corpus/templates/plan/changelog/2026-08-22-the-extensions-link-now-opens-the-extensions-tab-instead-o.md +6 -0
  246. package/corpus/templates/plan/netlify.toml +1 -1
  247. package/corpus/templates/slides/.agents/skills/secrets/SKILL.md +11 -4
  248. package/corpus/templates/slides/actions/patch-deck.ts +79 -10
  249. package/corpus/templates/slides/actions/update-slide.ts +11 -1
  250. package/corpus/templates/slides/app/components/deck/SlideRenderer.tsx +14 -4
  251. package/corpus/templates/slides/app/components/editor/ExportMenu.tsx +10 -52
  252. package/corpus/templates/slides/app/components/editor/GoogleDocImportHint.tsx +8 -53
  253. package/corpus/templates/slides/app/components/editor/GoogleDriveConnectionCta.tsx +9 -75
  254. package/corpus/templates/slides/app/components/editor/GoogleSlidesReferenceImport.tsx +8 -60
  255. package/corpus/templates/slides/app/components/editor/SlideContextToolbar.tsx +10 -2
  256. package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +19 -7
  257. package/corpus/templates/slides/app/lib/sanitize-slide-html.ts +49 -36
  258. package/corpus/templates/slides/app/routes/access-request.approve.tsx +16 -9
  259. package/corpus/templates/slides/app/routes.ts +3 -1
  260. package/corpus/templates/slides/changelog/2026-08-22-already-uploaded-chat-images-are-no-longer-dropped.md +6 -0
  261. package/corpus/templates/slides/changelog/2026-08-22-google-drive-and-slides-can-now-connect-with-the-shared-google-oauth.md +6 -0
  262. package/corpus/templates/slides/changelog/2026-08-22-multi-slide-repairs-now-report-slides-that-still-overflow.md +6 -0
  263. package/corpus/templates/slides/changelog/2026-08-22-update-slide-now-reports-which-batched-edit-was-skipped.md +6 -0
  264. package/corpus/templates/slides/server/handlers/google-docs-auth.ts +52 -1
  265. package/corpus/templates/slides/server/lib/chat-attachments.ts +29 -3
  266. package/corpus/templates/slides/server/lib/google-docs-oauth.ts +66 -16
  267. package/corpus/templates/slides/server/lib/slide-content-patch.ts +13 -2
  268. package/corpus/templates/slides/server/plugins/agent-chat.ts +5 -2
  269. package/corpus/templates/slides/tsconfig.json +5 -0
  270. package/corpus/templates/slides/vitest.config.ts +6 -1
  271. package/corpus/templates/tasks/.agents/skills/secrets/SKILL.md +11 -4
  272. package/corpus/templates/tasks/app/routes/settings.tsx +4 -1
  273. package/corpus/templates/tasks/app/routes.ts +3 -1
  274. package/corpus/templates/tasks/changelog/2026-08-22-the-extensions-link-now-opens-the-extensions-tab-instead-o.md +6 -0
  275. package/corpus/templates/tasks/vitest.config.ts +7 -1
  276. package/dist/action.d.ts +91 -0
  277. package/dist/action.js +50 -0
  278. package/dist/agent/abort-reasons.d.ts +38 -0
  279. package/dist/agent/abort-reasons.js +49 -0
  280. package/dist/agent/engine/ai-sdk-engine.js +8 -5
  281. package/dist/agent/engine/anthropic-engine.js +7 -5
  282. package/dist/agent/engine/first-event-timeout.d.ts +42 -17
  283. package/dist/agent/engine/first-event-timeout.js +67 -25
  284. package/dist/agent/production-agent.d.ts +23 -0
  285. package/dist/agent/production-agent.js +107 -102
  286. package/dist/agent/run-loop-with-resume.d.ts +2 -28
  287. package/dist/agent/run-loop-with-resume.js +25 -40
  288. package/dist/agent/run-manager.js +5 -4
  289. package/dist/agent/run-store.d.ts +55 -0
  290. package/dist/agent/run-store.js +124 -1
  291. package/dist/agent/tool-search.js +2 -1
  292. package/dist/agent/types.d.ts +9 -4
  293. package/dist/app-config/configuration-error.d.ts +11 -0
  294. package/dist/app-config/configuration-error.js +14 -0
  295. package/dist/app-config/index.d.ts +1 -0
  296. package/dist/app-config/index.js +1 -0
  297. package/dist/app-config/integrations.d.ts +1 -0
  298. package/dist/app-config/integrations.js +10 -0
  299. package/dist/app-config/plugins.d.ts +34 -0
  300. package/dist/app-config/plugins.js +39 -0
  301. package/dist/app-config/run-lifecycle-invariants.d.ts +18 -9
  302. package/dist/app-config/run-lifecycle-invariants.js +18 -25
  303. package/dist/app-config/schema.d.ts +16 -0
  304. package/dist/app-config/schema.js +2 -0
  305. package/dist/chat-threads/schema-migrations.js +20 -0
  306. package/dist/chat-threads/store.js +21 -4
  307. package/dist/cli/native-dependencies.d.ts +4 -0
  308. package/dist/cli/native-dependencies.js +15 -0
  309. package/dist/client/EnvironmentBadge.d.ts +1 -1
  310. package/dist/client/EnvironmentBadge.js +40 -5
  311. package/dist/client/MultiTabAssistantChat.d.ts +1 -1
  312. package/dist/client/MultiTabAssistantChat.js +35 -14
  313. package/dist/client/agent-chat/index.d.ts +1 -1
  314. package/dist/client/agent-chat/index.js +1 -1
  315. package/dist/client/agent-page/use-jobs.d.ts +2 -1
  316. package/dist/client/agent-page/use-jobs.js +3 -5
  317. package/dist/client/agent-sidebar-state.js +3 -1
  318. package/dist/client/blocks/library/code-tabs.js +5 -0
  319. package/dist/client/blocks/library/code.js +1 -0
  320. package/dist/client/chat-first/apps-rail.js +2 -2
  321. package/dist/client/chat-model-groups.d.ts +12 -0
  322. package/dist/client/chat-model-groups.js +3 -2
  323. package/dist/client/integrations/GoogleProductLogo.d.ts +5 -0
  324. package/dist/client/integrations/GoogleProductLogo.js +45 -0
  325. package/dist/client/integrations/index.d.ts +2 -0
  326. package/dist/client/integrations/index.js +2 -0
  327. package/dist/client/integrations/workspace-provider-oauth.d.ts +8 -0
  328. package/dist/client/integrations/workspace-provider-oauth.js +13 -0
  329. package/dist/client/resources/mcp-integration-catalog.js +0 -29
  330. package/dist/client/settings/SettingsTabsPage.js +10 -6
  331. package/dist/client/sharing/ShareButton.js +11 -2
  332. package/dist/client/use-chat-models.d.ts +6 -0
  333. package/dist/client/use-chat-models.js +10 -0
  334. package/dist/client/use-db-sync.js +27 -9
  335. package/dist/connections/catalog.d.ts +111 -9
  336. package/dist/connections/catalog.js +86 -30
  337. package/dist/db/create-get-db.js +18 -0
  338. package/dist/db/ddl-guard.d.ts +0 -4
  339. package/dist/db/ddl-guard.js +46 -0
  340. package/dist/deploy/build.d.ts +19 -0
  341. package/dist/deploy/build.js +190 -16
  342. package/dist/deploy/function-bundle.d.ts +45 -0
  343. package/dist/deploy/function-bundle.js +337 -0
  344. package/dist/deploy/workspace-deploy.js +19 -1
  345. package/dist/eject/workspace-connections.js +4 -0
  346. package/dist/email-catalog/registry.d.ts +4 -0
  347. package/dist/email-catalog/registry.js +79 -14
  348. package/dist/extensions/content-patch.js +14 -2
  349. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  350. package/dist/integrations/plugin.d.ts +10 -0
  351. package/dist/integrations/plugin.js +40 -6
  352. package/dist/jobs/actions/run-automation-now.d.ts +2 -1
  353. package/dist/jobs/actions/run-automation-now.js +11 -5
  354. package/dist/jobs/frontmatter.js +53 -2
  355. package/dist/jobs/run-now.d.ts +11 -1
  356. package/dist/jobs/run-now.js +42 -7
  357. package/dist/jobs/scheduler.d.ts +1 -0
  358. package/dist/jobs/scheduler.js +2 -1
  359. package/dist/localization/core-messages/ar-SA.js +3 -0
  360. package/dist/localization/core-messages/de-DE.js +3 -0
  361. package/dist/localization/core-messages/en-US.d.ts +3 -0
  362. package/dist/localization/core-messages/en-US.js +3 -0
  363. package/dist/localization/core-messages/es-ES.js +3 -0
  364. package/dist/localization/core-messages/fr-FR.js +3 -0
  365. package/dist/localization/core-messages/hi-IN.js +3 -0
  366. package/dist/localization/core-messages/ja-JP.js +3 -0
  367. package/dist/localization/core-messages/ko-KR.js +3 -0
  368. package/dist/localization/core-messages/pt-BR.js +3 -0
  369. package/dist/localization/core-messages/zh-CN.js +3 -0
  370. package/dist/localization/core-messages/zh-TW.js +3 -0
  371. package/dist/localization/core-messages.d.ts +3 -0
  372. package/dist/localization/default-messages.d.ts +2 -5
  373. package/dist/localization/default-messages.js +2 -5
  374. package/dist/mcp/build-server.d.ts +9 -0
  375. package/dist/mcp/build-server.js +37 -8
  376. package/dist/mcp-client/oauth-client.d.ts +7 -0
  377. package/dist/mcp-client/oauth-client.js +12 -1
  378. package/dist/oauth-tokens/index.d.ts +1 -1
  379. package/dist/oauth-tokens/index.js +1 -1
  380. package/dist/oauth-tokens/lifecycle.d.ts +11 -0
  381. package/dist/oauth-tokens/lifecycle.js +17 -0
  382. package/dist/oauth-tokens/store.js +7 -0
  383. package/dist/observability/posthog-ai.d.ts +15 -1
  384. package/dist/observability/posthog-ai.js +24 -12
  385. package/dist/observability/routes.d.ts +3 -3
  386. package/dist/observability/traces.js +158 -28
  387. package/dist/onboarding/app-profile.js +2 -2
  388. package/dist/onboarding/plugin.js +10 -2
  389. package/dist/onboarding/types.d.ts +2 -0
  390. package/dist/provider-api/actions/custom-provider-registration.d.ts +1 -1
  391. package/dist/provider-api/actions/provider-api.d.ts +2 -2
  392. package/dist/provider-api/index.js +2 -0
  393. package/dist/resources/store.js +13 -4
  394. package/dist/scripts/agent-engines/list-agent-engines.js +29 -3
  395. package/dist/secrets/register-framework-secrets.js +1 -1
  396. package/dist/server/action-discovery.js +5 -0
  397. package/dist/server/agent-chat/action-filters-a2a.d.ts +27 -3
  398. package/dist/server/agent-chat/action-filters-a2a.js +48 -9
  399. package/dist/server/agent-chat-plugin.js +36 -9
  400. package/dist/server/agent-discovery.js +43 -20
  401. package/dist/server/auth.js +18 -16
  402. package/dist/server/beta-opt-out-html.js +45 -4
  403. package/dist/server/better-auth-instance.d.ts +2 -1
  404. package/dist/server/better-auth-instance.js +23 -7
  405. package/dist/server/builder-design-systems.d.ts +4 -1
  406. package/dist/server/builder-design-systems.js +87 -6
  407. package/dist/server/builder-oauth.d.ts +1 -7
  408. package/dist/server/builder-oauth.js +80 -163
  409. package/dist/server/core-routes-plugin.d.ts +29 -0
  410. package/dist/server/core-routes-plugin.js +100 -20
  411. package/dist/server/default-plugins.d.ts +18 -0
  412. package/dist/server/default-plugins.js +22 -0
  413. package/dist/server/edge.d.ts +1 -0
  414. package/dist/server/edge.js +1 -0
  415. package/dist/server/framework-request-handler.js +31 -3
  416. package/dist/server/google-oauth.d.ts +3 -0
  417. package/dist/server/google-oauth.js +3 -0
  418. package/dist/server/index.d.ts +4 -4
  419. package/dist/server/index.js +3 -3
  420. package/dist/server/onboarding-html.js +37 -3
  421. package/dist/server/realtime-token.d.ts +1 -1
  422. package/dist/server/transcribe-voice.d.ts +1 -1
  423. package/dist/server/workspace-provider-oauth.d.ts +6 -1
  424. package/dist/server/workspace-provider-oauth.js +72 -20
  425. package/dist/shared/agent-sidebar-url.d.ts +1 -0
  426. package/dist/shared/agent-sidebar-url.js +1 -0
  427. package/dist/shared/environment-lanes.d.ts +2 -0
  428. package/dist/shared/environment-lanes.js +3 -1
  429. package/dist/shared/index.d.ts +3 -1
  430. package/dist/shared/index.js +3 -1
  431. package/dist/shared/surface-visibility.d.ts +31 -0
  432. package/dist/shared/surface-visibility.js +57 -0
  433. package/dist/templates/chat/.agents/skills/secrets/SKILL.md +11 -4
  434. package/dist/templates/chat/app/routes.ts +3 -1
  435. package/dist/templates/chat/vitest.config.ts +8 -0
  436. package/dist/templates/default/.agents/skills/secrets/SKILL.md +11 -4
  437. package/dist/templates/default/app/routes.ts +3 -1
  438. package/dist/templates/headless/.agents/skills/secrets/SKILL.md +11 -4
  439. package/dist/templates/workspace-core/.agents/skills/secrets/SKILL.md +11 -4
  440. package/dist/tracking/registry.d.ts +11 -0
  441. package/dist/tracking/registry.js +5 -2
  442. package/dist/triggers/actions.js +10 -3
  443. package/dist/usage/store.js +23 -3
  444. package/dist/user-profile/actions/get-auth-methods.js +18 -5
  445. package/dist/vite/client.js +24 -5
  446. package/docs/content/actions-access-control.mdx +43 -4
  447. package/docs/content/actions-defining.mdx +16 -0
  448. package/docs/content/template-clips-capture-everywhere.mdx +29 -30
  449. package/docs/content/template-clips-developers.mdx +4 -4
  450. package/docs/content/template-clips.mdx +3 -1
  451. package/package.json +2 -2
  452. package/src/eject/workspace-connections.ts +4 -0
  453. package/src/templates/chat/.agents/skills/secrets/SKILL.md +11 -4
  454. package/src/templates/chat/app/routes.ts +3 -1
  455. package/src/templates/chat/vitest.config.ts +8 -0
  456. package/src/templates/default/.agents/skills/secrets/SKILL.md +11 -4
  457. package/src/templates/default/app/routes.ts +3 -1
  458. package/src/templates/headless/.agents/skills/secrets/SKILL.md +11 -4
  459. package/src/templates/workspace-core/.agents/skills/secrets/SKILL.md +11 -4
@@ -506,6 +506,7 @@ export class RecorderEngine {
506
506
  private audioMixSources: MediaStreamAudioSourceNode[] = [];
507
507
  private wakeLock: WakeLockSentinel | null = null;
508
508
  private wakeLockGeneration = 0;
509
+ private wakeLockRetake: (() => void) | null = null;
509
510
  private recorder: MediaRecorder | null = null;
510
511
  private mimeType: string = "video/webm";
511
512
 
@@ -909,7 +910,7 @@ export class RecorderEngine {
909
910
  // during active recording, which ends getDisplayMedia's video track
910
911
  // outright (unlike the mic/camera, display capture requires an
911
912
  // active compositor). Without this, a paused recording left idle
912
- // finalizes early with no warning — see onDisplayTrackEnded below.
913
+ // finalizes early — see onDisplayTrackEnded below.
913
914
  // Best-effort: unsupported browsers or a denied request must never
914
915
  // block capture.
915
916
  void this.acquireWakeLock();
@@ -1010,6 +1011,14 @@ export class RecorderEngine {
1010
1011
  );
1011
1012
  track.addEventListener("ended", () => {
1012
1013
  if (this.state === "recording" || this.state === "paused") {
1014
+ // Paused, the user cannot have clicked "Stop sharing" — the
1015
+ // display slept or locked. Same finalize, but say so instead of
1016
+ // ending as if they had asked for it.
1017
+ if (this.state === "paused") {
1018
+ this.emitWarning(
1019
+ "Screen sharing ended while the recording was paused; saving what was captured so far.",
1020
+ );
1021
+ }
1013
1022
  if (this.opts.onDisplayTrackEnded) {
1014
1023
  this.opts.onDisplayTrackEnded();
1015
1024
  } else {
@@ -2371,7 +2380,22 @@ export class RecorderEngine {
2371
2380
 
2372
2381
  /** Best-effort — unsupported browsers or a denied request must never block capture. */
2373
2382
  private async acquireWakeLock(): Promise<void> {
2383
+ // The platform drops a screen wake lock the moment the document goes
2384
+ // hidden and refuses to grant one while it is hidden, so a single
2385
+ // acquisition only ever protects the foreground. Taking it again on the
2386
+ // way back is the most the page can do.
2387
+ if (!this.wakeLockRetake && typeof document !== "undefined") {
2388
+ const doc = document;
2389
+ this.wakeLockRetake = () => {
2390
+ if (doc.visibilityState === "visible" && this.displayStream) {
2391
+ void this.acquireWakeLock();
2392
+ }
2393
+ };
2394
+ doc.addEventListener("visibilitychange", this.wakeLockRetake);
2395
+ }
2374
2396
  const generation = ++this.wakeLockGeneration;
2397
+ this.wakeLock?.release().catch(() => {});
2398
+ this.wakeLock = null;
2375
2399
  try {
2376
2400
  // coercion-ok: optional chaining yields undefined only when the Wake
2377
2401
  // Lock API itself is absent (older/other browsers) — a real rejection
@@ -2389,6 +2413,10 @@ export class RecorderEngine {
2389
2413
 
2390
2414
  private releaseWakeLock(): void {
2391
2415
  this.wakeLockGeneration += 1;
2416
+ if (this.wakeLockRetake) {
2417
+ document.removeEventListener("visibilitychange", this.wakeLockRetake);
2418
+ this.wakeLockRetake = null;
2419
+ }
2392
2420
  this.wakeLock?.release().catch(() => {});
2393
2421
  this.wakeLock = null;
2394
2422
  }
@@ -351,6 +351,7 @@ const messages = {
351
351
  },
352
352
  meetingDetail: {
353
353
  untitledMeeting: "Untitled meeting",
354
+ recordedBy: "Recorded by {{name}}",
354
355
  unassigned: "Unassigned",
355
356
  them: "Them",
356
357
  me: "Me",
@@ -358,6 +359,10 @@ const messages = {
358
359
  meetingRemoved: "Meeting removed",
359
360
  couldNotRemoveMeeting: "Couldn't remove meeting",
360
361
  couldNotLoadMeeting: "Couldn't load this meeting.",
362
+ retry: "Retry",
363
+ meetingNotFound: "Meeting not found",
364
+ meetingUnavailable: "This meeting isn't available.",
365
+ noAccess: "You may not have access to this meeting.",
361
366
  transcriptCopied: "Transcript copied",
362
367
  couldNotCopyTranscript: "Couldn't copy transcript",
363
368
  allMeetings: "All meetings",
@@ -466,6 +466,7 @@ export default function MeetingDetailRoute() {
466
466
  } | null;
467
467
  recording?: { id: string; durationMs?: number | null } | null;
468
468
  role?: "owner" | "admin" | "editor" | "commenter" | "viewer";
469
+ reason?: "unavailable";
469
470
  };
470
471
 
471
472
  const {
@@ -1018,7 +1019,28 @@ export default function MeetingDetailRoute() {
1018
1019
  finalize,
1019
1020
  ]);
1020
1021
 
1021
- if (isLoading || !meeting) {
1022
+ // Failed, still pending, and loaded-but-absent are three outcomes: the query
1023
+ // never retries, so collapsing any of them into the skeleton pins it forever.
1024
+ // A failed live-poll on top of an already-loaded meeting is none of them —
1025
+ // keep showing the meeting.
1026
+ if (isError && !meeting) {
1027
+ return (
1028
+ <div className="p-6 max-w-2xl mx-auto w-full">
1029
+ <div className="rounded-md border border-destructive/30 bg-destructive/5 px-4 py-3 text-sm text-destructive">
1030
+ {t("meetingDetail.couldNotLoadMeeting")}
1031
+ </div>
1032
+ <Button
1033
+ variant="outline"
1034
+ className="mt-3"
1035
+ onClick={() => refetchMeeting()}
1036
+ >
1037
+ {t("meetingDetail.retry")}
1038
+ </Button>
1039
+ </div>
1040
+ );
1041
+ }
1042
+
1043
+ if (isLoading) {
1022
1044
  return (
1023
1045
  <div className="p-6 max-w-6xl mx-auto w-full">
1024
1046
  <Skeleton className="h-6 w-32 mb-4" />
@@ -1032,12 +1054,19 @@ export default function MeetingDetailRoute() {
1032
1054
  );
1033
1055
  }
1034
1056
 
1035
- if (isError) {
1057
+ if (!meeting) {
1036
1058
  return (
1037
1059
  <div className="p-6 max-w-2xl mx-auto w-full">
1038
- <div className="rounded-md border border-destructive/30 bg-destructive/5 px-4 py-3 text-sm text-destructive">
1039
- {t("meetingDetail.couldNotLoadMeeting")}
1060
+ <div className="rounded-md border px-4 py-3 text-sm text-muted-foreground">
1061
+ {/* Neutral on purpose: `get-meeting` returns one reason for missing
1062
+ and inaccessible so callers cannot probe which ids exist, and
1063
+ saying "not found" here would leak back the distinction the
1064
+ action withholds. */}
1065
+ {t("meetingDetail.meetingUnavailable")}
1040
1066
  </div>
1067
+ <Button asChild variant="outline" className="mt-3">
1068
+ <NavLink to="/meetings">{t("meetingDetail.allMeetings")}</NavLink>
1069
+ </Button>
1041
1070
  </div>
1042
1071
  );
1043
1072
  }
@@ -94,6 +94,7 @@ interface Meeting {
94
94
  userNotesMd?: string | null;
95
95
  source?: "calendar" | "adhoc" | "manual";
96
96
  participants?: AttendeeStackParticipant[];
97
+ ownerEmail?: string | null;
97
98
  }
98
99
 
99
100
  interface SearchMeetingResult extends Meeting {
@@ -43,16 +43,23 @@ export default function ApproveRecordingAccessRequestRoute() {
43
43
  const approvalTokenFromUrl = searchParams.get("token") ?? "";
44
44
  const approvalTokenStorageKey =
45
45
  recordingAccessApprovalSessionKey(recordingId);
46
- const [approvalToken, setApprovalToken] = useState(() => {
47
- if (approvalTokenFromUrl) return approvalTokenFromUrl;
48
- if (typeof window === "undefined" || !recordingId) return "";
46
+ // Only the URL token is knowable on the server, so reading storage in the
47
+ // initializer makes the first client render disagree with the server's and
48
+ // React re-renders the page from scratch. Adopt the stored token after mount.
49
+ const [approvalToken, setApprovalToken] = useState(
50
+ () => approvalTokenFromUrl ?? "",
51
+ );
52
+
53
+ useEffect(() => {
54
+ if (approvalTokenFromUrl || !recordingId) return;
49
55
  try {
50
- return sessionStorage.getItem(approvalTokenStorageKey) ?? "";
51
- } catch {
52
- // coercion-ok: unavailable tab storage is an absent continuation.
53
- return "";
54
- }
55
- });
56
+ const stored = sessionStorage.getItem(approvalTokenStorageKey);
57
+ if (stored) setApprovalToken(stored);
58
+ // Unavailable tab storage is an absent continuation: the page then asks
59
+ // for the token rather than silently continuing without one.
60
+ // coercion-ok: the absent case is visible to the user, not swallowed.
61
+ } catch {}
62
+ }, [approvalTokenFromUrl, recordingId, approvalTokenStorageKey]);
56
63
  const [state, setState] = useState<ApprovalState>({ kind: "loading" });
57
64
 
58
65
  useEffect(() => {
@@ -71,14 +71,24 @@ export default function EmbedRoute() {
71
71
  [searchParams],
72
72
  );
73
73
 
74
- const [password, setPassword] = useState<string | null>(() => {
75
- if (typeof window === "undefined" || !shareId) return null;
74
+ // Same hydration trap the share route had: reading sessionStorage in the
75
+ // initializer makes the first client render disagree with the server's,
76
+ // which has no storage and always renders the locked state. React discards
77
+ // the hydrated tree and re-renders from scratch, so an embedded player goes
78
+ // blank for a returning viewer. Start where the server started and adopt the
79
+ // stored password after mount.
80
+ const [password, setPassword] = useState<string | null>(null);
81
+
82
+ useEffect(() => {
83
+ if (!shareId) return;
76
84
  try {
77
- return sessionStorage.getItem(STORAGE_KEY_PREFIX + shareId);
78
- } catch {
79
- return null;
80
- }
81
- });
85
+ const stored = sessionStorage.getItem(STORAGE_KEY_PREFIX + shareId);
86
+ if (stored) setPassword(stored);
87
+ // Unreadable storage and no stored password are the same state here:
88
+ // both leave `password` null, which renders the password prompt.
89
+ // coercion-ok: the fallback is visible to the viewer, not swallowed.
90
+ } catch {}
91
+ }, [shareId]);
82
92
  const [pwError, setPwError] = useState<string | null>(null);
83
93
  const readyMediaPollRef = useRef<{ key: string; until: number } | null>(null);
84
94
 
@@ -443,14 +443,24 @@ export default function ShareRoute() {
443
443
 
444
444
  const playerRef = useRef<VideoPlayerHandle | null>(null);
445
445
  const readyMediaPollRef = useRef<{ key: string; until: number } | null>(null);
446
- const [password, setPassword] = useState<string | null>(() => {
447
- if (typeof window === "undefined" || !shareId) return null;
446
+ // Reading sessionStorage in the initializer makes the first client render
447
+ // disagree with the server's, which has no storage and always renders the
448
+ // locked state. React answers a mismatch by throwing away the hydrated tree
449
+ // and re-rendering from scratch, so a returning viewer watches a blank share
450
+ // page while everything refetches. Start where the server started and adopt
451
+ // the stored password after mount.
452
+ const [password, setPassword] = useState<string | null>(null);
453
+
454
+ useEffect(() => {
455
+ if (!shareId) return;
448
456
  try {
449
- return sessionStorage.getItem(STORAGE_KEY_PREFIX + shareId);
450
- } catch {
451
- return null;
452
- }
453
- });
457
+ const stored = sessionStorage.getItem(STORAGE_KEY_PREFIX + shareId);
458
+ if (stored) setPassword(stored);
459
+ // Unreadable storage and no stored password are the same state to this
460
+ // screen: both leave `password` null, which renders the password prompt.
461
+ // coercion-ok: the fallback is visible to the viewer, not swallowed.
462
+ } catch {}
463
+ }, [shareId]);
454
464
  const [pwError, setPwError] = useState<string | null>(null);
455
465
  const [currentMs, setCurrentMs] = useState(0);
456
466
  const [commentOpen, setCommentOpen] = useState(false);
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-08-21
4
+ ---
5
+
6
+ The camera bubble now recovers on its own when macOS refuses to start its video, instead of sitting as a black circle until you clicked it.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-08-22
4
+ ---
5
+
6
+ The Chrome extension no longer records tab/system audio when "Include microphone" is turned off.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-08-22
4
+ ---
5
+
6
+ The recordings library no longer returns an error on the first request right after the app starts.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-08-23
4
+ ---
5
+
6
+ Asking the agent what is in your library or shared clips no longer fails on the first request right after the app starts.
@@ -1330,8 +1330,7 @@ async function armRecording(args: {
1330
1330
  sourceAppName: "Chrome",
1331
1331
  sourceWindowTitle: tab.title ?? null,
1332
1332
  hasCamera: cameraInvolved,
1333
- hasAudio:
1334
- settings.includeMicrophone || settings.captureSurface !== "camera",
1333
+ hasAudio: settings.includeMicrophone,
1335
1334
  mimeType: "video/webm",
1336
1335
  requestStreaming: true,
1337
1336
  });
@@ -43,6 +43,7 @@ export interface NativeTranscriptionCapture {
43
43
 
44
44
  const STOP_SETTLE_MS = 1_500;
45
45
  const RESTART_DELAY_MS = 250;
46
+ const MAX_RESTART_ATTEMPTS = 8;
46
47
 
47
48
  function getSpeechRecognitionCtor(): SpeechRecognitionConstructor | null {
48
49
  if (typeof window === "undefined") return null;
@@ -81,20 +82,29 @@ export function createNativeTranscriptionCapture(options?: {
81
82
  let paused = false;
82
83
  let disposed = false;
83
84
  let failureReason = unsupportedReason;
85
+ // Kept apart from `failureReason`: a failed `start()` attempt loses no
86
+ // audio once a later attempt succeeds, whereas `failureReason` records
87
+ // speech that was actually dropped and must survive a recovery.
88
+ let restartStartFailure: string | null = null;
84
89
  let restartTimer: ReturnType<typeof setTimeout> | null = null;
90
+ let restartFailures = 0;
85
91
  let stopPromise: Promise<NativeTranscriptResult> | null = null;
86
92
  let resolveStop: ((result: NativeTranscriptResult) => void) | null = null;
87
93
  let stopTimer: ReturnType<typeof setTimeout> | null = null;
88
94
 
89
95
  const result = (): NativeTranscriptResult => {
90
96
  const text = appendTranscript(finalText, interimText).trim();
97
+ // Captured text does not clear a failure: a capture that died mid-recording
98
+ // still has to be re-transcribed in the cloud, and the reason is the only
99
+ // signal the server has that this transcript is truncated.
91
100
  return {
92
101
  text,
93
102
  failureReason:
94
- text.length > 0
103
+ failureReason ||
104
+ restartStartFailure ||
105
+ (text.length > 0
95
106
  ? null
96
- : failureReason ||
97
- "Chrome Web Speech recognition returned no transcript.",
107
+ : "Chrome Web Speech recognition returned no transcript."),
98
108
  };
99
109
  };
100
110
 
@@ -111,20 +121,34 @@ export function createNativeTranscriptionCapture(options?: {
111
121
  resolve(result());
112
122
  };
113
123
 
114
- const scheduleRestart = (): void => {
124
+ const scheduleRestart = (delayMs: number = RESTART_DELAY_MS): void => {
115
125
  if (restartTimer !== null) return;
116
126
  restartTimer = setTimeout(() => {
117
127
  restartTimer = null;
118
128
  if (disposed || stopped || paused || !recognition) return;
119
129
  try {
120
130
  recognition.start();
131
+ restartFailures = 0;
132
+ // The engine recovered, so a failed start attempt is no longer the
133
+ // transcript's outcome. `failureReason` is deliberately NOT cleared:
134
+ // it records audio that was actually dropped, which a restart cannot
135
+ // recover.
136
+ restartStartFailure = null;
121
137
  } catch (error) {
122
- failureReason =
138
+ restartStartFailure =
123
139
  error instanceof Error
124
140
  ? `Chrome Web Speech recognition could not restart: ${error.message}`
125
141
  : "Chrome Web Speech recognition could not restart.";
142
+ // Nothing started, so no `onend` will arrive to schedule the next try.
143
+ restartFailures += 1;
144
+ if (restartFailures < MAX_RESTART_ATTEMPTS) {
145
+ scheduleRestart(RESTART_DELAY_MS * restartFailures);
146
+ } else {
147
+ // Out of retries: the gap is permanent, so it stops being transient.
148
+ failureReason = failureReason || restartStartFailure;
149
+ }
126
150
  }
127
- }, RESTART_DELAY_MS);
151
+ }, delayMs);
128
152
  };
129
153
 
130
154
  const start = (): void => {
@@ -230,10 +254,18 @@ export function createNativeTranscriptionCapture(options?: {
230
254
  const resume = (): void => {
231
255
  if (!recognition || stopped || disposed) return;
232
256
  paused = false;
257
+ restartFailures = 0;
233
258
  try {
234
259
  recognition.start();
235
260
  } catch {
236
- failureReason = "Chrome Web Speech recognition could not resume.";
261
+ // Chrome throws a transient InvalidStateError if the previous session has
262
+ // not finished tearing down. Nothing started, so no `onend` will arrive to
263
+ // drive the bounded retry loop — schedule it here or transcription stays
264
+ // dead for the rest of the recording. The gap is recorded durably because
265
+ // audio is already live: `paused` is false above.
266
+ failureReason =
267
+ failureReason || "Chrome Web Speech recognition could not resume.";
268
+ scheduleRestart();
237
269
  }
238
270
  };
239
271
 
@@ -25,7 +25,7 @@ import {
25
25
  import { scheduleReadyChime } from "@shared/recording-audio";
26
26
  import {
27
27
  SCREEN_CAPTURE_FRAME_RATE,
28
- screenCaptureVideoConstraints,
28
+ screenCaptureDisplayOptions,
29
29
  type ScreenCaptureSurface,
30
30
  } from "@shared/recording-capture";
31
31
  import {
@@ -327,17 +327,17 @@ async function streamDimensions(
327
327
  };
328
328
  }
329
329
 
330
- function displayConstraints(
330
+ // Gates screen/tab audio on the same "Include microphone" toggle the popup
331
+ // shows for the mic stream — see screenCaptureDisplayOptions for why: mic off
332
+ // is the only signal the user gets to say "capture no audio at all".
333
+ export function displayConstraints(
331
334
  surface: ScreenCaptureSurface,
335
+ wantsMic: boolean,
332
336
  ): MediaStreamConstraints {
333
- return {
334
- video: screenCaptureVideoConstraints(surface),
335
- audio: {
336
- echoCancellation: false,
337
- noiseSuppression: false,
338
- autoGainControl: false,
339
- },
340
- } as MediaStreamConstraints;
337
+ return screenCaptureDisplayOptions(
338
+ surface,
339
+ wantsMic,
340
+ ) as MediaStreamConstraints;
341
341
  }
342
342
 
343
343
  // The user's chosen camera/mic devices (set in the popup, saved to storage).
@@ -1133,7 +1133,7 @@ async function acquire(message: AcquireMessage): Promise<{
1133
1133
  } else {
1134
1134
  // Native "Choose what to share" picker. This is the screenshot Steve showed.
1135
1135
  displayStream = await navigator.mediaDevices.getDisplayMedia(
1136
- displayConstraints(message.surface),
1136
+ displayConstraints(message.surface, message.includeMicrophone),
1137
1137
  );
1138
1138
  if (message.includeMicrophone) {
1139
1139
  const audioLabel = await lookupAudioDeviceLabel(devices.audio);
@@ -1456,20 +1456,16 @@ async function saveNativeTranscript(recording: ActiveRecording): Promise<void> {
1456
1456
  recording.nativeTranscript = captured.text.trim();
1457
1457
  recording.nativeTranscriptFailure = captured.failureReason;
1458
1458
 
1459
- const body = recording.nativeTranscript
1460
- ? {
1461
- recordingId: recording.recordingId,
1462
- fullText: recording.nativeTranscript,
1463
- source: "web-speech",
1464
- }
1465
- : {
1466
- recordingId: recording.recordingId,
1467
- fullText: "",
1468
- source: "web-speech",
1469
- failureReason:
1470
- recording.nativeTranscriptFailure ||
1471
- "Chrome Web Speech recognition returned no transcript.",
1472
- };
1459
+ // A partial capture must carry its reason too — the server treats text
1460
+ // without a reason as a complete transcript and skips the cloud fallback.
1461
+ const body = {
1462
+ recordingId: recording.recordingId,
1463
+ fullText: recording.nativeTranscript,
1464
+ source: "web-speech",
1465
+ ...(recording.nativeTranscriptFailure
1466
+ ? { failureReason: recording.nativeTranscriptFailure }
1467
+ : {}),
1468
+ };
1473
1469
  const headers: Record<string, string> = {
1474
1470
  "Content-Type": "application/json",
1475
1471
  "X-Agent-Native-Frontend": "1",
@@ -404,11 +404,10 @@ const CAM_ON_KEY = "clips:camera-on";
404
404
  const MIC_ON_KEY = "clips:mic-on";
405
405
  const SYSTEM_AUDIO_KEY = "clips:system-audio";
406
406
  const READINESS_REVIEWED_KEY = "clips:readiness-reviewed";
407
- // The tray's rolling buffer, which the docs publish under its internal name.
408
- // Not `#rewind-quick-save`: that section describes pulling a pre-roll from the
409
- // third-party rewind.ai app, which this app does not integrate with at all.
407
+ // The docs section for the tray's rolling buffer, published under the same
408
+ // Rewind name the settings tab uses.
410
409
  const REWIND_DOCS_URL =
411
- "https://www.agent-native.com/docs/template-clips-capture-everywhere#screen-memory";
410
+ "https://www.agent-native.com/docs/template-clips-capture-everywhere#rewind";
412
411
 
413
412
  // Sensible defaults so the user never has to type a URL on first launch.
414
413
  // Dev builds point at the local dev server; production builds point at the
@@ -2697,6 +2696,7 @@ export function App({
2697
2696
  let stopPump: (() => void) | null = null;
2698
2697
  let fellBackToPump = false;
2699
2698
  let stream: MediaStream | null = null;
2699
+ let unlistenUnrendered: (() => void) | null = null;
2700
2700
 
2701
2701
  const startPump = (reason: string) => {
2702
2702
  if (cancelled || stopPump || !stream) return;
@@ -2757,11 +2757,30 @@ export function App({
2757
2757
  webrtcHandle = null;
2758
2758
  startPump(reason);
2759
2759
  };
2760
+ // ICE reaching `connected` proves the transport works, nothing more.
2761
+ // WKWebView can refuse to play the received track (no user gesture in
2762
+ // the bubble page, or its window briefly had no on-screen area), and
2763
+ // that failure is invisible from here — so the bubble reports it and
2764
+ // we fall back to the pump. Without this the safety net below only
2765
+ // ever fired on ICE failure, which is not how this breaks in practice.
2766
+ listen("clips:bubble-webrtc-unrendered", (ev) => {
2767
+ startCanvasFallback(
2768
+ `bubble reported no rendered frames ${JSON.stringify(ev.payload)}`,
2769
+ );
2770
+ })
2771
+ .then((u) => {
2772
+ if (cancelled) {
2773
+ u();
2774
+ return;
2775
+ }
2776
+ unlistenUnrendered = u;
2777
+ })
2778
+ .catch(() => {});
2760
2779
  webrtcHandle = startBubbleWebrtc({
2761
2780
  stream: s,
2762
2781
  onConnected: () => {
2763
2782
  console.log(
2764
- "[clips-popover] bubble WebRTC connected — video is live",
2783
+ "[clips-popover] bubble WebRTC transport connected — waiting for the bubble to confirm playback",
2765
2784
  );
2766
2785
  },
2767
2786
  onFailure: startCanvasFallback,
@@ -2806,6 +2825,10 @@ export function App({
2806
2825
  !!webrtcHandle,
2807
2826
  !!stopPump,
2808
2827
  );
2828
+ if (unlistenUnrendered) {
2829
+ unlistenUnrendered();
2830
+ unlistenUnrendered = null;
2831
+ }
2809
2832
  if (webrtcHandle) {
2810
2833
  webrtcHandle.stop();
2811
2834
  webrtcHandle = null;
@@ -3293,11 +3316,14 @@ export function App({
3293
3316
  // A restart hands off the already-live display stream from the take
3294
3317
  // it's replacing (see `discardForRestart`/`preAcquiredDisplayStream`
3295
3318
  // below) — it must keep recording the same screen, not re-prompt.
3296
- if (source === "full-screen" && !options?.resumeCapture) {
3319
+ if (
3320
+ (source === "full-screen" || source === "region") &&
3321
+ !options?.resumeCapture
3322
+ ) {
3297
3323
  try {
3298
3324
  // Must resolve before `recordingFlowActive` flips the toolbar on
3299
- // below — the toolbar reads the pick to place itself on the
3300
- // chosen screen the first time it's shown.
3325
+ // below — the toolbar and region selector read the pick to place
3326
+ // themselves on the chosen screen the first time they are shown.
3301
3327
  await pickFullscreenRecordingDisplay();
3302
3328
  } catch (err) {
3303
3329
  recordingFlowGateRef.current = false;
@@ -3835,22 +3861,25 @@ export function App({
3835
3861
  const showCameraRow = mode !== "screen"; // screen-only has no camera
3836
3862
  const showSourceRow = mode !== "camera"; // camera-only has no screen source
3837
3863
 
3838
- const pendingUploadBanner = recordingStopFinalizing ? (
3839
- <FinalizingUploadBanner />
3840
- ) : pendingUploads.length > 0 ? (
3841
- <PendingUploadBanner
3842
- uploads={pendingUploads}
3843
- retryingUploadId={retryingUploadId}
3844
- retryingUploadStatus={retryingUploadStatus}
3845
- exportingUploadId={exportingUploadId}
3846
- dismissingUploadId={dismissingUploadId}
3847
- onExport={exportPendingUpload}
3848
- onRetry={retryPendingUpload}
3849
- onDismiss={dismissPendingUpload}
3850
- onOpenFolder={openPendingUploadFolder}
3851
- onConnectStorage={(upload) => openVideoStorageSetup(upload.serverUrl)}
3852
- />
3853
- ) : null;
3864
+ const pendingUploadBanner =
3865
+ authStatus === "authed" ? (
3866
+ recordingStopFinalizing ? (
3867
+ <FinalizingUploadBanner />
3868
+ ) : pendingUploads.length > 0 ? (
3869
+ <PendingUploadBanner
3870
+ uploads={pendingUploads}
3871
+ retryingUploadId={retryingUploadId}
3872
+ retryingUploadStatus={retryingUploadStatus}
3873
+ exportingUploadId={exportingUploadId}
3874
+ dismissingUploadId={dismissingUploadId}
3875
+ onExport={exportPendingUpload}
3876
+ onRetry={retryPendingUpload}
3877
+ onDismiss={dismissPendingUpload}
3878
+ onOpenFolder={openPendingUploadFolder}
3879
+ onConnectStorage={(upload) => openVideoStorageSetup(upload.serverUrl)}
3880
+ />
3881
+ ) : null
3882
+ ) : null;
3854
3883
 
3855
3884
  async function copyRewindAgentPrompt() {
3856
3885
  try {