@agent-native/core 0.121.1 → 0.122.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 (465) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +145 -0
  3. package/corpus/core/docs/content/actions.mdx +2 -2
  4. package/corpus/core/docs/content/agent-surfaces.mdx +1 -1
  5. package/corpus/core/docs/content/authentication.mdx +2 -0
  6. package/corpus/core/docs/content/deployment.mdx +36 -0
  7. package/corpus/core/docs/content/getting-started.mdx +477 -115
  8. package/corpus/core/docs/content/http-api.mdx +266 -0
  9. package/corpus/core/docs/content/syncing-template-changes.mdx +159 -0
  10. package/corpus/core/package.json +2 -1
  11. package/corpus/core/src/a2a/activity.ts +38 -27
  12. package/corpus/core/src/agent/engine/builder-engine.ts +35 -4
  13. package/corpus/core/src/agent/run-manager.ts +20 -1
  14. package/corpus/core/src/agent/run-store.ts +4 -1
  15. package/corpus/core/src/agent/types.ts +28 -8
  16. package/corpus/core/src/chat-threads/store.ts +45 -0
  17. package/corpus/core/src/checkpoints/index.ts +2 -0
  18. package/corpus/core/src/checkpoints/route-match.ts +13 -0
  19. package/corpus/core/src/cli/create.ts +105 -17
  20. package/corpus/core/src/cli/index.ts +20 -0
  21. package/corpus/core/src/cli/template-baseline.ts +410 -0
  22. package/corpus/core/src/cli/template-sync.ts +1004 -0
  23. package/corpus/core/src/cli/templates-meta.ts +1 -0
  24. package/corpus/core/src/client/AssistantChat.tsx +38 -12
  25. package/corpus/core/src/client/NewWorkspaceAppFlow.tsx +75 -10
  26. package/corpus/core/src/client/chat/message-components.tsx +127 -66
  27. package/corpus/core/src/client/chat/tool-call-display.tsx +29 -5
  28. package/corpus/core/src/client/error-format.ts +18 -0
  29. package/corpus/core/src/client/org/OrgSwitcher.tsx +30 -8
  30. package/corpus/core/src/client/org/TeamPage.tsx +7 -6
  31. package/corpus/core/src/client/sse-event-processor.ts +3 -0
  32. package/corpus/core/src/data-widgets/index.ts +41 -0
  33. package/corpus/core/src/deploy/build.ts +11 -9
  34. package/corpus/core/src/integrations/webhook-handler.ts +63 -9
  35. package/corpus/core/src/org/auto-join-domain.ts +4 -3
  36. package/corpus/core/src/org/context.ts +108 -39
  37. package/corpus/core/src/org/index.ts +5 -0
  38. package/corpus/core/src/org/service-identity.ts +60 -0
  39. package/corpus/core/src/provider-api/index.ts +22 -1
  40. package/corpus/core/src/scripts/docs/search.ts +12 -1
  41. package/corpus/core/src/server/agent-chat/context-tools.ts +9 -4
  42. package/corpus/core/src/server/agent-chat/framework-prompts.ts +38 -66
  43. package/corpus/core/src/server/agent-chat-plugin.ts +17 -10
  44. package/corpus/core/src/server/agents-bundle.ts +84 -5
  45. package/corpus/core/src/server/auth.ts +4 -3
  46. package/corpus/core/src/server/builder-browser.ts +47 -19
  47. package/corpus/core/src/server/core-routes-plugin.ts +2 -2
  48. package/corpus/core/src/server/credential-provider.ts +209 -68
  49. package/corpus/core/src/server/index.ts +3 -0
  50. package/corpus/core/src/server/prompts/framework-core-compact.ts +6 -13
  51. package/corpus/core/src/server/prompts/framework-core.ts +9 -21
  52. package/corpus/core/src/server/prompts/index.ts +0 -1
  53. package/corpus/core/src/server/prompts/shared-rules.ts +19 -11
  54. package/corpus/core/src/server/ssr-handler.ts +13 -2
  55. package/corpus/core/src/settings/user-settings.ts +13 -1
  56. package/corpus/core/src/shared/cache-control.ts +141 -0
  57. package/corpus/core/src/templates/chat/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  58. package/corpus/core/src/templates/chat/_gitignore +1 -0
  59. package/corpus/core/src/templates/default/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  60. package/corpus/core/src/templates/headless/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  61. package/corpus/core/src/templates/workspace-core/.agents/skills/performance/SKILL.md +19 -0
  62. package/corpus/core/src/templates/workspace-core/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  63. package/corpus/core/src/templates/workspace-core/.agents/skills/visual-answer/SKILL.md +1 -0
  64. package/corpus/core/src/vite/agents-bundle-plugin.ts +7 -6
  65. package/corpus/core/src/vite/client.ts +5 -0
  66. package/corpus/templates/analytics/.agents/skills/adhoc-analysis/SKILL.md +4 -5
  67. package/corpus/templates/analytics/.agents/skills/admin-surfaces/SKILL.md +55 -0
  68. package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +10 -0
  69. package/corpus/templates/analytics/.agents/skills/dashboard-management/references/template-catalog-and-demo.md +62 -0
  70. package/corpus/templates/analytics/.agents/skills/dashboard-ops/SKILL.md +85 -0
  71. package/corpus/templates/analytics/.agents/skills/data-querying/SKILL.md +27 -2
  72. package/corpus/templates/analytics/.agents/skills/data-querying/references/inline-chart-embeds.md +139 -0
  73. package/corpus/templates/analytics/.agents/skills/monitoring/SKILL.md +77 -0
  74. package/corpus/templates/analytics/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  75. package/corpus/templates/analytics/AGENTS.md +91 -563
  76. package/corpus/templates/analytics/_gitignore +1 -0
  77. package/corpus/templates/analytics/actions/bigquery.ts +12 -4
  78. package/corpus/templates/analytics/actions/generate-chart.ts +5 -5
  79. package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +30 -1
  80. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/DashboardFilterBar.tsx +3 -0
  81. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +1 -1
  82. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +1 -0
  83. package/corpus/templates/analytics/changelog/2026-07-24-analytics-finds-saved-dashboards-and-queries-far-more-reliab.md +6 -0
  84. package/corpus/templates/analytics/changelog/2026-07-24-notion-access-errors-now-explain-that-a-page-needs-sharing-w.md +6 -0
  85. package/corpus/templates/analytics/server/lib/agent-chat-plan-mode.ts +7 -0
  86. package/corpus/templates/analytics/server/lib/analytics-query-catalog.ts +191 -30
  87. package/corpus/templates/analytics/server/lib/bigquery.ts +11 -1
  88. package/corpus/templates/analytics/server/lib/notion.ts +15 -4
  89. package/corpus/templates/analytics/server/plugins/agent-chat.ts +10 -0
  90. package/corpus/templates/assets/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  91. package/corpus/templates/brain/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  92. package/corpus/templates/brain/_gitignore +1 -0
  93. package/corpus/templates/calendar/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  94. package/corpus/templates/calendar/_gitignore +1 -0
  95. package/corpus/templates/chat/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  96. package/corpus/templates/chat/_gitignore +1 -0
  97. package/corpus/templates/clips/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  98. package/corpus/templates/clips/.agents/skills/video-sharing/SKILL.md +34 -0
  99. package/corpus/templates/clips/AGENTS.md +5 -4
  100. package/corpus/templates/clips/_gitignore +1 -0
  101. package/corpus/templates/clips/actions/cleanup-transcript.ts +5 -0
  102. package/corpus/templates/clips/actions/get-recording-insights.ts +44 -8
  103. package/corpus/templates/clips/actions/get-recording-player-data.ts +39 -70
  104. package/corpus/templates/clips/actions/list-clip-views.ts +2 -4
  105. package/corpus/templates/clips/actions/list-recordings.ts +69 -19
  106. package/corpus/templates/clips/actions/list-viewers.ts +5 -2
  107. package/corpus/templates/clips/actions/regenerate-summary.ts +5 -1
  108. package/corpus/templates/clips/actions/request-transcript.ts +28 -1
  109. package/corpus/templates/clips/app/components/editor/stitch-manager.tsx +21 -1
  110. package/corpus/templates/clips/app/components/meetings/quick-ask-sidebar.tsx +14 -1
  111. package/corpus/templates/clips/app/components/player/insights-panel.tsx +8 -20
  112. package/corpus/templates/clips/app/components/player/recording-views-badge.tsx +335 -0
  113. package/corpus/templates/clips/app/components/player/video-player.tsx +13 -8
  114. package/corpus/templates/clips/app/components/sharing/share-ui.tsx +2 -1
  115. package/corpus/templates/clips/app/i18n/en-US.ts +13 -2
  116. package/corpus/templates/clips/app/lib/capture-permissions.ts +110 -0
  117. package/corpus/templates/clips/app/lib/recording-link.ts +32 -0
  118. package/corpus/templates/clips/app/routes/_app.meetings.$meetingId.tsx +27 -0
  119. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +46 -15
  120. package/corpus/templates/clips/app/routes/record.tsx +77 -31
  121. package/corpus/templates/clips/app/routes/share.$shareId.tsx +42 -31
  122. package/corpus/templates/clips/changelog/2026-07-24-clip-pages-now-show-a-view-count-with-viewer-avatars-next-to.md +6 -0
  123. package/corpus/templates/clips/changelog/2026-07-24-clip-summaries-read-like-a-description-you-d-write-yourself-.md +6 -0
  124. package/corpus/templates/clips/changelog/2026-07-24-clip-view-counts-now-separate-human-views-from-agent-views-s.md +6 -0
  125. package/corpus/templates/clips/changelog/2026-07-24-clips-actions-can-now-be-called-by-org-service-tokens-so-ext.md +6 -0
  126. package/corpus/templates/clips/changelog/2026-07-24-clips-no-longer-briefly-shows-a-dock-icon-while-launching.md +6 -0
  127. package/corpus/templates/clips/changelog/2026-07-24-fixed-owner-and-editor-share-links-redirecting-to-the-record.md +6 -0
  128. package/corpus/templates/clips/changelog/2026-07-24-meeting-and-note-recordings-now-start-as-a-compact-pill-on-t.md +6 -0
  129. package/corpus/templates/clips/changelog/2026-07-24-new-clips-now-copy-a-shareable-link-instead-of-the-owner-onl.md +6 -0
  130. package/corpus/templates/clips/changelog/2026-07-24-opening-a-share-link-as-the-clip-s-owner-now-goes-straight-t.md +6 -0
  131. package/corpus/templates/clips/changelog/2026-07-24-permissions-and-rewind-controls-now-use-compact-consistent-h.md +6 -0
  132. package/corpus/templates/clips/changelog/2026-07-24-quitting-the-desktop-app-no-longer-shows-a-false-macos-crash.md +6 -0
  133. package/corpus/templates/clips/changelog/2026-07-24-screen-recording-permission-errors-now-name-the-exact-app-to.md +6 -0
  134. package/corpus/templates/clips/changelog/2026-07-24-the-desktop-app-now-copies-a-new-clip-s-share-link-to-your-c.md +6 -0
  135. package/corpus/templates/clips/changelog/2026-07-24-the-recording-toolbar-now-stays-above-other-apps-including-o.md +6 -0
  136. package/corpus/templates/clips/changelog/2026-07-24-transcript-captions-now-use-real-speech-timings-instead-of-a.md +6 -0
  137. package/corpus/templates/clips/changelog/2026-07-24-video-playback-no-longer-stutters-and-replays-the-last-momen.md +6 -0
  138. package/corpus/templates/clips/chrome-extension/src/background.ts +17 -1
  139. package/corpus/templates/clips/desktop/package.json +2 -0
  140. package/corpus/templates/clips/desktop/src/app.tsx +89 -0
  141. package/corpus/templates/clips/desktop/src/hooks/useMeetingTranscription.ts +9 -3
  142. package/corpus/templates/clips/desktop/src/lib/audio-meter.ts +51 -0
  143. package/corpus/templates/clips/desktop/src/lib/native-notification.ts +44 -0
  144. package/corpus/templates/clips/desktop/src/lib/recording-link.ts +67 -0
  145. package/corpus/templates/clips/desktop/src/overlays/live-audio-bars.tsx +35 -35
  146. package/corpus/templates/clips/desktop/src/overlays/live-transcript.tsx +3 -2
  147. package/corpus/templates/clips/desktop/src/overlays/recording-pill.tsx +47 -46
  148. package/corpus/templates/clips/desktop/src/styles.css +127 -78
  149. package/corpus/templates/clips/desktop/src-tauri/Cargo.toml +7 -0
  150. package/corpus/templates/clips/desktop/src-tauri/Info.plist +6 -0
  151. package/corpus/templates/clips/desktop/src-tauri/capabilities/default.json +1 -0
  152. package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +7 -3
  153. package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +4 -1
  154. package/corpus/templates/clips/desktop/src-tauri/src/main.rs +8 -0
  155. package/corpus/templates/clips/desktop/src-tauri/src/recording_indicator.rs +21 -10
  156. package/corpus/templates/clips/desktop/src-tauri/src/util.rs +40 -0
  157. package/corpus/templates/clips/server/db/schema.ts +25 -0
  158. package/corpus/templates/clips/server/lib/agent-views.ts +145 -0
  159. package/corpus/templates/clips/server/lib/public-agent-context.ts +7 -0
  160. package/corpus/templates/clips/server/lib/recording-share-grant.ts +79 -0
  161. package/corpus/templates/clips/server/lib/recordings.ts +51 -3
  162. package/corpus/templates/clips/server/plugins/db.ts +23 -0
  163. package/corpus/templates/clips/server/routes/api/public-recording.get.ts +49 -17
  164. package/corpus/templates/clips/shared/recording-link.ts +43 -0
  165. package/corpus/templates/clips/shared/share-attribution.ts +4 -0
  166. package/corpus/templates/clips/shared/share-dashboard-redirect.ts +42 -0
  167. package/corpus/templates/clips/shared/view-analytics.ts +26 -0
  168. package/corpus/templates/content/.agents/skills/content/SKILL.md +5 -0
  169. package/corpus/templates/content/.agents/skills/content/references/local-file-mode.md +135 -0
  170. package/corpus/templates/content/.agents/skills/document-editing/SKILL.md +12 -0
  171. package/corpus/templates/content/.agents/skills/document-editing/references/databases.md +238 -0
  172. package/corpus/templates/content/.agents/skills/document-editing/references/document-behavior.md +91 -0
  173. package/corpus/templates/content/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  174. package/corpus/templates/content/AGENTS.md +62 -583
  175. package/corpus/templates/content/_gitignore +1 -0
  176. package/corpus/templates/design/.agents/skills/creative-context/SKILL.md +11 -0
  177. package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +50 -8
  178. package/corpus/templates/design/.agents/skills/design-generation/references/code-layers.md +81 -0
  179. package/corpus/templates/design/.agents/skills/design-generation/references/code-workspace.md +42 -0
  180. package/corpus/templates/design/.agents/skills/design-generation/references/editor-extensions.md +34 -0
  181. package/corpus/templates/design/.agents/skills/responsive-breakpoints/SKILL.md +4 -1
  182. package/corpus/templates/design/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  183. package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +17 -0
  184. package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +8196 -0
  185. package/corpus/templates/design/.generated/bridge/embedded-wheel.generated.ts +265 -0
  186. package/corpus/templates/design/.generated/bridge/hit-test.generated.ts +642 -0
  187. package/corpus/templates/design/.generated/bridge/motion-preview.generated.ts +571 -0
  188. package/corpus/templates/design/.generated/bridge/nav.generated.ts +91 -0
  189. package/corpus/templates/design/.generated/bridge/sample.generated.ts +23 -0
  190. package/corpus/templates/design/.generated/bridge/shader-fill-preview.generated.ts +263 -0
  191. package/corpus/templates/design/.generated/bridge/shader-runtime.generated.ts +518 -0
  192. package/corpus/templates/design/.generated/bridge/tweak.generated.ts +20 -0
  193. package/corpus/templates/design/.generated/bridge/zoom.generated.ts +32 -0
  194. package/corpus/templates/design/AGENTS.md +88 -503
  195. package/corpus/templates/design/_gitignore +1 -0
  196. package/corpus/templates/dispatch/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  197. package/corpus/templates/dispatch/_gitignore +1 -0
  198. package/corpus/templates/dispatch/changelog/2026-07-24-signing-in-now-puts-you-in-your-companys-workspace.md +6 -0
  199. package/corpus/templates/forms/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  200. package/corpus/templates/forms/_gitignore +1 -0
  201. package/corpus/templates/forms/server/lib/public-form-ssr.ts +2 -2
  202. package/corpus/templates/macros/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  203. package/corpus/templates/macros/_gitignore +1 -0
  204. package/corpus/templates/mail/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  205. package/corpus/templates/mail/_gitignore +1 -0
  206. package/corpus/templates/plan/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  207. package/corpus/templates/plan/_gitignore +1 -0
  208. package/corpus/templates/slides/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  209. package/corpus/templates/slides/_gitignore +1 -0
  210. package/corpus/templates/slides/server/plugins/db.ts +4 -0
  211. package/corpus/templates/tasks/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  212. package/corpus/templates/tasks/AGENTS.md +1 -1
  213. package/corpus/templates/tasks/_gitignore +1 -0
  214. package/dist/a2a/activity.d.ts +4 -1
  215. package/dist/a2a/activity.d.ts.map +1 -1
  216. package/dist/a2a/activity.js +27 -16
  217. package/dist/a2a/activity.js.map +1 -1
  218. package/dist/agent/engine/builder-engine.d.ts +1 -0
  219. package/dist/agent/engine/builder-engine.d.ts.map +1 -1
  220. package/dist/agent/engine/builder-engine.js +31 -4
  221. package/dist/agent/engine/builder-engine.js.map +1 -1
  222. package/dist/agent/run-manager.d.ts.map +1 -1
  223. package/dist/agent/run-manager.js +18 -1
  224. package/dist/agent/run-manager.js.map +1 -1
  225. package/dist/agent/run-store.d.ts +1 -0
  226. package/dist/agent/run-store.d.ts.map +1 -1
  227. package/dist/agent/run-store.js +2 -1
  228. package/dist/agent/run-store.js.map +1 -1
  229. package/dist/agent/types.d.ts +12 -1
  230. package/dist/agent/types.d.ts.map +1 -1
  231. package/dist/agent/types.js +21 -1
  232. package/dist/agent/types.js.map +1 -1
  233. package/dist/chat-threads/store.d.ts +10 -0
  234. package/dist/chat-threads/store.d.ts.map +1 -1
  235. package/dist/chat-threads/store.js +41 -0
  236. package/dist/chat-threads/store.js.map +1 -1
  237. package/dist/checkpoints/index.d.ts +1 -0
  238. package/dist/checkpoints/index.d.ts.map +1 -1
  239. package/dist/checkpoints/index.js +1 -0
  240. package/dist/checkpoints/index.js.map +1 -1
  241. package/dist/checkpoints/route-match.d.ts +8 -0
  242. package/dist/checkpoints/route-match.d.ts.map +1 -0
  243. package/dist/checkpoints/route-match.js +13 -0
  244. package/dist/checkpoints/route-match.js.map +1 -0
  245. package/dist/cli/create.d.ts +35 -4
  246. package/dist/cli/create.d.ts.map +1 -1
  247. package/dist/cli/create.js +69 -19
  248. package/dist/cli/create.js.map +1 -1
  249. package/dist/cli/index.js +19 -0
  250. package/dist/cli/index.js.map +1 -1
  251. package/dist/cli/template-baseline.d.ts +54 -0
  252. package/dist/cli/template-baseline.d.ts.map +1 -0
  253. package/dist/cli/template-baseline.js +334 -0
  254. package/dist/cli/template-baseline.js.map +1 -0
  255. package/dist/cli/template-sync.d.ts +57 -0
  256. package/dist/cli/template-sync.d.ts.map +1 -0
  257. package/dist/cli/template-sync.js +787 -0
  258. package/dist/cli/template-sync.js.map +1 -0
  259. package/dist/cli/templates-meta.d.ts.map +1 -1
  260. package/dist/cli/templates-meta.js +1 -0
  261. package/dist/cli/templates-meta.js.map +1 -1
  262. package/dist/client/AssistantChat.d.ts +2 -1
  263. package/dist/client/AssistantChat.d.ts.map +1 -1
  264. package/dist/client/AssistantChat.js +38 -10
  265. package/dist/client/AssistantChat.js.map +1 -1
  266. package/dist/client/NewWorkspaceAppFlow.d.ts.map +1 -1
  267. package/dist/client/NewWorkspaceAppFlow.js +32 -2
  268. package/dist/client/NewWorkspaceAppFlow.js.map +1 -1
  269. package/dist/client/chat/message-components.d.ts +20 -0
  270. package/dist/client/chat/message-components.d.ts.map +1 -1
  271. package/dist/client/chat/message-components.js +81 -46
  272. package/dist/client/chat/message-components.js.map +1 -1
  273. package/dist/client/chat/tool-call-display.d.ts.map +1 -1
  274. package/dist/client/chat/tool-call-display.js +14 -6
  275. package/dist/client/chat/tool-call-display.js.map +1 -1
  276. package/dist/client/error-format.d.ts.map +1 -1
  277. package/dist/client/error-format.js +13 -0
  278. package/dist/client/error-format.js.map +1 -1
  279. package/dist/client/org/OrgSwitcher.d.ts +8 -1
  280. package/dist/client/org/OrgSwitcher.d.ts.map +1 -1
  281. package/dist/client/org/OrgSwitcher.js +3 -2
  282. package/dist/client/org/OrgSwitcher.js.map +1 -1
  283. package/dist/client/org/TeamPage.d.ts.map +1 -1
  284. package/dist/client/org/TeamPage.js +1 -1
  285. package/dist/client/org/TeamPage.js.map +1 -1
  286. package/dist/client/sse-event-processor.d.ts.map +1 -1
  287. package/dist/client/sse-event-processor.js +3 -0
  288. package/dist/client/sse-event-processor.js.map +1 -1
  289. package/dist/collab/awareness.d.ts +2 -2
  290. package/dist/collab/awareness.d.ts.map +1 -1
  291. package/dist/data-widgets/index.d.ts +3 -0
  292. package/dist/data-widgets/index.d.ts.map +1 -1
  293. package/dist/data-widgets/index.js +33 -0
  294. package/dist/data-widgets/index.js.map +1 -1
  295. package/dist/deploy/build.d.ts.map +1 -1
  296. package/dist/deploy/build.js +11 -7
  297. package/dist/deploy/build.js.map +1 -1
  298. package/dist/eject/provider-api-definitions.d.ts +1 -0
  299. package/dist/eject/provider-api-definitions.d.ts.map +1 -1
  300. package/dist/integrations/webhook-handler.d.ts.map +1 -1
  301. package/dist/integrations/webhook-handler.js +46 -9
  302. package/dist/integrations/webhook-handler.js.map +1 -1
  303. package/dist/notifications/routes.d.ts +3 -3
  304. package/dist/observability/routes.d.ts +3 -3
  305. package/dist/org/auto-join-domain.d.ts +3 -2
  306. package/dist/org/auto-join-domain.d.ts.map +1 -1
  307. package/dist/org/auto-join-domain.js +1 -1
  308. package/dist/org/auto-join-domain.js.map +1 -1
  309. package/dist/org/context.d.ts.map +1 -1
  310. package/dist/org/context.js +84 -28
  311. package/dist/org/context.js.map +1 -1
  312. package/dist/org/index.d.ts +1 -0
  313. package/dist/org/index.d.ts.map +1 -1
  314. package/dist/org/index.js +1 -0
  315. package/dist/org/index.js.map +1 -1
  316. package/dist/org/service-identity.d.ts +43 -0
  317. package/dist/org/service-identity.d.ts.map +1 -0
  318. package/dist/org/service-identity.js +34 -0
  319. package/dist/org/service-identity.js.map +1 -0
  320. package/dist/provider-api/actions/custom-provider-registration.d.ts +14 -14
  321. package/dist/provider-api/actions/provider-api.d.ts +13 -11
  322. package/dist/provider-api/actions/provider-api.d.ts.map +1 -1
  323. package/dist/provider-api/index.d.ts +4 -0
  324. package/dist/provider-api/index.d.ts.map +1 -1
  325. package/dist/provider-api/index.js +17 -1
  326. package/dist/provider-api/index.js.map +1 -1
  327. package/dist/resources/handlers.d.ts +1 -1
  328. package/dist/scripts/docs/search.d.ts.map +1 -1
  329. package/dist/scripts/docs/search.js +12 -1
  330. package/dist/scripts/docs/search.js.map +1 -1
  331. package/dist/server/agent-chat/context-tools.d.ts.map +1 -1
  332. package/dist/server/agent-chat/context-tools.js +3 -3
  333. package/dist/server/agent-chat/context-tools.js.map +1 -1
  334. package/dist/server/agent-chat/framework-prompts.d.ts +8 -3
  335. package/dist/server/agent-chat/framework-prompts.d.ts.map +1 -1
  336. package/dist/server/agent-chat/framework-prompts.js +33 -62
  337. package/dist/server/agent-chat/framework-prompts.js.map +1 -1
  338. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  339. package/dist/server/agent-chat-plugin.js +16 -10
  340. package/dist/server/agent-chat-plugin.js.map +1 -1
  341. package/dist/server/agents-bundle.d.ts +18 -0
  342. package/dist/server/agents-bundle.d.ts.map +1 -1
  343. package/dist/server/agents-bundle.js +70 -4
  344. package/dist/server/agents-bundle.js.map +1 -1
  345. package/dist/server/auth.d.ts.map +1 -1
  346. package/dist/server/auth.js +4 -3
  347. package/dist/server/auth.js.map +1 -1
  348. package/dist/server/builder-browser.d.ts.map +1 -1
  349. package/dist/server/builder-browser.js +43 -19
  350. package/dist/server/builder-browser.js.map +1 -1
  351. package/dist/server/core-routes-plugin.js +2 -2
  352. package/dist/server/core-routes-plugin.js.map +1 -1
  353. package/dist/server/credential-provider.d.ts +38 -2
  354. package/dist/server/credential-provider.d.ts.map +1 -1
  355. package/dist/server/credential-provider.js +142 -64
  356. package/dist/server/credential-provider.js.map +1 -1
  357. package/dist/server/index.d.ts +1 -1
  358. package/dist/server/index.d.ts.map +1 -1
  359. package/dist/server/index.js +1 -1
  360. package/dist/server/index.js.map +1 -1
  361. package/dist/server/prompts/framework-core-compact.d.ts +1 -1
  362. package/dist/server/prompts/framework-core-compact.d.ts.map +1 -1
  363. package/dist/server/prompts/framework-core-compact.js +7 -13
  364. package/dist/server/prompts/framework-core-compact.js.map +1 -1
  365. package/dist/server/prompts/framework-core.d.ts +1 -1
  366. package/dist/server/prompts/framework-core.d.ts.map +1 -1
  367. package/dist/server/prompts/framework-core.js +10 -21
  368. package/dist/server/prompts/framework-core.js.map +1 -1
  369. package/dist/server/prompts/index.d.ts +1 -1
  370. package/dist/server/prompts/index.d.ts.map +1 -1
  371. package/dist/server/prompts/index.js +1 -1
  372. package/dist/server/prompts/index.js.map +1 -1
  373. package/dist/server/prompts/shared-rules.d.ts +16 -10
  374. package/dist/server/prompts/shared-rules.d.ts.map +1 -1
  375. package/dist/server/prompts/shared-rules.js +19 -10
  376. package/dist/server/prompts/shared-rules.js.map +1 -1
  377. package/dist/server/ssr-handler.d.ts +1 -1
  378. package/dist/server/ssr-handler.d.ts.map +1 -1
  379. package/dist/server/ssr-handler.js +10 -3
  380. package/dist/server/ssr-handler.js.map +1 -1
  381. package/dist/server/transcribe-voice.d.ts +1 -1
  382. package/dist/settings/user-settings.d.ts.map +1 -1
  383. package/dist/settings/user-settings.js +13 -1
  384. package/dist/settings/user-settings.js.map +1 -1
  385. package/dist/shared/cache-control.d.ts +52 -0
  386. package/dist/shared/cache-control.d.ts.map +1 -1
  387. package/dist/shared/cache-control.js +107 -0
  388. package/dist/shared/cache-control.js.map +1 -1
  389. package/dist/templates/chat/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  390. package/dist/templates/chat/_gitignore +1 -0
  391. package/dist/templates/default/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  392. package/dist/templates/headless/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  393. package/dist/templates/workspace-core/.agents/skills/performance/SKILL.md +19 -0
  394. package/dist/templates/workspace-core/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  395. package/dist/templates/workspace-core/.agents/skills/visual-answer/SKILL.md +1 -0
  396. package/dist/vite/agents-bundle-plugin.d.ts.map +1 -1
  397. package/dist/vite/agents-bundle-plugin.js +8 -7
  398. package/dist/vite/agents-bundle-plugin.js.map +1 -1
  399. package/dist/vite/client.d.ts.map +1 -1
  400. package/dist/vite/client.js +2 -0
  401. package/dist/vite/client.js.map +1 -1
  402. package/docs/content/actions.mdx +2 -2
  403. package/docs/content/agent-surfaces.mdx +1 -1
  404. package/docs/content/authentication.mdx +2 -0
  405. package/docs/content/deployment.mdx +36 -0
  406. package/docs/content/getting-started.mdx +477 -115
  407. package/docs/content/http-api.mdx +266 -0
  408. package/docs/content/syncing-template-changes.mdx +159 -0
  409. package/package.json +4 -3
  410. package/src/a2a/activity.ts +38 -27
  411. package/src/agent/engine/builder-engine.ts +35 -4
  412. package/src/agent/run-manager.ts +20 -1
  413. package/src/agent/run-store.ts +4 -1
  414. package/src/agent/types.ts +28 -8
  415. package/src/chat-threads/store.ts +45 -0
  416. package/src/checkpoints/index.ts +2 -0
  417. package/src/checkpoints/route-match.ts +13 -0
  418. package/src/cli/create.ts +105 -17
  419. package/src/cli/index.ts +20 -0
  420. package/src/cli/template-baseline.ts +410 -0
  421. package/src/cli/template-sync.ts +1004 -0
  422. package/src/cli/templates-meta.ts +1 -0
  423. package/src/client/AssistantChat.tsx +38 -12
  424. package/src/client/NewWorkspaceAppFlow.tsx +75 -10
  425. package/src/client/chat/message-components.tsx +127 -66
  426. package/src/client/chat/tool-call-display.tsx +29 -5
  427. package/src/client/error-format.ts +18 -0
  428. package/src/client/org/OrgSwitcher.tsx +30 -8
  429. package/src/client/org/TeamPage.tsx +7 -6
  430. package/src/client/sse-event-processor.ts +3 -0
  431. package/src/data-widgets/index.ts +41 -0
  432. package/src/deploy/build.ts +11 -9
  433. package/src/integrations/webhook-handler.ts +63 -9
  434. package/src/org/auto-join-domain.ts +4 -3
  435. package/src/org/context.ts +108 -39
  436. package/src/org/index.ts +5 -0
  437. package/src/org/service-identity.ts +60 -0
  438. package/src/provider-api/index.ts +22 -1
  439. package/src/scripts/docs/search.ts +12 -1
  440. package/src/server/__snapshots__/agent-chat-plugin.surface.spec.ts.snap +25 -36
  441. package/src/server/agent-chat/context-tools.ts +9 -4
  442. package/src/server/agent-chat/framework-prompts.ts +38 -66
  443. package/src/server/agent-chat-plugin.ts +17 -10
  444. package/src/server/agents-bundle.ts +84 -5
  445. package/src/server/auth.ts +4 -3
  446. package/src/server/builder-browser.ts +47 -19
  447. package/src/server/core-routes-plugin.ts +2 -2
  448. package/src/server/credential-provider.ts +209 -68
  449. package/src/server/index.ts +3 -0
  450. package/src/server/prompts/framework-core-compact.ts +6 -13
  451. package/src/server/prompts/framework-core.ts +9 -21
  452. package/src/server/prompts/index.ts +0 -1
  453. package/src/server/prompts/shared-rules.ts +19 -11
  454. package/src/server/ssr-handler.ts +13 -2
  455. package/src/settings/user-settings.ts +13 -1
  456. package/src/shared/cache-control.ts +141 -0
  457. package/src/templates/chat/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  458. package/src/templates/chat/_gitignore +1 -0
  459. package/src/templates/default/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  460. package/src/templates/headless/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  461. package/src/templates/workspace-core/.agents/skills/performance/SKILL.md +19 -0
  462. package/src/templates/workspace-core/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  463. package/src/templates/workspace-core/.agents/skills/visual-answer/SKILL.md +1 -0
  464. package/src/vite/agents-bundle-plugin.ts +7 -6
  465. package/src/vite/client.ts +5 -0
@@ -0,0 +1,110 @@
1
+ export type CaptureHostApp = {
2
+ /** The name macOS lists this app under in Privacy & Security. */
3
+ name: string;
4
+ kind: "desktop" | "browser";
5
+ };
6
+
7
+ export type CapturePermissionPane = "screen" | "camera" | "microphone";
8
+
9
+ export type CaptureHostEnv = {
10
+ userAgent: string;
11
+ isTauri: boolean;
12
+ isBrave: boolean;
13
+ isArc: boolean;
14
+ };
15
+
16
+ const UNKNOWN_BROWSER = "your browser";
17
+
18
+ // Arc does not identify itself in the user agent, but it injects its palette
19
+ // variables onto the document element, so a browser reporting plain Chrome
20
+ // while exposing --arc-palette-title is Arc.
21
+ function detectArc(): boolean {
22
+ if (typeof window === "undefined" || typeof document === "undefined") {
23
+ return false;
24
+ }
25
+ try {
26
+ return Boolean(
27
+ window
28
+ .getComputedStyle(document.documentElement)
29
+ .getPropertyValue("--arc-palette-title")
30
+ .trim(),
31
+ );
32
+ } catch {
33
+ return false;
34
+ }
35
+ }
36
+
37
+ export function readCaptureHostEnv(): CaptureHostEnv {
38
+ const tauri =
39
+ typeof window === "undefined"
40
+ ? undefined
41
+ : (window as unknown as {
42
+ __TAURI_INTERNALS__?: unknown;
43
+ __TAURI__?: unknown;
44
+ });
45
+ return {
46
+ userAgent: typeof navigator === "undefined" ? "" : navigator.userAgent,
47
+ isTauri: Boolean(tauri?.__TAURI_INTERNALS__ || tauri?.__TAURI__),
48
+ isBrave:
49
+ typeof navigator !== "undefined" &&
50
+ Boolean((navigator as { brave?: unknown }).brave),
51
+ isArc: detectArc(),
52
+ };
53
+ }
54
+
55
+ export function detectCaptureHostApp(env: CaptureHostEnv): CaptureHostApp {
56
+ if (env.isTauri) return { name: "Clips", kind: "desktop" };
57
+ if (/Electron/i.test(env.userAgent)) {
58
+ return { name: "Agent Native", kind: "desktop" };
59
+ }
60
+ const ua = env.userAgent;
61
+ const name = /Vivaldi/i.test(ua)
62
+ ? "Vivaldi"
63
+ : /OPR\//i.test(ua)
64
+ ? "Opera"
65
+ : /Edg\//i.test(ua)
66
+ ? "Microsoft Edge"
67
+ : env.isBrave
68
+ ? "Brave Browser"
69
+ : env.isArc
70
+ ? "Arc"
71
+ : /Firefox\//i.test(ua)
72
+ ? "Firefox"
73
+ : /Chrome\//i.test(ua)
74
+ ? "Google Chrome"
75
+ : /Safari\//i.test(ua)
76
+ ? "Safari"
77
+ : UNKNOWN_BROWSER;
78
+ return { name, kind: "browser" };
79
+ }
80
+
81
+ /**
82
+ * macOS grants screen, camera, and microphone access per application, so
83
+ * permission guidance has to name the app hosting the recorder — Clips itself
84
+ * never appears in System Settings when it runs in a browser tab.
85
+ */
86
+ export function getCaptureHostApp(): CaptureHostApp {
87
+ return detectCaptureHostApp(readCaptureHostEnv());
88
+ }
89
+
90
+ export function macSettingsPath(pane: CapturePermissionPane): string {
91
+ const label =
92
+ pane === "screen"
93
+ ? "Screen & System Audio Recording"
94
+ : pane === "camera"
95
+ ? "Camera"
96
+ : "Microphone";
97
+ return `System Settings > Privacy & Security > ${label}`;
98
+ }
99
+
100
+ export function macPermissionGuidanceFor(
101
+ pane: CapturePermissionPane,
102
+ host: CaptureHostApp = getCaptureHostApp(),
103
+ ): string {
104
+ const where = macSettingsPath(pane);
105
+ if (host.kind === "desktop") {
106
+ return `macOS grants this per app. Turn on ${host.name} in ${where}, then quit and reopen ${host.name} and start the recording again.`;
107
+ }
108
+ const subject = host.name === UNKNOWN_BROWSER ? "it" : host.name;
109
+ return `macOS grants this per app, not per site, so Clips is never listed by name — look for ${host.name} instead. Turn ${subject} on in ${where}, then quit and reopen it. If it is not listed yet, add it with the + button.`;
110
+ }
@@ -0,0 +1,32 @@
1
+ import { appBasePath } from "@agent-native/core/client/api-path";
2
+ import { writeClipboardText } from "@agent-native/core/client/clipboard";
3
+ import {
4
+ buildRecordingShareUrl,
5
+ recordingSharePath,
6
+ } from "@shared/recording-link";
7
+
8
+ /** Absolute, ready-to-paste public share URL for a recording. */
9
+ export function recordingShareUrl(
10
+ recordingId: string,
11
+ ownerId?: string | null,
12
+ ): string {
13
+ if (typeof window === "undefined") return recordingSharePath(recordingId);
14
+ return buildRecordingShareUrl({
15
+ recordingId,
16
+ origin: window.location.origin,
17
+ basePath: appBasePath(),
18
+ ownerId,
19
+ });
20
+ }
21
+
22
+ /**
23
+ * Copy a recording's public share link. Returns whether the write actually
24
+ * landed so callers can tell the user the truth instead of assuming a silent
25
+ * `navigator.clipboard` rejection was a success.
26
+ */
27
+ export async function copyRecordingShareLink(
28
+ recordingId: string,
29
+ ownerId?: string | null,
30
+ ): Promise<boolean> {
31
+ return writeClipboardText(recordingShareUrl(recordingId, ownerId));
32
+ }
@@ -1,3 +1,5 @@
1
+ import { appPath } from "@agent-native/core/client/api-path";
2
+ import { writeClipboardText } from "@agent-native/core/client/clipboard";
1
3
  import {
2
4
  useActionMutation,
3
5
  useActionQuery,
@@ -99,6 +101,7 @@ interface Meeting {
99
101
  recordingId?: string | null;
100
102
  recordingDurationMs?: number | null;
101
103
  transcriptStatus?: "pending" | "ready" | "failed" | "in_progress" | string;
104
+ visibility?: "private" | "org" | "public" | null;
102
105
  shareTranscript?: boolean | null;
103
106
  summaryMd?: string | null;
104
107
  userNotesMd?: string | null;
@@ -542,6 +545,30 @@ export default function MeetingDetailRoute() {
542
545
 
543
546
  const handleEndMeeting = () => {
544
547
  if (!meeting) return;
548
+ // The meeting share link is valid independently of the stop call, so copy
549
+ // it while the user's click still counts as activation instead of waiting
550
+ // on the mutation. The public meeting page resolves `visibility = public`
551
+ // rows only — anything else would hand the user a link that 404s for the
552
+ // people they send it to.
553
+ if (meeting.visibility === "public" && typeof window !== "undefined") {
554
+ const shareUrl = `${window.location.origin}${appPath(
555
+ `/share/meeting/${meeting.id}`,
556
+ )}`;
557
+ void writeClipboardText(shareUrl).then((copied) => {
558
+ if (copied) {
559
+ toast.success(t("recordRoute.linkCopied"));
560
+ return;
561
+ }
562
+ toast(t("meetingDetail.share"), {
563
+ action: {
564
+ label: t("recordRoute.copyLinkAction"),
565
+ onClick: () => {
566
+ void writeClipboardText(shareUrl);
567
+ },
568
+ },
569
+ });
570
+ });
571
+ }
545
572
  // Optimistic: flip the live badge off immediately rather than waiting
546
573
  // for the next 2s poll — stop-meeting-recording stamps actualEnd and
547
574
  // flips transcriptStatus server-side.
@@ -1,5 +1,6 @@
1
1
  import { AgentPanel } from "@agent-native/core/client/agent-chat";
2
2
  import { appPath, agentNativePath } from "@agent-native/core/client/api-path";
3
+ import { writeClipboardText } from "@agent-native/core/client/clipboard";
3
4
  import {
4
5
  useActionMutation,
5
6
  useActionQuery,
@@ -19,7 +20,12 @@ import {
19
20
  isLoomEmbedBackedRecording,
20
21
  isLoomRecordingSource,
21
22
  } from "@shared/loom";
22
- import { CLIP_SHARE_REF, REF_PARAM } from "@shared/share-attribution";
23
+ import {
24
+ CLIP_SHARE_REF,
25
+ DASHBOARD_REDIRECT_PARAM,
26
+ DASHBOARD_REDIRECT_VALUE,
27
+ REF_PARAM,
28
+ } from "@shared/share-attribution";
23
29
  import {
24
30
  IconShare3,
25
31
  IconArrowLeft,
@@ -50,6 +56,7 @@ import { CommentsPanel } from "@/components/player/comments-panel";
50
56
  import { RecordingOptionsMenu } from "@/components/player/delete-recording-menu";
51
57
  import { InsightsPanel } from "@/components/player/insights-panel";
52
58
  import { ReactionsTray } from "@/components/player/reactions-tray";
59
+ import { RecordingViewsBadge } from "@/components/player/recording-views-badge";
53
60
  import { SettingsPanel } from "@/components/player/settings-panel";
54
61
  import { ShareRecordingPopover } from "@/components/player/share-dialog";
55
62
  import {
@@ -85,6 +92,7 @@ import { usePlayerShortcuts } from "@/hooks/use-player-shortcuts";
85
92
  import { useViewTracking } from "@/hooks/use-view-tracking";
86
93
  import enMessages from "@/i18n/en-US";
87
94
  import { parsePlaybackSpeed } from "@/lib/playback-speed";
95
+ import { recordingShareUrl } from "@/lib/recording-link";
88
96
  import { isStorageSetupFailureReason } from "@/lib/storage-failures";
89
97
  import { cn } from "@/lib/utils";
90
98
 
@@ -253,6 +261,18 @@ export default function RecordingPage() {
253
261
  }
254
262
  return currentMs;
255
263
  }, [currentMs]);
264
+ // The compact layout stacks the panel below the video, so switching tabs
265
+ // alone leaves the user looking at the player. Desktop always renders the
266
+ // side aside, so nothing to scroll there.
267
+ const openInsightsPanel = useCallback(() => {
268
+ setPanel("insights");
269
+ if (!isCompactLayout) return;
270
+ requestAnimationFrame(() => {
271
+ document
272
+ .getElementById("clip-activity-panel")
273
+ ?.scrollIntoView({ block: "start" });
274
+ });
275
+ }, [isCompactLayout]);
256
276
  const transcriptKickedRef = useRef<string | null>(null);
257
277
  // When the recording lands in the processing state but never flips to
258
278
  // 'ready', stop spinning forever and surface an error banner so the user
@@ -366,8 +386,11 @@ export default function RecordingPage() {
366
386
  // password.
367
387
  useEffect(() => {
368
388
  if (!recordingId || !playerDataForbidden) return;
389
+ const shareParams = new URLSearchParams();
390
+ shareParams.set(REF_PARAM, CLIP_SHARE_REF);
391
+ shareParams.set(DASHBOARD_REDIRECT_PARAM, DASHBOARD_REDIRECT_VALUE);
369
392
  navigate(
370
- `/share/${encodeURIComponent(recordingId)}?${REF_PARAM}=${CLIP_SHARE_REF}`,
393
+ `/share/${encodeURIComponent(recordingId)}?${shareParams.toString()}`,
371
394
  {
372
395
  replace: true,
373
396
  },
@@ -408,23 +431,21 @@ export default function RecordingPage() {
408
431
  const visibleTitle = recording
409
432
  ? displayRecordingTitle(recording.title)
410
433
  : "Untitled Clip";
434
+ // Attribution `via` must never point at someone who isn't the owner, so it
435
+ // is only tagged when the viewer is the owner (same rule as the share dialog).
436
+ const shareViaId =
437
+ role === "owner" ? (session?.userId ?? undefined) : undefined;
411
438
  const pendingShareUrl = useMemo(() => {
412
439
  if (!recordingId || typeof window === "undefined") return "";
413
- return new URL(
414
- appPath(`/share/${encodeURIComponent(recordingId)}`),
415
- window.location.origin,
416
- ).toString();
417
- }, [recordingId]);
440
+ return recordingShareUrl(recordingId, shareViaId);
441
+ }, [recordingId, shareViaId]);
418
442
  const copyPendingShareLink = useCallback(async () => {
419
443
  if (!pendingShareUrl) return;
420
- try {
421
- await navigator.clipboard.writeText(pendingShareUrl);
422
- setPendingLinkCopied(true);
423
- window.setTimeout(() => setPendingLinkCopied(false), 1400);
424
- } catch {
425
- // The full Share popover remains available when clipboard permission is
426
- // unavailable, so a denied clipboard write does not block the page.
427
- }
444
+ // The full Share popover remains available when clipboard permission is
445
+ // unavailable, so a denied clipboard write does not block the page.
446
+ if (!(await writeClipboardText(pendingShareUrl))) return;
447
+ setPendingLinkCopied(true);
448
+ window.setTimeout(() => setPendingLinkCopied(false), 1400);
428
449
  }, [pendingShareUrl]);
429
450
  useEffect(() => {
430
451
  if (!recording?.id) return;
@@ -1336,6 +1357,16 @@ export default function RecordingPage() {
1336
1357
  ) : null}
1337
1358
  </div>
1338
1359
 
1360
+ {!editing ? (
1361
+ <RecordingViewsBadge
1362
+ recordingId={recording.id}
1363
+ viewCount={playerDataQ.data?.viewCount ?? 0}
1364
+ canViewDetails={canEdit}
1365
+ onOpenInsights={openInsightsPanel}
1366
+ className="shrink-0"
1367
+ />
1368
+ ) : null}
1369
+
1339
1370
  {canUseNativeEditor ? (
1340
1371
  <Button
1341
1372
  variant={editing ? "secondary" : "outline"}
@@ -46,6 +46,10 @@ import {
46
46
  createBrowserDiagnosticsCapture,
47
47
  type BrowserDiagnosticsCapture,
48
48
  } from "@/lib/browser-diagnostics-capture";
49
+ import {
50
+ getCaptureHostApp,
51
+ macPermissionGuidanceFor,
52
+ } from "@/lib/capture-permissions";
49
53
  import {
50
54
  COMPRESS_THRESHOLD_BYTES,
51
55
  COMPRESSION_ENABLED,
@@ -61,6 +65,7 @@ import {
61
65
  loadRecorderPreferences,
62
66
  saveRecorderPreferences,
63
67
  } from "@/lib/recorder-preferences";
68
+ import { copyRecordingShareLink } from "@/lib/recording-link";
64
69
  import {
65
70
  buildCaptureTitle,
66
71
  defaultRecordingTitle,
@@ -87,19 +92,6 @@ async function writeAppState(key: string, value: unknown): Promise<void> {
87
92
  );
88
93
  }
89
94
 
90
- function recordingLink(recordingId: string): string {
91
- const path = `${appBasePath()}/r/${encodeURIComponent(recordingId)}`;
92
- if (typeof window === "undefined") return path;
93
- return new URL(path, window.location.origin).toString();
94
- }
95
-
96
- async function copyRecordingLink(recordingId: string): Promise<void> {
97
- if (typeof navigator === "undefined") return;
98
- if (!navigator.clipboard?.writeText) return;
99
- await navigator.clipboard
100
- .writeText(recordingLink(recordingId))
101
- .catch(() => undefined);
102
- }
103
95
  import {
104
96
  bugReportTitle,
105
97
  parseBugReportContext,
@@ -368,27 +360,30 @@ function permissionGuidance(
368
360
  return "Browser site permissions are not the blocker here. Open Clips directly in a browser tab, or use an app frame that delegates the selected capture sources.";
369
361
  }
370
362
  if (isScreenPermissionError(message)) {
371
- if (isEmbeddedWindow()) {
363
+ // The desktop shell hosts the recorder in its own webview, so "open it in a
364
+ // real tab" is not advice a desktop user can act on.
365
+ if (isEmbeddedWindow() && getCaptureHostApp().kind !== "desktop") {
372
366
  return "The web client is running Clips inside a frame. Open the recorder in its own tab, then start recording; Chrome can block screen sharing in embedded pages even when macOS access is enabled.";
373
367
  }
374
368
  if (isMacPlatform()) {
375
- return "Chrome can have Camera and Microphone allowed while macOS still blocks screen capture. Enable your browser in System Settings > Privacy & Security > Screen & System Audio Recording, then quit and reopen it.";
369
+ return `Camera and Microphone can be allowed while macOS still blocks screen capture. ${macPermissionGuidanceFor("screen")}`;
376
370
  }
377
371
  return "Choose a source in the browser screen picker. If it still fails, check this site's browser permissions and reload Clips.";
378
372
  }
379
373
  if (isCameraPermissionError(message)) {
380
374
  if (isMacPlatform()) {
381
- return "Allow Camera in this site's browser settings and in macOS System Settings > Privacy & Security > Camera, then reload Clips.";
375
+ return `Allow Camera for this site first. ${macPermissionGuidanceFor("camera")}`;
382
376
  }
383
377
  return "Open this site's browser settings, allow Camera, then reload Clips.";
384
378
  }
385
379
  if (isMicrophonePermissionError(message)) {
386
380
  if (isMacPlatform()) {
387
- return "Allow Microphone in this site's browser settings and in macOS System Settings > Privacy & Security > Microphone, then reload Clips.";
381
+ return `Allow Microphone for this site first. ${macPermissionGuidanceFor("microphone")}`;
388
382
  }
389
383
  return "Open this site's browser settings, allow Microphone, then reload Clips.";
390
384
  }
391
385
  if (isMacPlatform()) {
386
+ const host = getCaptureHostApp();
392
387
  const labels = getModePermissionLabels(opts?.mode, opts?.micDeviceId);
393
388
  if (labels.length > 0) {
394
389
  const readable = labels
@@ -400,9 +395,9 @@ function permissionGuidance(
400
395
  : "Microphone",
401
396
  )
402
397
  .join(", ");
403
- return `Check this site's browser permissions first. If it still fails, enable ${readable} for your browser in macOS System Settings > Privacy & Security, then quit and reopen it.`;
398
+ return `Check this site's permissions first. If it still fails, turn on ${host.name} under ${readable} in macOS System Settings > Privacy & Security, then quit and reopen it. Clips is never listed there — macOS grants access to ${host.name}.`;
404
399
  }
405
- return "Check this site's browser permissions first. If it still fails, open macOS System Settings > Privacy & Security for your browser, then quit and reopen it.";
400
+ return `Check this site's permissions first. If it still fails, turn on ${host.name} in macOS System Settings > Privacy & Security, then quit and reopen it.`;
406
401
  }
407
402
  return "Open this site's browser settings and allow the selected capture sources, then reload this page.";
408
403
  }
@@ -511,7 +506,7 @@ function friendlyRecordingErrorMessage(error: string): string {
511
506
  }
512
507
  if (isScreenPermissionError(error)) {
513
508
  if (isMacPlatform()) {
514
- return "Clips could not start screen capture. Enable screen recording for your browser, then try again.";
509
+ return `Clips could not start screen capture. macOS is blocking screen recording for ${getCaptureHostApp().name}.`;
515
510
  }
516
511
  return "Clips could not start screen capture. Allow screen sharing for this site, then try again.";
517
512
  }
@@ -629,7 +624,10 @@ function RecordingErrorCard({
629
624
  const permissionError = !uploadFailure && isPermissionError(error);
630
625
  const policyError = !uploadFailure && isPolicyPermissionError(error);
631
626
  const embeddedScreenError =
632
- !uploadFailure && isEmbeddedWindow() && isScreenPermissionError(error);
627
+ !uploadFailure &&
628
+ isEmbeddedWindow() &&
629
+ getCaptureHostApp().kind !== "desktop" &&
630
+ isScreenPermissionError(error);
633
631
  const settings = permissionError
634
632
  ? getModePermissionLabels(mode, micDeviceId)
635
633
  : [];
@@ -766,6 +764,27 @@ export default function RecordRoute() {
766
764
  const t = useT();
767
765
  const navigate = useNavigate();
768
766
  const location = useLocation();
767
+ // A clipboard write can be refused (insecure origin, unfocused document, no
768
+ // transient activation). Never let the success toast imply the link was
769
+ // copied when it wasn't — offer a click instead, which restores the user
770
+ // gesture the browser is asking for.
771
+ const showSavedToast = useCallback(
772
+ (message: string, copied: boolean, recordingId: string) => {
773
+ if (copied) {
774
+ toast.success(message, { description: t("recordRoute.linkCopied") });
775
+ return;
776
+ }
777
+ toast.success(message, {
778
+ action: {
779
+ label: t("recordRoute.copyLinkAction"),
780
+ onClick: () => {
781
+ void copyRecordingShareLink(recordingId);
782
+ },
783
+ },
784
+ });
785
+ },
786
+ [t],
787
+ );
769
788
  const [uiState, setUiState] = useState<UiState>("idle");
770
789
  const [error, setError] = useState<string | null>(null);
771
790
  const [isPaused, setIsPaused] = useState(false);
@@ -1723,8 +1742,13 @@ export default function RecordRoute() {
1723
1742
  description: t("recordRoute.connectStorageToFinish"),
1724
1743
  duration: 12_000,
1725
1744
  });
1745
+ } else if (createdId && !reportContext) {
1746
+ showSavedToast(
1747
+ t("recordRoute.videoUploaded"),
1748
+ await copyRecordingShareLink(createdId),
1749
+ createdId,
1750
+ );
1726
1751
  } else {
1727
- if (createdId && !reportContext) await copyRecordingLink(createdId);
1728
1752
  toast.success(t("recordRoute.videoUploaded"));
1729
1753
  }
1730
1754
  if (reportContext && createdId) {
@@ -1789,7 +1813,7 @@ export default function RecordRoute() {
1789
1813
  setUploadProgress(null);
1790
1814
  }
1791
1815
  },
1792
- [markStorageConfigured, navigate, probeVideoMetadata],
1816
+ [markStorageConfigured, navigate, probeVideoMetadata, showSavedToast],
1793
1817
  );
1794
1818
 
1795
1819
  const importLoom = useCallback(
@@ -1827,8 +1851,11 @@ export default function RecordRoute() {
1827
1851
  duration: 12_000,
1828
1852
  });
1829
1853
  } else {
1830
- await copyRecordingLink(recordingId);
1831
- toast.success(t("recordRoute.loomImported"));
1854
+ showSavedToast(
1855
+ t("recordRoute.loomImported"),
1856
+ await copyRecordingShareLink(recordingId),
1857
+ recordingId,
1858
+ );
1832
1859
  }
1833
1860
  await writeAppState("navigate", {
1834
1861
  view: "recording",
@@ -1845,7 +1872,7 @@ export default function RecordRoute() {
1845
1872
  setLoomImporting(false);
1846
1873
  }
1847
1874
  },
1848
- [folderIdFromUrl, navigate, spaceIdFromUrl],
1875
+ [folderIdFromUrl, navigate, spaceIdFromUrl, showSavedToast],
1849
1876
  );
1850
1877
 
1851
1878
  const saveBrowserDiagnostics = useCallback(
@@ -1944,7 +1971,14 @@ export default function RecordRoute() {
1944
1971
  // Stop / upload / navigate.
1945
1972
  // -------------------------------------------------------------------------
1946
1973
  const finishSavedRecording = useCallback(
1947
- async (recordingId: string, result: RecorderFinalizeResult) => {
1974
+ async (
1975
+ recordingId: string,
1976
+ result: RecorderFinalizeResult,
1977
+ // Started by the caller the moment the recording became durable, so the
1978
+ // clipboard write happens closer to the user's stop gesture than to the
1979
+ // end of the post-save bookkeeping.
1980
+ pendingCopy?: Promise<boolean>,
1981
+ ) => {
1948
1982
  // Recording is fully saved — clear refs so that if anything below throws
1949
1983
  // and the user clicks "Try again", doCancel() won't trash a good recording.
1950
1984
  pendingRef.current = null;
@@ -1960,9 +1994,14 @@ export default function RecordRoute() {
1960
1994
  description: t("recordRoute.connectStorageToFinish"),
1961
1995
  duration: 12_000,
1962
1996
  });
1963
- } else {
1964
- if (!reportContext) await copyRecordingLink(recordingId);
1997
+ } else if (reportContext) {
1965
1998
  toast.success(t("recordRoute.recordingSaved"));
1999
+ } else {
2000
+ showSavedToast(
2001
+ t("recordRoute.recordingSaved"),
2002
+ await (pendingCopy ?? copyRecordingShareLink(recordingId)),
2003
+ recordingId,
2004
+ );
1966
2005
  }
1967
2006
 
1968
2007
  if (reportContext) {
@@ -1986,7 +2025,7 @@ export default function RecordRoute() {
1986
2025
  navigate(`/r/${recordingId}`);
1987
2026
  }, 50);
1988
2027
  },
1989
- [navigate],
2028
+ [navigate, showSavedToast],
1990
2029
  );
1991
2030
 
1992
2031
  const doStop = useCallback(async () => {
@@ -2056,8 +2095,15 @@ export default function RecordRoute() {
2056
2095
  }
2057
2096
 
2058
2097
  const stopResult = await engine.stop();
2098
+ // The recording is durable here; saveBrowserDiagnostics is one more
2099
+ // round trip. Start the clipboard write first so it isn't pushed even
2100
+ // further from the stop gesture that authorized it.
2101
+ const pendingCopy =
2102
+ stopResult.waitingForStorage || bugReportContextRef.current
2103
+ ? undefined
2104
+ : copyRecordingShareLink(pending.id).catch(() => false);
2059
2105
  await saveBrowserDiagnostics(pending.id);
2060
- await finishSavedRecording(pending.id, stopResult);
2106
+ await finishSavedRecording(pending.id, stopResult, pendingCopy);
2061
2107
  } catch (err) {
2062
2108
  const message =
2063
2109
  err instanceof Error ? err.message : t("recordRoute.uploadFailed");