@agent-native/core 0.103.1 → 0.105.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 (568) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +61 -0
  3. package/corpus/core/package.json +9 -2
  4. package/corpus/core/src/agent/engine/credential-errors.ts +2 -2
  5. package/corpus/core/src/agent/production-agent.ts +30 -0
  6. package/corpus/core/src/agent/run-store.ts +12 -2
  7. package/corpus/core/src/cli/create.ts +1 -0
  8. package/corpus/core/src/cli/skills-content/visual-plan-skill.ts +30 -11
  9. package/corpus/core/src/cli/templates-meta.ts +4 -3
  10. package/corpus/core/src/client/AgentAskPopover.tsx +89 -0
  11. package/corpus/core/src/client/AgentChatHome.tsx +4 -0
  12. package/corpus/core/src/client/AgentPanel.tsx +321 -223
  13. package/corpus/core/src/client/AssistantChat.tsx +6 -10
  14. package/corpus/core/src/client/MultiTabAssistantChat.tsx +53 -372
  15. package/corpus/core/src/client/agent-chat-adapter.ts +13 -1
  16. package/corpus/core/src/client/agent-page/AgentContextTab.tsx +133 -149
  17. package/corpus/core/src/client/agent-page/AgentEmptyState.tsx +44 -0
  18. package/corpus/core/src/client/agent-page/AgentJobsTab.tsx +153 -82
  19. package/corpus/core/src/client/agent-page/AgentTabFrame.tsx +39 -0
  20. package/corpus/core/src/client/agent-page/AgentTabsPage.tsx +368 -356
  21. package/corpus/core/src/client/agent-page/types.ts +1 -1
  22. package/corpus/core/src/client/analytics.ts +51 -5
  23. package/corpus/core/src/client/chat/run-recovery.tsx +12 -4
  24. package/corpus/core/src/client/composer/PromptComposer.tsx +5 -15
  25. package/corpus/core/src/client/composer/TiptapComposer.tsx +32 -3
  26. package/corpus/core/src/client/dynamic-suggestions.ts +3 -3
  27. package/corpus/core/src/client/index.ts +16 -1
  28. package/corpus/core/src/client/resources/ResourceTree.tsx +249 -38
  29. package/corpus/core/src/client/resources/ResourcesPanel.tsx +307 -140
  30. package/corpus/core/src/client/session-replay.ts +158 -5
  31. package/corpus/core/src/client/settings/AutomationsSection.tsx +30 -10
  32. package/corpus/core/src/client/settings/SettingsPanel.tsx +3 -2
  33. package/corpus/core/src/client/settings/SettingsTabsPage.tsx +2 -0
  34. package/corpus/core/src/client/settings/agent-settings-search.ts +2 -2
  35. package/corpus/core/src/client/use-chat-threads.ts +2 -0
  36. package/corpus/core/src/connections/catalog.ts +49 -7
  37. package/corpus/core/src/db/index.ts +6 -1
  38. package/corpus/core/src/deploy/build.ts +23 -0
  39. package/corpus/core/src/extensions/actions.ts +106 -16
  40. package/corpus/core/src/extensions/content-patch.ts +22 -0
  41. package/corpus/core/src/extensions/routes.ts +18 -0
  42. package/corpus/core/src/extensions/store.ts +8 -0
  43. package/corpus/core/src/index.ts +3 -0
  44. package/corpus/core/src/ingestion/docx.ts +158 -0
  45. package/corpus/core/src/ingestion/figma-node-to-html.ts +1860 -0
  46. package/corpus/core/src/ingestion/figma.ts +548 -0
  47. package/corpus/core/src/ingestion/index.ts +107 -0
  48. package/corpus/core/src/ingestion/media.ts +264 -0
  49. package/corpus/core/src/ingestion/notion.ts +121 -0
  50. package/corpus/core/src/ingestion/office.ts +214 -0
  51. package/corpus/core/src/ingestion/orchestration.ts +160 -0
  52. package/corpus/core/src/ingestion/pptx.ts +333 -0
  53. package/corpus/core/src/ingestion/selection.ts +81 -0
  54. package/corpus/core/src/ingestion/website.ts +151 -0
  55. package/corpus/core/src/integrations/plugin.ts +45 -37
  56. package/corpus/core/src/localization/default-messages.ts +35 -12
  57. package/corpus/core/src/observability/hosted-model-experiment.ts +118 -0
  58. package/corpus/core/src/observability/traces.ts +5 -3
  59. package/corpus/core/src/provider-api/index.ts +452 -8
  60. package/corpus/core/src/scripts/agent-engines/list-agent-engines.ts +18 -1
  61. package/corpus/core/src/search-utils/index.ts +112 -0
  62. package/corpus/core/src/secrets/register-framework-secrets.ts +61 -0
  63. package/corpus/core/src/server/action-discovery.ts +33 -8
  64. package/corpus/core/src/server/agent-chat/framework-prompts.ts +2 -2
  65. package/corpus/core/src/server/agent-chat/prompt-resources.ts +144 -0
  66. package/corpus/core/src/server/agent-chat-plugin.ts +6 -0
  67. package/corpus/core/src/server/core-routes-plugin.ts +12 -0
  68. package/corpus/core/src/server/index.ts +30 -0
  69. package/corpus/core/src/server/workspace-provider-oauth.ts +583 -0
  70. package/corpus/core/src/styles/agent-native.css +9 -0
  71. package/corpus/core/src/templates/default/app/i18n/en-US.ts +3 -3
  72. package/corpus/core/src/templates/workspace-core/.agents/skills/extensions/SKILL.md +14 -5
  73. package/corpus/core/src/templates/workspace-root/.env.example +12 -0
  74. package/corpus/core/src/workspace-connections/index.ts +6 -0
  75. package/corpus/core/src/workspace-connections/lifecycle.ts +43 -0
  76. package/corpus/core/src/workspace-connections/store.ts +16 -0
  77. package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +46 -3
  78. package/corpus/templates/analytics/AGENTS.md +9 -0
  79. package/corpus/templates/analytics/actions/dashboard-mutation-api.ts +120 -6
  80. package/corpus/templates/analytics/actions/mutate-dashboard.ts +92 -30
  81. package/corpus/templates/analytics/actions/update-dashboard.ts +5 -5
  82. package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +313 -220
  83. package/corpus/templates/analytics/app/components/layout/CommandPalette.tsx +2 -2
  84. package/corpus/templates/analytics/app/components/layout/Layout.tsx +9 -6
  85. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +90 -64
  86. package/corpus/templates/analytics/app/i18n-data.ts +3 -3
  87. package/corpus/templates/analytics/app/lib/dashboard-list-loading.ts +25 -0
  88. package/corpus/templates/analytics/app/lib/item-popularity.ts +13 -4
  89. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/DashboardFilterBar.tsx +1 -1
  90. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/pivot.ts +8 -3
  91. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/types.ts +1 -0
  92. package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +15 -3
  93. package/corpus/templates/analytics/changelog/2026-07-16-dashboard-filter-defaults-can-now-be-changed-reliably-withou.md +6 -0
  94. package/corpus/templates/analytics/changelog/2026-07-16-dashboard-lists-load-in-one-stable-order-without-popping-bet.md +6 -0
  95. package/corpus/templates/analytics/changelog/2026-07-16-fixed-dashboard-filter-dropdown-text-alignment.md +6 -0
  96. package/corpus/templates/analytics/changelog/2026-07-16-recurring-signed-in-users-can-now-be-viewed-as-weekly-bars-b.md +6 -0
  97. package/corpus/templates/analytics/changelog/2026-07-16-the-analytics-agent-can-now-duplicate-a-chart-and-place-the-.md +6 -0
  98. package/corpus/templates/analytics/seeds/dashboards/agent-native-templates-first-party.json +41 -1
  99. package/corpus/templates/analytics/server/lib/dashboard-catalog.ts +1 -1
  100. package/corpus/templates/analytics/server/lib/first-party-metric-catalog.ts +47 -1
  101. package/corpus/templates/analytics/server/lib/session-replay.ts +68 -0
  102. package/corpus/templates/analytics/server/plugins/agent-chat.ts +1 -0
  103. package/corpus/templates/analytics/server/routes/sessions/lookup.get.ts +47 -0
  104. package/corpus/templates/assets/.agents/skills/asset-generation/SKILL.md +16 -9
  105. package/corpus/templates/assets/.agents/skills/creative-context/SKILL.md +86 -0
  106. package/corpus/templates/assets/AGENTS.md +10 -0
  107. package/corpus/templates/assets/actions/create-generation-session.ts +59 -1
  108. package/corpus/templates/assets/actions/edit-image.ts +2 -0
  109. package/corpus/templates/assets/actions/generate-asset.ts +52 -0
  110. package/corpus/templates/assets/actions/generate-image-batch.ts +55 -0
  111. package/corpus/templates/assets/actions/generate-image.ts +219 -1
  112. package/corpus/templates/assets/actions/open-asset-picker.ts +14 -0
  113. package/corpus/templates/assets/actions/refine-image.ts +3 -0
  114. package/corpus/templates/assets/actions/restyle-image.ts +2 -0
  115. package/corpus/templates/assets/agent-native.app-skill.json +4 -0
  116. package/corpus/templates/assets/app/components/layout/Layout.tsx +2 -0
  117. package/corpus/templates/assets/app/i18n/zh-TW.ts +3 -0
  118. package/corpus/templates/assets/app/i18n-data.ts +29 -13
  119. package/corpus/templates/assets/app/routes/agent.tsx +7 -1
  120. package/corpus/templates/assets/app/routes/library.tsx +9 -0
  121. package/corpus/templates/assets/app/routes/settings.tsx +3 -0
  122. package/corpus/templates/assets/changelog/2026-07-16-creative-context-library.md +6 -0
  123. package/corpus/templates/assets/package.json +1 -0
  124. package/corpus/templates/assets/server/lib/image-processing.ts +1 -22
  125. package/corpus/templates/assets/server/plugins/creative-context.ts +205 -0
  126. package/corpus/templates/brain/app/i18n-data.ts +3 -3
  127. package/corpus/templates/brain/app/lib/brain.ts +1 -1
  128. package/corpus/templates/brain/server/lib/search.ts +17 -67
  129. package/corpus/templates/calendar/app/i18n-data.ts +3 -3
  130. package/corpus/templates/calendar/app/pages/BookingLinksPage.tsx +19 -18
  131. package/corpus/templates/chat/app/i18n/en-US.ts +3 -3
  132. package/corpus/templates/chat/app/lib/agent-page.tsx +10 -1
  133. package/corpus/templates/clips/.agents/skills/meetings/SKILL.md +1 -1
  134. package/corpus/templates/clips/AGENTS.md +4 -0
  135. package/corpus/templates/clips/actions/cleanup-transcript.ts +35 -4
  136. package/corpus/templates/clips/actions/create-meeting.ts +6 -2
  137. package/corpus/templates/clips/actions/create-organization.ts +3 -2
  138. package/corpus/templates/clips/actions/create-recording.ts +4 -1
  139. package/corpus/templates/clips/actions/finalize-recording.ts +44 -7
  140. package/corpus/templates/clips/actions/import-loom-recording.ts +4 -1
  141. package/corpus/templates/clips/actions/lib/create-recording-schema.ts +2 -2
  142. package/corpus/templates/clips/actions/list-meetings.ts +23 -5
  143. package/corpus/templates/clips/actions/list-organization-state.ts +1 -1
  144. package/corpus/templates/clips/actions/remove-silences.ts +10 -1
  145. package/corpus/templates/clips/actions/request-transcript.ts +53 -11
  146. package/corpus/templates/clips/actions/search-recordings-utils.ts +7 -0
  147. package/corpus/templates/clips/actions/search-recordings.ts +5 -8
  148. package/corpus/templates/clips/actions/set-organization-branding.ts +2 -2
  149. package/corpus/templates/clips/actions/stitch-recordings.ts +10 -5
  150. package/corpus/templates/clips/actions/update-ai-request-status.ts +38 -0
  151. package/corpus/templates/clips/app/components/editor/editor-layout.tsx +3 -4
  152. package/corpus/templates/clips/app/components/editor/editor-selection.ts +19 -0
  153. package/corpus/templates/clips/app/components/editor/stitch-manager.tsx +10 -10
  154. package/corpus/templates/clips/app/components/library/bulk-action-toolbar.tsx +1 -2
  155. package/corpus/templates/clips/app/components/library/library-grid.tsx +101 -93
  156. package/corpus/templates/clips/app/components/player/video-player.tsx +11 -0
  157. package/corpus/templates/clips/app/components/workspace/branding-editor.tsx +53 -1
  158. package/corpus/templates/clips/app/i18n/ar-SA.ts +7 -1
  159. package/corpus/templates/clips/app/i18n/de-DE.ts +7 -1
  160. package/corpus/templates/clips/app/i18n/en-US.ts +10 -4
  161. package/corpus/templates/clips/app/i18n/es-ES.ts +7 -1
  162. package/corpus/templates/clips/app/i18n/fr-FR.ts +7 -1
  163. package/corpus/templates/clips/app/i18n/hi-IN.ts +7 -1
  164. package/corpus/templates/clips/app/i18n/ja-JP.ts +7 -1
  165. package/corpus/templates/clips/app/i18n/ko-KR.ts +7 -1
  166. package/corpus/templates/clips/app/i18n/pt-BR.ts +7 -1
  167. package/corpus/templates/clips/app/i18n/zh-CN.ts +6 -1
  168. package/corpus/templates/clips/app/i18n/zh-TW.ts +6 -1
  169. package/corpus/templates/clips/app/routes/_app.settings._index.tsx +5 -9
  170. package/corpus/templates/clips/app/routes/_app.settings.organization.tsx +6 -2
  171. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +129 -27
  172. package/corpus/templates/clips/app/routes/record.tsx +23 -2
  173. package/corpus/templates/clips/app/routes/share.$shareId.tsx +6 -2
  174. package/corpus/templates/clips/app/routes.ts +3 -1
  175. package/corpus/templates/clips/changelog/2026-07-16-authorized-viewers-can-open-shared-private-clips-without-a-m.md +6 -0
  176. package/corpus/templates/clips/changelog/2026-07-16-camera-bubble-hover-controls-appear-above-the-face.md +6 -0
  177. package/corpus/templates/clips/changelog/2026-07-16-chrome-extension-recovers-stale-recorder-state.md +6 -0
  178. package/corpus/templates/clips/changelog/2026-07-16-clips-agent-chat-no-longer-shows-a-separate-workspace-header.md +6 -0
  179. package/corpus/templates/clips/changelog/2026-07-16-clips-search-now-matches-recording-content-without-requiring.md +6 -0
  180. package/corpus/templates/clips/changelog/2026-07-16-declined-meetings-no-longer-show-desktop-reminders.md +6 -0
  181. package/corpus/templates/clips/changelog/2026-07-16-failed-desktop-saves-now-show-their-local-recovery-copy.md +6 -0
  182. package/corpus/templates/clips/changelog/2026-07-16-long-desktop-clips-now-preserve-complete-playback-synced-aud.md +6 -0
  183. package/corpus/templates/clips/changelog/2026-07-16-long-recording-lists-keep-stitch-and-library-actions-visible.md +6 -0
  184. package/corpus/templates/clips/changelog/2026-07-16-organization-admins-can-choose-new-recording-visibility.md +6 -0
  185. package/corpus/templates/clips/changelog/2026-07-16-remove-silences-now-shows-queued-active-completed-and-failed.md +6 -0
  186. package/corpus/templates/clips/changelog/2026-07-16-settings-no-longer-repeats-the-builder-connection-status-in-.md +6 -0
  187. package/corpus/templates/clips/changelog/2026-07-16-transcripts-now-appear-from-native-browser-speech-sooner-wit.md +6 -0
  188. package/corpus/templates/clips/chrome-extension/public/manifest.json +1 -1
  189. package/corpus/templates/clips/chrome-extension/src/background.ts +73 -1
  190. package/corpus/templates/clips/chrome-extension/src/native-recording-state.ts +32 -0
  191. package/corpus/templates/clips/chrome-extension/src/native-transcription.ts +248 -0
  192. package/corpus/templates/clips/chrome-extension/src/offscreen.ts +106 -0
  193. package/corpus/templates/clips/desktop/src/app.tsx +66 -28
  194. package/corpus/templates/clips/desktop/src/lib/recorder.ts +335 -285
  195. package/corpus/templates/clips/desktop/src/lib/single-flight.ts +7 -0
  196. package/corpus/templates/clips/desktop/src/lib/upload-verification.ts +51 -0
  197. package/corpus/templates/clips/desktop/src/overlays/bubble.tsx +2 -2
  198. package/corpus/templates/clips/desktop/src/overlays/finalizing.tsx +10 -2
  199. package/corpus/templates/clips/desktop/src/styles.css +13 -11
  200. package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +8 -9
  201. package/corpus/templates/clips/desktop/src-tauri/src/meetings_watcher.rs +1 -0
  202. package/corpus/templates/clips/desktop/src-tauri/src/native_screen/custom_capture.rs +88 -13
  203. package/corpus/templates/clips/desktop/src-tauri/src/native_screen/live_upload.rs +13 -2
  204. package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +241 -6
  205. package/corpus/templates/clips/server/db/schema.ts +2 -2
  206. package/corpus/templates/clips/server/lib/builder-media-compression.ts +64 -67
  207. package/corpus/templates/clips/server/lib/calendar-event-classification.ts +19 -0
  208. package/corpus/templates/clips/server/lib/google-calendar-client.ts +1 -0
  209. package/corpus/templates/clips/server/lib/recordings.ts +40 -1
  210. package/corpus/templates/clips/server/plugins/agent-chat.ts +1 -0
  211. package/corpus/templates/clips/server/plugins/db.ts +2 -2
  212. package/corpus/templates/clips/server/routes/api/auth/google-calendar.get.ts +1 -1
  213. package/corpus/templates/clips/server/routes/api/public-recording.get.ts +14 -5
  214. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/chunk.post.ts +51 -1
  215. package/corpus/templates/clips/server/routes/api/video/[recordingId].get.ts +1 -64
  216. package/corpus/templates/clips/shared/media-worker-contract.ts +32 -15
  217. package/corpus/templates/content/.agents/skills/content/SKILL.md +16 -0
  218. package/corpus/templates/content/.agents/skills/creative-context/SKILL.md +85 -0
  219. package/corpus/templates/content/.agents/skills/notion-integration/SKILL.md +8 -0
  220. package/corpus/templates/content/AGENTS.md +9 -0
  221. package/corpus/templates/content/actions/create-document.ts +94 -0
  222. package/corpus/templates/content/actions/edit-document.ts +144 -4
  223. package/corpus/templates/content/actions/update-document.ts +138 -0
  224. package/corpus/templates/content/agent-native.app-skill.json +4 -0
  225. package/corpus/templates/content/app/components/layout/Layout.tsx +2 -0
  226. package/corpus/templates/content/app/i18n/zh-TW.ts +3 -0
  227. package/corpus/templates/content/app/i18n-data.ts +13 -4
  228. package/corpus/templates/content/app/routes/_app.agent.tsx +2 -1
  229. package/corpus/templates/content/app/routes/_app.settings.tsx +3 -0
  230. package/corpus/templates/content/changelog/2026-07-16-creative-context-library.md +6 -0
  231. package/corpus/templates/content/package.json +1 -0
  232. package/corpus/templates/content/server/plugins/creative-context.ts +31 -0
  233. package/corpus/templates/design/.agents/skills/creative-context/SKILL.md +116 -0
  234. package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +16 -0
  235. package/corpus/templates/design/.agents/skills/design-systems/SKILL.md +8 -0
  236. package/corpus/templates/design/AGENTS.md +6 -0
  237. package/corpus/templates/design/actions/clone-creative-context-design.ts +176 -0
  238. package/corpus/templates/design/actions/edit-design.ts +128 -0
  239. package/corpus/templates/design/actions/generate-design.ts +278 -14
  240. package/corpus/templates/design/actions/generate-screens.ts +42 -1
  241. package/corpus/templates/design/agent-native.app-skill.json +4 -0
  242. package/corpus/templates/design/app/components/layout/Layout.tsx +7 -3
  243. package/corpus/templates/design/app/i18n/zh-TW.ts +3 -0
  244. package/corpus/templates/design/app/i18n-data.ts +10 -4
  245. package/corpus/templates/design/app/routes/agent.tsx +2 -1
  246. package/corpus/templates/design/app/routes/settings.tsx +3 -0
  247. package/corpus/templates/design/changelog/2026-07-16-creative-context-library.md +6 -0
  248. package/corpus/templates/design/changelog/2026-07-16-design-agent-chat-no-longer-shows-a-separate-workspace-header.md +6 -0
  249. package/corpus/templates/design/package.json +1 -0
  250. package/corpus/templates/design/server/lib/figma-design-context.ts +5 -335
  251. package/corpus/templates/design/server/lib/figma-node-to-html.ts +1 -1859
  252. package/corpus/templates/design/server/lib/import-design-files.ts +6 -8
  253. package/corpus/templates/design/server/plugins/creative-context.ts +31 -0
  254. package/corpus/templates/design/shared/generation-session.ts +7 -0
  255. package/corpus/templates/dispatch/app/i18n-data.ts +3 -3
  256. package/corpus/templates/forms/app/i18n/en-US.ts +3 -3
  257. package/corpus/templates/macros/app/i18n/en-US.ts +3 -3
  258. package/corpus/templates/mail/app/components/email/EmailThread.tsx +35 -5
  259. package/corpus/templates/mail/app/i18n/en-US.ts +3 -3
  260. package/corpus/templates/mail/changelog/2026-07-16-mail-previews-now-expand-to-show-the-full-message-without-an.md +6 -0
  261. package/corpus/templates/plan/.agents/skills/visual-plan/SKILL.md +30 -11
  262. package/corpus/templates/plan/AGENTS.md +21 -1
  263. package/corpus/templates/plan/actions/get-visual-plan.ts +1 -1
  264. package/corpus/templates/plan/actions/patch-visual-plan-source.ts +161 -0
  265. package/corpus/templates/plan/actions/read-visual-plan-source.ts +1 -1
  266. package/corpus/templates/plan/actions/update-visual-plan.ts +126 -10
  267. package/corpus/templates/plan/app/hooks/use-plans.ts +2 -0
  268. package/corpus/templates/plan/app/i18n/en-US.ts +3 -3
  269. package/corpus/templates/plan/app/pages/PlansPage.tsx +65 -62
  270. package/corpus/templates/plan/changelog/2026-07-16-local-plan-previews-now-load-annotations-containing-html-lik.md +6 -0
  271. package/corpus/templates/plan/changelog/2026-07-16-plan-agents-now-prevent-stale-edits-from-overwriting-newer-p.md +6 -0
  272. package/corpus/templates/plan/server/plan-mdx.ts +75 -2
  273. package/corpus/templates/slides/.agents/skills/create-deck/SKILL.md +21 -4
  274. package/corpus/templates/slides/.agents/skills/creative-context/SKILL.md +122 -0
  275. package/corpus/templates/slides/.agents/skills/design-systems/SKILL.md +11 -0
  276. package/corpus/templates/slides/.agents/skills/slide-editing/SKILL.md +12 -3
  277. package/corpus/templates/slides/AGENTS.md +6 -0
  278. package/corpus/templates/slides/actions/add-slide.ts +230 -14
  279. package/corpus/templates/slides/actions/clone-context-slide.ts +302 -0
  280. package/corpus/templates/slides/actions/create-deck.ts +130 -0
  281. package/corpus/templates/slides/actions/extract-pdf.ts +6 -2
  282. package/corpus/templates/slides/actions/import-file.ts +5 -4
  283. package/corpus/templates/slides/actions/patch-deck.ts +200 -10
  284. package/corpus/templates/slides/actions/update-slide.ts +208 -15
  285. package/corpus/templates/slides/app/components/layout/Layout.tsx +2 -0
  286. package/corpus/templates/slides/app/components/visual-editor/CanvasCommentPins.tsx +16 -1
  287. package/corpus/templates/slides/app/i18n/ar-SA.ts +3 -0
  288. package/corpus/templates/slides/app/i18n/de-DE.ts +3 -0
  289. package/corpus/templates/slides/app/i18n/en-US.ts +6 -3
  290. package/corpus/templates/slides/app/i18n/es-ES.ts +3 -0
  291. package/corpus/templates/slides/app/i18n/fr-FR.ts +3 -0
  292. package/corpus/templates/slides/app/i18n/hi-IN.ts +3 -0
  293. package/corpus/templates/slides/app/i18n/ja-JP.ts +3 -0
  294. package/corpus/templates/slides/app/i18n/ko-KR.ts +3 -0
  295. package/corpus/templates/slides/app/i18n/pt-BR.ts +3 -0
  296. package/corpus/templates/slides/app/i18n/zh-CN.ts +3 -0
  297. package/corpus/templates/slides/app/i18n/zh-TW.ts +3 -0
  298. package/corpus/templates/slides/app/lib/validate-native-slide-html.ts +176 -0
  299. package/corpus/templates/slides/app/routes/agent.tsx +7 -1
  300. package/corpus/templates/slides/app/routes/settings.tsx +3 -0
  301. package/corpus/templates/slides/changelog/2026-07-16-creative-context-library.md +6 -0
  302. package/corpus/templates/slides/changelog/2026-07-16-google-slides-native-cloning.md +6 -0
  303. package/corpus/templates/slides/package.json +1 -0
  304. package/corpus/templates/slides/server/handlers/import/docx-parser.ts +4 -85
  305. package/corpus/templates/slides/server/handlers/import/pptx-parser.ts +7 -421
  306. package/corpus/templates/slides/server/plugins/creative-context.ts +166 -0
  307. package/dist/agent/engine/credential-errors.d.ts +1 -1
  308. package/dist/agent/engine/credential-errors.d.ts.map +1 -1
  309. package/dist/agent/engine/credential-errors.js +2 -2
  310. package/dist/agent/engine/credential-errors.js.map +1 -1
  311. package/dist/agent/production-agent.d.ts.map +1 -1
  312. package/dist/agent/production-agent.js +25 -0
  313. package/dist/agent/production-agent.js.map +1 -1
  314. package/dist/agent/run-store.d.ts.map +1 -1
  315. package/dist/agent/run-store.js +12 -2
  316. package/dist/agent/run-store.js.map +1 -1
  317. package/dist/cli/create.d.ts.map +1 -1
  318. package/dist/cli/create.js +1 -0
  319. package/dist/cli/create.js.map +1 -1
  320. package/dist/cli/skills-content/visual-plan-skill.d.ts +1 -1
  321. package/dist/cli/skills-content/visual-plan-skill.d.ts.map +1 -1
  322. package/dist/cli/skills-content/visual-plan-skill.js +30 -11
  323. package/dist/cli/skills-content/visual-plan-skill.js.map +1 -1
  324. package/dist/cli/templates-meta.d.ts.map +1 -1
  325. package/dist/cli/templates-meta.js +4 -3
  326. package/dist/cli/templates-meta.js.map +1 -1
  327. package/dist/client/AgentAskPopover.d.ts +11 -0
  328. package/dist/client/AgentAskPopover.d.ts.map +1 -0
  329. package/dist/client/AgentAskPopover.js +30 -0
  330. package/dist/client/AgentAskPopover.js.map +1 -0
  331. package/dist/client/AgentChatHome.d.ts +1 -1
  332. package/dist/client/AgentChatHome.d.ts.map +1 -1
  333. package/dist/client/AgentChatHome.js +2 -2
  334. package/dist/client/AgentChatHome.js.map +1 -1
  335. package/dist/client/AgentPanel.d.ts +9 -19
  336. package/dist/client/AgentPanel.d.ts.map +1 -1
  337. package/dist/client/AgentPanel.js +119 -80
  338. package/dist/client/AgentPanel.js.map +1 -1
  339. package/dist/client/AssistantChat.d.ts.map +1 -1
  340. package/dist/client/AssistantChat.js +4 -4
  341. package/dist/client/AssistantChat.js.map +1 -1
  342. package/dist/client/MultiTabAssistantChat.d.ts +3 -9
  343. package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
  344. package/dist/client/MultiTabAssistantChat.js +49 -189
  345. package/dist/client/MultiTabAssistantChat.js.map +1 -1
  346. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  347. package/dist/client/agent-chat-adapter.js +12 -1
  348. package/dist/client/agent-chat-adapter.js.map +1 -1
  349. package/dist/client/agent-page/AgentContextTab.d.ts.map +1 -1
  350. package/dist/client/agent-page/AgentContextTab.js +26 -28
  351. package/dist/client/agent-page/AgentContextTab.js.map +1 -1
  352. package/dist/client/agent-page/AgentEmptyState.d.ts +13 -0
  353. package/dist/client/agent-page/AgentEmptyState.d.ts.map +1 -0
  354. package/dist/client/agent-page/AgentEmptyState.js +6 -0
  355. package/dist/client/agent-page/AgentEmptyState.js.map +1 -0
  356. package/dist/client/agent-page/AgentJobsTab.d.ts +1 -1
  357. package/dist/client/agent-page/AgentJobsTab.d.ts.map +1 -1
  358. package/dist/client/agent-page/AgentJobsTab.js +90 -58
  359. package/dist/client/agent-page/AgentJobsTab.js.map +1 -1
  360. package/dist/client/agent-page/AgentTabFrame.d.ts +12 -0
  361. package/dist/client/agent-page/AgentTabFrame.d.ts.map +1 -0
  362. package/dist/client/agent-page/AgentTabFrame.js +7 -0
  363. package/dist/client/agent-page/AgentTabFrame.js.map +1 -0
  364. package/dist/client/agent-page/AgentTabsPage.d.ts +9 -1
  365. package/dist/client/agent-page/AgentTabsPage.d.ts.map +1 -1
  366. package/dist/client/agent-page/AgentTabsPage.js +135 -99
  367. package/dist/client/agent-page/AgentTabsPage.js.map +1 -1
  368. package/dist/client/agent-page/types.d.ts +1 -1
  369. package/dist/client/agent-page/types.d.ts.map +1 -1
  370. package/dist/client/agent-page/types.js.map +1 -1
  371. package/dist/client/analytics.d.ts +10 -3
  372. package/dist/client/analytics.d.ts.map +1 -1
  373. package/dist/client/analytics.js +37 -2
  374. package/dist/client/analytics.js.map +1 -1
  375. package/dist/client/chat/run-recovery.d.ts.map +1 -1
  376. package/dist/client/chat/run-recovery.js +10 -3
  377. package/dist/client/chat/run-recovery.js.map +1 -1
  378. package/dist/client/composer/PromptComposer.d.ts.map +1 -1
  379. package/dist/client/composer/PromptComposer.js +2 -2
  380. package/dist/client/composer/PromptComposer.js.map +1 -1
  381. package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
  382. package/dist/client/composer/TiptapComposer.js +15 -3
  383. package/dist/client/composer/TiptapComposer.js.map +1 -1
  384. package/dist/client/dynamic-suggestions.js +3 -3
  385. package/dist/client/dynamic-suggestions.js.map +1 -1
  386. package/dist/client/index.d.ts +4 -3
  387. package/dist/client/index.d.ts.map +1 -1
  388. package/dist/client/index.js +3 -2
  389. package/dist/client/index.js.map +1 -1
  390. package/dist/client/resources/ResourceTree.d.ts +5 -1
  391. package/dist/client/resources/ResourceTree.d.ts.map +1 -1
  392. package/dist/client/resources/ResourceTree.js +74 -5
  393. package/dist/client/resources/ResourceTree.js.map +1 -1
  394. package/dist/client/resources/ResourcesPanel.d.ts +11 -2
  395. package/dist/client/resources/ResourcesPanel.d.ts.map +1 -1
  396. package/dist/client/resources/ResourcesPanel.js +105 -31
  397. package/dist/client/resources/ResourcesPanel.js.map +1 -1
  398. package/dist/client/session-replay.d.ts +28 -0
  399. package/dist/client/session-replay.d.ts.map +1 -1
  400. package/dist/client/session-replay.js +122 -8
  401. package/dist/client/session-replay.js.map +1 -1
  402. package/dist/client/settings/AutomationsSection.d.ts +3 -1
  403. package/dist/client/settings/AutomationsSection.d.ts.map +1 -1
  404. package/dist/client/settings/AutomationsSection.js +16 -6
  405. package/dist/client/settings/AutomationsSection.js.map +1 -1
  406. package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
  407. package/dist/client/settings/SettingsPanel.js +3 -3
  408. package/dist/client/settings/SettingsPanel.js.map +1 -1
  409. package/dist/client/settings/SettingsTabsPage.d.ts +2 -0
  410. package/dist/client/settings/SettingsTabsPage.d.ts.map +1 -1
  411. package/dist/client/settings/SettingsTabsPage.js.map +1 -1
  412. package/dist/client/settings/agent-settings-search.js +2 -2
  413. package/dist/client/settings/agent-settings-search.js.map +1 -1
  414. package/dist/client/use-chat-threads.d.ts +2 -0
  415. package/dist/client/use-chat-threads.d.ts.map +1 -1
  416. package/dist/client/use-chat-threads.js.map +1 -1
  417. package/dist/connections/catalog.d.ts +41 -7
  418. package/dist/connections/catalog.d.ts.map +1 -1
  419. package/dist/connections/catalog.js +40 -7
  420. package/dist/connections/catalog.js.map +1 -1
  421. package/dist/db/index.d.ts +2 -2
  422. package/dist/db/index.d.ts.map +1 -1
  423. package/dist/db/index.js +2 -2
  424. package/dist/db/index.js.map +1 -1
  425. package/dist/deploy/build.d.ts.map +1 -1
  426. package/dist/deploy/build.js +17 -0
  427. package/dist/deploy/build.js.map +1 -1
  428. package/dist/extensions/actions.d.ts.map +1 -1
  429. package/dist/extensions/actions.js +85 -15
  430. package/dist/extensions/actions.js.map +1 -1
  431. package/dist/extensions/content-patch.d.ts +4 -0
  432. package/dist/extensions/content-patch.d.ts.map +1 -1
  433. package/dist/extensions/content-patch.js +18 -0
  434. package/dist/extensions/content-patch.js.map +1 -1
  435. package/dist/extensions/routes.d.ts.map +1 -1
  436. package/dist/extensions/routes.js +14 -0
  437. package/dist/extensions/routes.js.map +1 -1
  438. package/dist/extensions/store.d.ts +1 -0
  439. package/dist/extensions/store.d.ts.map +1 -1
  440. package/dist/extensions/store.js +4 -1
  441. package/dist/extensions/store.js.map +1 -1
  442. package/dist/index.d.ts +1 -1
  443. package/dist/index.d.ts.map +1 -1
  444. package/dist/index.js +1 -1
  445. package/dist/index.js.map +1 -1
  446. package/dist/ingestion/docx.d.ts +16 -0
  447. package/dist/ingestion/docx.d.ts.map +1 -0
  448. package/dist/ingestion/docx.js +129 -0
  449. package/dist/ingestion/docx.js.map +1 -0
  450. package/dist/ingestion/figma-node-to-html.d.ts +304 -0
  451. package/dist/ingestion/figma-node-to-html.d.ts.map +1 -0
  452. package/dist/ingestion/figma-node-to-html.js +1292 -0
  453. package/dist/ingestion/figma-node-to-html.js.map +1 -0
  454. package/dist/ingestion/figma.d.ts +115 -0
  455. package/dist/ingestion/figma.d.ts.map +1 -0
  456. package/dist/ingestion/figma.js +399 -0
  457. package/dist/ingestion/figma.js.map +1 -0
  458. package/dist/ingestion/index.d.ts +11 -0
  459. package/dist/ingestion/index.d.ts.map +1 -0
  460. package/dist/ingestion/index.js +11 -0
  461. package/dist/ingestion/index.js.map +1 -0
  462. package/dist/ingestion/media.d.ts +36 -0
  463. package/dist/ingestion/media.d.ts.map +1 -0
  464. package/dist/ingestion/media.js +178 -0
  465. package/dist/ingestion/media.js.map +1 -0
  466. package/dist/ingestion/notion.d.ts +12 -0
  467. package/dist/ingestion/notion.d.ts.map +1 -0
  468. package/dist/ingestion/notion.js +104 -0
  469. package/dist/ingestion/notion.js.map +1 -0
  470. package/dist/ingestion/office.d.ts +45 -0
  471. package/dist/ingestion/office.d.ts.map +1 -0
  472. package/dist/ingestion/office.js +141 -0
  473. package/dist/ingestion/office.js.map +1 -0
  474. package/dist/ingestion/orchestration.d.ts +52 -0
  475. package/dist/ingestion/orchestration.d.ts.map +1 -0
  476. package/dist/ingestion/orchestration.js +89 -0
  477. package/dist/ingestion/orchestration.js.map +1 -0
  478. package/dist/ingestion/pptx.d.ts +28 -0
  479. package/dist/ingestion/pptx.d.ts.map +1 -0
  480. package/dist/ingestion/pptx.js +255 -0
  481. package/dist/ingestion/pptx.js.map +1 -0
  482. package/dist/ingestion/selection.d.ts +20 -0
  483. package/dist/ingestion/selection.d.ts.map +1 -0
  484. package/dist/ingestion/selection.js +52 -0
  485. package/dist/ingestion/selection.js.map +1 -0
  486. package/dist/ingestion/website.d.ts +27 -0
  487. package/dist/ingestion/website.d.ts.map +1 -0
  488. package/dist/ingestion/website.js +100 -0
  489. package/dist/ingestion/website.js.map +1 -0
  490. package/dist/integrations/plugin.d.ts.map +1 -1
  491. package/dist/integrations/plugin.js +32 -27
  492. package/dist/integrations/plugin.js.map +1 -1
  493. package/dist/localization/default-messages.d.ts +22 -0
  494. package/dist/localization/default-messages.d.ts.map +1 -1
  495. package/dist/localization/default-messages.js +31 -9
  496. package/dist/localization/default-messages.js.map +1 -1
  497. package/dist/notifications/routes.d.ts +2 -2
  498. package/dist/observability/hosted-model-experiment.d.ts +39 -0
  499. package/dist/observability/hosted-model-experiment.d.ts.map +1 -0
  500. package/dist/observability/hosted-model-experiment.js +90 -0
  501. package/dist/observability/hosted-model-experiment.js.map +1 -0
  502. package/dist/observability/routes.d.ts +5 -5
  503. package/dist/observability/traces.d.ts.map +1 -1
  504. package/dist/observability/traces.js +5 -3
  505. package/dist/observability/traces.js.map +1 -1
  506. package/dist/provider-api/index.d.ts +35 -4
  507. package/dist/provider-api/index.d.ts.map +1 -1
  508. package/dist/provider-api/index.js +339 -8
  509. package/dist/provider-api/index.js.map +1 -1
  510. package/dist/scripts/agent-engines/list-agent-engines.d.ts.map +1 -1
  511. package/dist/scripts/agent-engines/list-agent-engines.js +18 -1
  512. package/dist/scripts/agent-engines/list-agent-engines.js.map +1 -1
  513. package/dist/search-utils/index.d.ts +12 -0
  514. package/dist/search-utils/index.d.ts.map +1 -0
  515. package/dist/search-utils/index.js +95 -0
  516. package/dist/search-utils/index.js.map +1 -0
  517. package/dist/secrets/register-framework-secrets.d.ts.map +1 -1
  518. package/dist/secrets/register-framework-secrets.js +57 -0
  519. package/dist/secrets/register-framework-secrets.js.map +1 -1
  520. package/dist/secrets/routes.d.ts +9 -9
  521. package/dist/server/action-discovery.d.ts +8 -0
  522. package/dist/server/action-discovery.d.ts.map +1 -1
  523. package/dist/server/action-discovery.js +26 -9
  524. package/dist/server/action-discovery.js.map +1 -1
  525. package/dist/server/agent-chat/framework-prompts.js +2 -2
  526. package/dist/server/agent-chat/framework-prompts.js.map +1 -1
  527. package/dist/server/agent-chat/prompt-resources.d.ts +19 -0
  528. package/dist/server/agent-chat/prompt-resources.d.ts.map +1 -1
  529. package/dist/server/agent-chat/prompt-resources.js +95 -0
  530. package/dist/server/agent-chat/prompt-resources.js.map +1 -1
  531. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  532. package/dist/server/agent-chat-plugin.js +7 -0
  533. package/dist/server/agent-chat-plugin.js.map +1 -1
  534. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  535. package/dist/server/core-routes-plugin.js +5 -0
  536. package/dist/server/core-routes-plugin.js.map +1 -1
  537. package/dist/server/index.d.ts +5 -1
  538. package/dist/server/index.d.ts.map +1 -1
  539. package/dist/server/index.js +5 -1
  540. package/dist/server/index.js.map +1 -1
  541. package/dist/server/workspace-provider-oauth.d.ts +48 -0
  542. package/dist/server/workspace-provider-oauth.d.ts.map +1 -0
  543. package/dist/server/workspace-provider-oauth.js +415 -0
  544. package/dist/server/workspace-provider-oauth.js.map +1 -0
  545. package/dist/styles/agent-native.css +9 -0
  546. package/dist/templates/chat/app/i18n/en-US.ts +3 -3
  547. package/dist/templates/chat/app/lib/agent-page.tsx +10 -1
  548. package/dist/templates/default/app/i18n/en-US.ts +3 -3
  549. package/dist/templates/workspace-core/.agents/skills/extensions/SKILL.md +14 -5
  550. package/dist/templates/workspace-root/.env.example +12 -0
  551. package/dist/workspace-connections/index.d.ts +1 -0
  552. package/dist/workspace-connections/index.d.ts.map +1 -1
  553. package/dist/workspace-connections/index.js +1 -0
  554. package/dist/workspace-connections/index.js.map +1 -1
  555. package/dist/workspace-connections/lifecycle.d.ts +16 -0
  556. package/dist/workspace-connections/lifecycle.d.ts.map +1 -0
  557. package/dist/workspace-connections/lifecycle.js +14 -0
  558. package/dist/workspace-connections/lifecycle.js.map +1 -0
  559. package/dist/workspace-connections/store.d.ts.map +1 -1
  560. package/dist/workspace-connections/store.js +16 -0
  561. package/dist/workspace-connections/store.js.map +1 -1
  562. package/package.json +10 -3
  563. package/src/templates/chat/app/i18n/en-US.ts +3 -3
  564. package/src/templates/chat/app/lib/agent-page.spec.tsx +10 -1
  565. package/src/templates/chat/app/lib/agent-page.tsx +10 -1
  566. package/src/templates/default/app/i18n/en-US.ts +3 -3
  567. package/src/templates/workspace-core/.agents/skills/extensions/SKILL.md +14 -5
  568. package/src/templates/workspace-root/.env.example +12 -0
@@ -1,3 +1,7 @@
1
+ import {
2
+ shouldReconcilePersistedRecording,
3
+ type OffscreenRecordingState,
4
+ } from "./native-recording-state";
1
5
  import { captureExtensionError, initExtensionSentry } from "./sentry";
2
6
 
3
7
  initExtensionSentry("background");
@@ -174,6 +178,7 @@ type OffscreenStatusMessage = {
174
178
  storageSetupRequired?: boolean;
175
179
  savedToDisk?: boolean;
176
180
  savedFilename?: string;
181
+ recordingStep?: string;
177
182
  };
178
183
 
179
184
  type ExtensionErrorMessage = {
@@ -1154,6 +1159,7 @@ async function startRecordingFromTab(args: {
1154
1159
  settings: ExtensionSettings;
1155
1160
  }) {
1156
1161
  const { tab, settings } = args;
1162
+ await reconcilePersistedNativeRecording();
1157
1163
  // The persisted value is authoritative (survives a worker suspension during
1158
1164
  // arming); the in-memory var is only a same-tick fast path on top of it.
1159
1165
  // Stale (past-TTL) or legacy-shaped guards are treated as absent — see
@@ -1311,7 +1317,6 @@ async function armRecording(args: {
1311
1317
  hasCamera: cameraInvolved,
1312
1318
  hasAudio:
1313
1319
  settings.includeMicrophone || settings.captureSurface !== "camera",
1314
- visibility: "public",
1315
1320
  mimeType: "video/webm",
1316
1321
  requestStreaming: true,
1317
1322
  });
@@ -1382,6 +1387,7 @@ async function armRecording(args: {
1382
1387
  hasCamera: cameraInvolved,
1383
1388
  startDelayMs,
1384
1389
  authToken,
1390
+ transcriptUrl: actionUrl(settings, "save-browser-transcript"),
1385
1391
  });
1386
1392
  } catch (err) {
1387
1393
  console.error("[clips-bg] arm: BEGIN failed", err);
@@ -1548,6 +1554,10 @@ async function handleOverlayRestart() {
1548
1554
  hasCamera: cameraInvolved,
1549
1555
  startDelayMs: cameraInvolved ? 20000 : COUNTDOWN_SECONDS * 1000 + 1000,
1550
1556
  authToken: restartAuthToken,
1557
+ transcriptUrl: actionUrl(
1558
+ settingsFromRecording(recording),
1559
+ "save-browser-transcript",
1560
+ ),
1551
1561
  });
1552
1562
  } catch (err) {
1553
1563
  // Re-arming failed: tear the countdown overlay back down and report the
@@ -1721,7 +1731,48 @@ async function clearNativeRecording(): Promise<void> {
1721
1731
  await chrome.action.setBadgeText({ text: "" });
1722
1732
  }
1723
1733
 
1734
+ async function reconcilePersistedNativeRecording(): Promise<void> {
1735
+ const recording = activeNativeRecording;
1736
+ if (!recording) return;
1737
+ if (recording.status === "error" || recording.status === "complete") return;
1738
+
1739
+ try {
1740
+ await ensureOffscreenDocument();
1741
+ const state = await sendOffscreenMessage<OffscreenRecordingState>({
1742
+ type: "CLIPS_OFFSCREEN_STATUS",
1743
+ });
1744
+ if (
1745
+ !shouldReconcilePersistedRecording(
1746
+ recording.status,
1747
+ recording.sessionId,
1748
+ state,
1749
+ )
1750
+ ) {
1751
+ return;
1752
+ }
1753
+ } catch {
1754
+ // A transient wake-up failure must not discard a real recording.
1755
+ return;
1756
+ }
1757
+
1758
+ console.warn(
1759
+ "[clips-bg] clearing persisted recording with no live offscreen session",
1760
+ recording.sessionId,
1761
+ );
1762
+ await deleteSession(recording.sessionId).catch((error) => {
1763
+ console.warn(
1764
+ "[clips-bg] stale recording cleanup could not detach tab",
1765
+ error,
1766
+ );
1767
+ });
1768
+ resetOverlay();
1769
+ await broadcastUnmount();
1770
+ broadcastOverlayState();
1771
+ await clearNativeRecording();
1772
+ }
1773
+
1724
1774
  async function handlePopupStatus() {
1775
+ await reconcilePersistedNativeRecording();
1725
1776
  return {
1726
1777
  ok: true,
1727
1778
  activeRecording: activeNativeRecording,
@@ -2355,6 +2406,27 @@ async function dispatchRuntimeMessage(message: unknown): Promise<unknown> {
2355
2406
  ? status.savedFilename
2356
2407
  : undefined;
2357
2408
  }
2409
+ if (
2410
+ status.status === "error" &&
2411
+ status.recordingStep === "recorder-start"
2412
+ ) {
2413
+ await deleteSession(activeNativeRecording.sessionId).catch((error) => {
2414
+ console.warn(
2415
+ "[clips-bg] failed recorder-start cleanup could not detach tab",
2416
+ error,
2417
+ );
2418
+ });
2419
+ await postAction(
2420
+ settingsFromRecording(activeNativeRecording),
2421
+ "trash-recording",
2422
+ { id: activeNativeRecording.recordingId },
2423
+ ).catch(() => undefined);
2424
+ resetOverlay();
2425
+ await broadcastUnmount();
2426
+ broadcastOverlayState();
2427
+ await clearNativeRecording();
2428
+ return { ok: true };
2429
+ }
2358
2430
  await saveActiveNativeRecording();
2359
2431
  // The offscreen recorder finished its pre-roll and actually started —
2360
2432
  // advance from countdown to recording (the reliable phase flip).
@@ -0,0 +1,32 @@
1
+ export type NativeRecordingStateStatus =
2
+ | "recording"
3
+ | "paused"
4
+ | "stopping"
5
+ | "uploading"
6
+ | "complete"
7
+ | "error";
8
+
9
+ export type OffscreenRecordingState = {
10
+ activeSessionId?: string;
11
+ preparedSessionId?: string;
12
+ };
13
+
14
+ export function hasLiveOffscreenSession(
15
+ sessionId: string,
16
+ state: OffscreenRecordingState,
17
+ ): boolean {
18
+ return (
19
+ state.activeSessionId === sessionId || state.preparedSessionId === sessionId
20
+ );
21
+ }
22
+
23
+ export function shouldReconcilePersistedRecording(
24
+ status: NativeRecordingStateStatus,
25
+ sessionId: string,
26
+ state: OffscreenRecordingState,
27
+ ): boolean {
28
+ // Preserve terminal errors so the popup can explain an upload failure and
29
+ // offer the existing discard/re-upload path.
30
+ if (status === "error" || status === "complete") return false;
31
+ return !hasLiveOffscreenSession(sessionId, state);
32
+ }
@@ -0,0 +1,248 @@
1
+ export interface NativeTranscriptResult {
2
+ text: string;
3
+ failureReason: string | null;
4
+ }
5
+
6
+ interface SpeechRecognitionResultLike {
7
+ isFinal: boolean;
8
+ 0?: { transcript?: string };
9
+ }
10
+
11
+ interface SpeechRecognitionEventLike {
12
+ resultIndex: number;
13
+ results: ArrayLike<SpeechRecognitionResultLike>;
14
+ }
15
+
16
+ interface SpeechRecognitionErrorEventLike {
17
+ error?: string;
18
+ }
19
+
20
+ interface SpeechRecognitionLike {
21
+ continuous: boolean;
22
+ interimResults: boolean;
23
+ lang: string;
24
+ maxAlternatives: number;
25
+ onresult: ((event: SpeechRecognitionEventLike) => void) | null;
26
+ onerror: ((event: SpeechRecognitionErrorEventLike) => void) | null;
27
+ onend: (() => void) | null;
28
+ start: () => void;
29
+ stop: () => void;
30
+ abort: () => void;
31
+ }
32
+
33
+ type SpeechRecognitionConstructor = new () => SpeechRecognitionLike;
34
+
35
+ export interface NativeTranscriptionCapture {
36
+ supported: boolean;
37
+ start(): void;
38
+ stop(): Promise<NativeTranscriptResult>;
39
+ cancel(): void;
40
+ pause(): void;
41
+ resume(): void;
42
+ }
43
+
44
+ const STOP_SETTLE_MS = 1_500;
45
+ const RESTART_DELAY_MS = 250;
46
+
47
+ function getSpeechRecognitionCtor(): SpeechRecognitionConstructor | null {
48
+ if (typeof window === "undefined") return null;
49
+ const scope = window as unknown as {
50
+ SpeechRecognition?: SpeechRecognitionConstructor;
51
+ webkitSpeechRecognition?: SpeechRecognitionConstructor;
52
+ };
53
+ return scope.SpeechRecognition ?? scope.webkitSpeechRecognition ?? null;
54
+ }
55
+
56
+ function appendTranscript(current: string, next: string): string {
57
+ const cleanNext = next.trim();
58
+ if (!cleanNext) return current;
59
+ return current ? `${current} ${cleanNext}` : cleanNext;
60
+ }
61
+
62
+ export function createNativeTranscriptionCapture(options?: {
63
+ enabled?: boolean;
64
+ lang?: string;
65
+ }): NativeTranscriptionCapture {
66
+ const Ctor = getSpeechRecognitionCtor();
67
+ const enabled = options?.enabled ?? true;
68
+ const language =
69
+ options?.lang ??
70
+ (typeof navigator !== "undefined" ? navigator.language : "en-US");
71
+ const unsupportedReason = !enabled
72
+ ? "Native speech transcription requires microphone capture."
73
+ : !Ctor
74
+ ? "Chrome Web Speech recognition is unavailable in this context."
75
+ : null;
76
+
77
+ let recognition: SpeechRecognitionLike | null = null;
78
+ let finalText = "";
79
+ let interimText = "";
80
+ let stopped = false;
81
+ let paused = false;
82
+ let disposed = false;
83
+ let failureReason = unsupportedReason;
84
+ let restartTimer: ReturnType<typeof setTimeout> | null = null;
85
+ let stopPromise: Promise<NativeTranscriptResult> | null = null;
86
+ let resolveStop: ((result: NativeTranscriptResult) => void) | null = null;
87
+ let stopTimer: ReturnType<typeof setTimeout> | null = null;
88
+
89
+ const result = (): NativeTranscriptResult => {
90
+ const text = appendTranscript(finalText, interimText).trim();
91
+ return {
92
+ text,
93
+ failureReason:
94
+ text.length > 0
95
+ ? null
96
+ : failureReason ||
97
+ "Chrome Web Speech recognition returned no transcript.",
98
+ };
99
+ };
100
+
101
+ const settleStop = (): void => {
102
+ if (!resolveStop) return;
103
+ if (stopTimer !== null) {
104
+ clearTimeout(stopTimer);
105
+ stopTimer = null;
106
+ }
107
+ const resolve = resolveStop;
108
+ resolveStop = null;
109
+ disposed = true;
110
+ recognition = null;
111
+ resolve(result());
112
+ };
113
+
114
+ const scheduleRestart = (): void => {
115
+ if (restartTimer !== null) return;
116
+ restartTimer = setTimeout(() => {
117
+ restartTimer = null;
118
+ if (disposed || stopped || paused || !recognition) return;
119
+ try {
120
+ recognition.start();
121
+ } catch (error) {
122
+ failureReason =
123
+ error instanceof Error
124
+ ? `Chrome Web Speech recognition could not restart: ${error.message}`
125
+ : "Chrome Web Speech recognition could not restart.";
126
+ }
127
+ }, RESTART_DELAY_MS);
128
+ };
129
+
130
+ const start = (): void => {
131
+ if (!Ctor || !enabled || disposed || stopped || recognition) return;
132
+
133
+ const nextRecognition = new Ctor();
134
+ recognition = nextRecognition;
135
+ nextRecognition.continuous = true;
136
+ nextRecognition.interimResults = true;
137
+ nextRecognition.lang = language;
138
+ nextRecognition.maxAlternatives = 1;
139
+ nextRecognition.onresult = (event) => {
140
+ let nextInterim = "";
141
+ for (
142
+ let index = event.resultIndex;
143
+ index < event.results.length;
144
+ index++
145
+ ) {
146
+ const item = event.results[index];
147
+ const text = item?.[0]?.transcript ?? "";
148
+ if (item?.isFinal) finalText = appendTranscript(finalText, text);
149
+ else nextInterim = appendTranscript(nextInterim, text);
150
+ }
151
+ interimText = nextInterim;
152
+ };
153
+ nextRecognition.onerror = (event) => {
154
+ const error = event.error;
155
+ if (!error || error === "no-speech" || error === "aborted") return;
156
+ failureReason = `Chrome Web Speech recognition error: ${error}.`;
157
+ if (error === "not-allowed" || error === "service-not-allowed") {
158
+ stopped = true;
159
+ }
160
+ };
161
+ nextRecognition.onend = () => {
162
+ if (disposed) return;
163
+ if (stopped) {
164
+ settleStop();
165
+ return;
166
+ }
167
+ if (!paused) scheduleRestart();
168
+ };
169
+
170
+ try {
171
+ nextRecognition.start();
172
+ } catch (error) {
173
+ failureReason =
174
+ error instanceof Error
175
+ ? `Chrome Web Speech recognition could not start: ${error.message}`
176
+ : "Chrome Web Speech recognition could not start.";
177
+ recognition = null;
178
+ }
179
+ };
180
+
181
+ const stop = (): Promise<NativeTranscriptResult> => {
182
+ if (stopPromise) return stopPromise;
183
+ stopped = true;
184
+ paused = false;
185
+ if (restartTimer !== null) {
186
+ clearTimeout(restartTimer);
187
+ restartTimer = null;
188
+ }
189
+ if (!recognition) {
190
+ disposed = true;
191
+ return Promise.resolve(result());
192
+ }
193
+
194
+ stopPromise = new Promise<NativeTranscriptResult>((resolve) => {
195
+ resolveStop = resolve;
196
+ stopTimer = setTimeout(settleStop, STOP_SETTLE_MS);
197
+ try {
198
+ recognition?.stop();
199
+ } catch {
200
+ settleStop();
201
+ }
202
+ });
203
+ return stopPromise;
204
+ };
205
+
206
+ const cancel = (): void => {
207
+ stopped = true;
208
+ disposed = true;
209
+ if (restartTimer !== null) clearTimeout(restartTimer);
210
+ if (stopTimer !== null) clearTimeout(stopTimer);
211
+ resolveStop = null;
212
+ try {
213
+ recognition?.abort();
214
+ } catch {
215
+ // Ignore teardown failures.
216
+ }
217
+ recognition = null;
218
+ };
219
+
220
+ const pause = (): void => {
221
+ if (!recognition || stopped || disposed) return;
222
+ paused = true;
223
+ try {
224
+ recognition.stop();
225
+ } catch {
226
+ // The onend handler will settle the stopped recognition.
227
+ }
228
+ };
229
+
230
+ const resume = (): void => {
231
+ if (!recognition || stopped || disposed) return;
232
+ paused = false;
233
+ try {
234
+ recognition.start();
235
+ } catch {
236
+ failureReason = "Chrome Web Speech recognition could not resume.";
237
+ }
238
+ };
239
+
240
+ return {
241
+ supported: Boolean(Ctor && enabled),
242
+ start,
243
+ stop,
244
+ cancel,
245
+ pause,
246
+ resume,
247
+ };
248
+ }
@@ -36,6 +36,10 @@ import {
36
36
  import { MAX_UPLOAD_BYTES } from "@shared/upload-limits";
37
37
 
38
38
  import { waitForReadyRecordingAfterFinalizeError } from "./finalize-recovery";
39
+ import {
40
+ createNativeTranscriptionCapture,
41
+ type NativeTranscriptionCapture,
42
+ } from "./native-transcription";
39
43
  import {
40
44
  createRecordingDurationState,
41
45
  pauseRecordingDuration,
@@ -141,6 +145,7 @@ type BeginMessage = {
141
145
  // Bearer token so chunk uploads authenticate the same way create-recording
142
146
  // does. The offscreen document has no Clips session cookie of its own.
143
147
  authToken?: string;
148
+ transcriptUrl?: string;
144
149
  };
145
150
 
146
151
  type SimpleMessage = {
@@ -172,6 +177,8 @@ type UploadResult = {
172
177
  waitingForStorage?: boolean;
173
178
  storageSetupRequired?: boolean;
174
179
  error?: string;
180
+ nativeTranscript?: string;
181
+ nativeTranscriptFailure?: string;
175
182
  };
176
183
 
177
184
  type PreparedStreams = {
@@ -192,6 +199,7 @@ type ActiveRecording = {
192
199
  uploadUrl: string;
193
200
  uploadMode: UploadMode;
194
201
  authToken: string | null;
202
+ transcriptUrl: string | null;
195
203
  mode: CaptureMode;
196
204
  startedAtMs: number;
197
205
  duration: RecordingDurationState;
@@ -231,6 +239,10 @@ type ActiveRecording = {
231
239
  dimensions: { width: number; height: number };
232
240
  hasAudio: boolean;
233
241
  hasCamera: boolean;
242
+ nativeTranscription: NativeTranscriptionCapture;
243
+ nativeTranscript: string;
244
+ nativeTranscriptFailure: string | null;
245
+ nativeTranscriptSaved: boolean;
234
246
  stopped: Promise<UploadResult>;
235
247
  resolveStopped: (result: UploadResult) => void;
236
248
  rejectStopped: (error: Error) => void;
@@ -1224,6 +1236,7 @@ async function begin(message: BeginMessage): Promise<{
1224
1236
  uploadUrl: message.uploadUrl,
1225
1237
  uploadMode: message.uploadMode ?? "buffered",
1226
1238
  authToken: message.authToken ?? null,
1239
+ transcriptUrl: message.transcriptUrl ?? null,
1227
1240
  mode: ready.mode,
1228
1241
  startedAtMs: 0,
1229
1242
  duration: createRecordingDurationState(),
@@ -1259,6 +1272,12 @@ async function begin(message: BeginMessage): Promise<{
1259
1272
  typeof message.hasCamera === "boolean"
1260
1273
  ? message.hasCamera
1261
1274
  : ready.mode === "camera",
1275
+ nativeTranscription: createNativeTranscriptionCapture({
1276
+ enabled: Boolean(ready.micStream),
1277
+ }),
1278
+ nativeTranscript: "",
1279
+ nativeTranscriptFailure: null,
1280
+ nativeTranscriptSaved: false,
1262
1281
  stopped,
1263
1282
  resolveStopped,
1264
1283
  rejectStopped,
@@ -1358,6 +1377,7 @@ function startRecorderNow(recording: ActiveRecording): void {
1358
1377
  // Chime first (on "Go") so it mostly lands before the recording begins.
1359
1378
  playStartChime();
1360
1379
  recording.recorder.start(2000);
1380
+ recording.nativeTranscription.start();
1361
1381
  recording.startedAtMs = Date.now();
1362
1382
  recording.duration = startRecordingDuration(recording.startedAtMs);
1363
1383
  console.log("[clips-offscreen] recorder.start ok");
@@ -1383,9 +1403,14 @@ function startRecorderNow(recording: ActiveRecording): void {
1383
1403
  hasCamera: recording.hasCamera,
1384
1404
  },
1385
1405
  });
1406
+ recording.cancelled = true;
1407
+ recording.nativeTranscription.cancel();
1408
+ cleanup(recording);
1409
+ if (activeRecording === recording) activeRecording = null;
1386
1410
  reportStatus(recording.sessionId, "error", {
1387
1411
  recordingId: recording.recordingId,
1388
1412
  error: err instanceof Error ? err.message : "Could not start recording.",
1413
+ recordingStep: "recorder-start",
1389
1414
  });
1390
1415
  }
1391
1416
  }
@@ -1400,6 +1425,47 @@ function recordingDownloadFilename(recording: ActiveRecording): string {
1400
1425
  return `clip-${stamp}.${ext}`;
1401
1426
  }
1402
1427
 
1428
+ async function saveNativeTranscript(recording: ActiveRecording): Promise<void> {
1429
+ if (recording.nativeTranscriptSaved || !recording.transcriptUrl) return;
1430
+ const captured = await recording.nativeTranscription.stop();
1431
+ recording.nativeTranscript = captured.text.trim();
1432
+ recording.nativeTranscriptFailure = captured.failureReason;
1433
+
1434
+ const body = recording.nativeTranscript
1435
+ ? {
1436
+ recordingId: recording.recordingId,
1437
+ fullText: recording.nativeTranscript,
1438
+ source: "web-speech",
1439
+ }
1440
+ : {
1441
+ recordingId: recording.recordingId,
1442
+ fullText: "",
1443
+ source: "web-speech",
1444
+ failureReason:
1445
+ recording.nativeTranscriptFailure ||
1446
+ "Chrome Web Speech recognition returned no transcript.",
1447
+ };
1448
+ const headers: Record<string, string> = {
1449
+ "Content-Type": "application/json",
1450
+ "X-Agent-Native-Frontend": "1",
1451
+ ...(recording.authToken
1452
+ ? { Authorization: `Bearer ${recording.authToken}` }
1453
+ : {}),
1454
+ };
1455
+ const response = await fetch(recording.transcriptUrl, {
1456
+ method: "POST",
1457
+ headers,
1458
+ credentials: "include",
1459
+ cache: "no-store",
1460
+ body: JSON.stringify(body),
1461
+ signal: AbortSignal.timeout(5_000),
1462
+ });
1463
+ if (!response.ok) {
1464
+ throw new Error(`Native transcript save failed (${response.status}).`);
1465
+ }
1466
+ recording.nativeTranscriptSaved = true;
1467
+ }
1468
+
1403
1469
  // Last-resort recovery: if a finished recording can't be uploaded, save the
1404
1470
  // locally-buffered bytes to the user's Downloads so the recording is never
1405
1471
  // lost. The offscreen document can't call chrome.downloads, so it hands the
@@ -1461,6 +1527,18 @@ async function finalizeStop(recording: ActiveRecording): Promise<void> {
1461
1527
  // spent paused is excluded by pauseRecordingDuration().
1462
1528
  recording.duration = pauseRecordingDuration(recording.duration, Date.now());
1463
1529
  const durationMs = recording.duration.elapsedMs;
1530
+ try {
1531
+ await saveNativeTranscript(recording);
1532
+ } catch (error) {
1533
+ console.warn("[clips-offscreen] native transcript save failed", error);
1534
+ captureExtensionError(error, {
1535
+ tags: {
1536
+ surface: "offscreen",
1537
+ recordingStep: "save-native-transcript",
1538
+ },
1539
+ extra: { recordingId: recording.recordingId },
1540
+ });
1541
+ }
1464
1542
  reportStatus(recording.sessionId, "uploading", {
1465
1543
  recordingId: recording.recordingId,
1466
1544
  });
@@ -1514,6 +1592,15 @@ async function finalizeStop(recording: ActiveRecording): Promise<void> {
1514
1592
  hasAudio: recording.hasAudio,
1515
1593
  hasCamera: recording.hasCamera,
1516
1594
  });
1595
+ result = {
1596
+ ...result,
1597
+ ...(recording.nativeTranscript
1598
+ ? { nativeTranscript: recording.nativeTranscript }
1599
+ : {}),
1600
+ ...(recording.nativeTranscriptFailure
1601
+ ? { nativeTranscriptFailure: recording.nativeTranscriptFailure }
1602
+ : {}),
1603
+ };
1517
1604
  } catch (err) {
1518
1605
  const error = err instanceof Error ? err : new Error(String(err));
1519
1606
  (error as { finalUpload?: boolean }).finalUpload = true;
@@ -1590,6 +1677,7 @@ function pause(message: SimpleMessage): { ok: boolean } {
1590
1677
  if (recording && recording.sessionId === message.sessionId) {
1591
1678
  if (recording.recorder.state === "recording") {
1592
1679
  recording.recorder.pause();
1680
+ recording.nativeTranscription.pause();
1593
1681
  recording.duration = pauseRecordingDuration(
1594
1682
  recording.duration,
1595
1683
  Date.now(),
@@ -1607,6 +1695,7 @@ function resume(message: SimpleMessage): { ok: boolean } {
1607
1695
  if (recording && recording.sessionId === message.sessionId) {
1608
1696
  if (recording.recorder.state === "paused") {
1609
1697
  recording.recorder.resume();
1698
+ recording.nativeTranscription.resume();
1610
1699
  recording.duration = resumeRecordingDuration(
1611
1700
  recording.duration,
1612
1701
  Date.now(),
@@ -1644,6 +1733,7 @@ function cancel(message: SimpleMessage): { ok: boolean } {
1644
1733
  const recording = activeRecording;
1645
1734
  if (recording && recording.sessionId === message.sessionId) {
1646
1735
  recording.cancelled = true;
1736
+ recording.nativeTranscription.cancel();
1647
1737
  if (recording.startTimer !== null) {
1648
1738
  clearTimeout(recording.startTimer);
1649
1739
  recording.startTimer = null;
@@ -1673,6 +1763,18 @@ function startNow(message: SimpleMessage): { ok: boolean } {
1673
1763
  return { ok: true };
1674
1764
  }
1675
1765
 
1766
+ function getRecordingState(): {
1767
+ ok: boolean;
1768
+ activeSessionId?: string;
1769
+ preparedSessionId?: string;
1770
+ } {
1771
+ return {
1772
+ ok: true,
1773
+ ...(activeRecording ? { activeSessionId: activeRecording.sessionId } : {}),
1774
+ ...(prepared ? { preparedSessionId: prepared.sessionId } : {}),
1775
+ };
1776
+ }
1777
+
1676
1778
  // Restart: discard the in-progress recording but keep the same source streams
1677
1779
  // (so the user does not have to re-pick a screen), then re-home them into a
1678
1780
  // prepared slot. A fresh recorder is built on the next BEGIN.
@@ -1687,6 +1789,7 @@ async function restart(
1687
1789
  // handler ignores the final flush, so the source tracks stay live.
1688
1790
  recording.restarting = true;
1689
1791
  recording.cancelled = true;
1792
+ recording.nativeTranscription.cancel();
1690
1793
  if (recording.recorder.state !== "inactive") recording.recorder.stop();
1691
1794
  // Tear down the old compositor + mixing context; keep the capture tracks alive
1692
1795
  // so the next BEGIN can build a fresh compositor/recorder on the same streams.
@@ -1741,6 +1844,9 @@ chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
1741
1844
  case "CLIPS_OFFSCREEN_START_NOW":
1742
1845
  task = Promise.resolve(startNow(message as SimpleMessage));
1743
1846
  break;
1847
+ case "CLIPS_OFFSCREEN_STATUS":
1848
+ task = Promise.resolve(getRecordingState());
1849
+ break;
1744
1850
  case "CLIPS_OFFSCREEN_COPY_TEXT":
1745
1851
  task = copyTextToClipboard(message as CopyTextMessage);
1746
1852
  break;