@agent-native/core 0.137.7 → 0.138.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 (446) hide show
  1. package/agent-native.eject.json +2 -0
  2. package/corpus/README.md +1 -1
  3. package/corpus/templates/analytics/.agents/skills/agent-native-docs/SKILL.md +23 -3
  4. package/corpus/templates/analytics/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
  5. package/corpus/templates/analytics/.agents/skills/data-querying/SKILL.md +15 -0
  6. package/corpus/templates/analytics/.agents/skills/frontend-design/SKILL.md +23 -2
  7. package/corpus/templates/analytics/.agents/skills/frontend-design/references/visual-direction.md +99 -0
  8. package/corpus/templates/analytics/AGENTS.md +2 -2
  9. package/corpus/templates/analytics/actions/get-first-party-analytics-health.ts +65 -0
  10. package/corpus/templates/analytics/actions/provider-api-catalog.ts +3 -6
  11. package/corpus/templates/analytics/actions/provider-api-docs.ts +3 -6
  12. package/corpus/templates/analytics/actions/provider-api-request.ts +3 -6
  13. package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +3 -3
  14. package/corpus/templates/analytics/agent-native.json +12 -0
  15. package/corpus/templates/analytics/app/i18n-data.ts +162 -0
  16. package/corpus/templates/analytics/app/pages/DataSources.tsx +126 -1
  17. package/corpus/templates/analytics/changelog/2026-08-05-analytics-now-flags-neon-pressure-and-guides-high-volume-tra.md +6 -0
  18. package/corpus/templates/analytics/changelog/2026-08-05-first-party-analytics-uses-compact-rollups-for-faster-usage-.md +6 -0
  19. package/corpus/templates/analytics/server/db/schema.ts +52 -0
  20. package/corpus/templates/analytics/server/lib/credential-keys.ts +3 -0
  21. package/corpus/templates/analytics/server/lib/first-party-analytics-health.ts +397 -0
  22. package/corpus/templates/analytics/server/lib/first-party-analytics-rollups.ts +182 -0
  23. package/corpus/templates/analytics/server/lib/first-party-analytics.ts +86 -15
  24. package/corpus/templates/analytics/server/lib/provider-api.ts +20 -1
  25. package/corpus/templates/analytics/server/lib/replay-storage.ts +1 -1
  26. package/corpus/templates/analytics/server/plugins/agent-chat.ts +1 -0
  27. package/corpus/templates/analytics/server/plugins/db.ts +60 -0
  28. package/corpus/templates/assets/.agents/skills/agent-native-docs/SKILL.md +23 -3
  29. package/corpus/templates/assets/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
  30. package/corpus/templates/assets/.agents/skills/frontend-design/SKILL.md +23 -2
  31. package/corpus/templates/assets/.agents/skills/frontend-design/references/visual-direction.md +99 -0
  32. package/corpus/templates/assets/agent-native.json +12 -0
  33. package/corpus/templates/assets/server/lib/generation.ts +8 -8
  34. package/corpus/templates/assets/server/lib/storage.ts +1 -1
  35. package/corpus/templates/assets/server/plugins/onboarding.ts +1 -1
  36. package/corpus/templates/brain/.agents/skills/agent-native-docs/SKILL.md +23 -3
  37. package/corpus/templates/brain/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
  38. package/corpus/templates/brain/.agents/skills/frontend-design/SKILL.md +23 -2
  39. package/corpus/templates/brain/.agents/skills/frontend-design/references/visual-direction.md +99 -0
  40. package/corpus/templates/brain/agent-native.json +12 -0
  41. package/corpus/templates/calendar/.agents/skills/agent-native-docs/SKILL.md +23 -3
  42. package/corpus/templates/calendar/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
  43. package/corpus/templates/calendar/.agents/skills/frontend-design/SKILL.md +23 -2
  44. package/corpus/templates/calendar/.agents/skills/frontend-design/references/visual-direction.md +99 -0
  45. package/corpus/templates/calendar/agent-native.json +12 -0
  46. package/corpus/templates/chat/.agents/skills/agent-native-docs/SKILL.md +23 -3
  47. package/corpus/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
  48. package/corpus/templates/chat/.agents/skills/frontend-design/SKILL.md +23 -2
  49. package/corpus/templates/chat/.agents/skills/frontend-design/references/visual-direction.md +99 -0
  50. package/corpus/templates/chat/AGENTS.md +3 -0
  51. package/corpus/templates/chat/DESIGN.md +28 -0
  52. package/corpus/templates/chat/agent-native.json +12 -0
  53. package/corpus/templates/clips/.agents/skills/agent-native-docs/SKILL.md +23 -3
  54. package/corpus/templates/clips/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
  55. package/corpus/templates/clips/.agents/skills/frontend-design/SKILL.md +23 -2
  56. package/corpus/templates/clips/.agents/skills/frontend-design/references/visual-direction.md +99 -0
  57. package/corpus/templates/clips/actions/cleanup-transcript.ts +2 -2
  58. package/corpus/templates/clips/actions/delete-recording-permanent.ts +3 -0
  59. package/corpus/templates/clips/actions/get-playback-position.ts +68 -0
  60. package/corpus/templates/clips/actions/import-loom-recording.ts +2 -2
  61. package/corpus/templates/clips/actions/save-playback-position.ts +80 -0
  62. package/corpus/templates/clips/actions/set-thumbnail.ts +1 -1
  63. package/corpus/templates/clips/agent-native.json +12 -0
  64. package/corpus/templates/clips/app/components/player/video-player.tsx +54 -5
  65. package/corpus/templates/clips/app/components/recorder/pre-record-panel.tsx +65 -18
  66. package/corpus/templates/clips/app/hooks/use-playback-position.ts +188 -0
  67. package/corpus/templates/clips/app/hooks/use-view-tracking.ts +6 -24
  68. package/corpus/templates/clips/app/i18n/en-US.ts +4 -0
  69. package/corpus/templates/clips/app/lib/playback-position.ts +99 -0
  70. package/corpus/templates/clips/app/lib/viewer-session.ts +29 -0
  71. package/corpus/templates/clips/changelog/2026-08-05-clip-buffering-now-uses-buffering-copy-after-playback.md +6 -0
  72. package/corpus/templates/clips/changelog/2026-08-05-clips-remembers-your-playback-position-when-you-reopen-a-cli.md +6 -0
  73. package/corpus/templates/clips/desktop/package.json +1 -0
  74. package/corpus/templates/clips/desktop/src/app.tsx +70 -6
  75. package/corpus/templates/clips/desktop/src/components/AlertDialog.tsx +131 -0
  76. package/corpus/templates/clips/desktop/src/styles.css +129 -0
  77. package/corpus/templates/clips/learnings.defaults.md +1 -1
  78. package/corpus/templates/clips/server/db/schema.ts +18 -0
  79. package/corpus/templates/clips/server/lib/public-agent-context.ts +1 -1
  80. package/corpus/templates/clips/server/lib/video-storage.ts +1 -1
  81. package/corpus/templates/clips/server/plugins/db.ts +15 -0
  82. package/corpus/templates/clips/server/routes/api/media/index.post.ts +1 -1
  83. package/corpus/templates/content/.agents/skills/agent-native-docs/SKILL.md +23 -3
  84. package/corpus/templates/content/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
  85. package/corpus/templates/content/.agents/skills/document-editing/references/databases.md +13 -0
  86. package/corpus/templates/content/.agents/skills/frontend-design/SKILL.md +23 -2
  87. package/corpus/templates/content/.agents/skills/frontend-design/references/visual-direction.md +99 -0
  88. package/corpus/templates/content/AGENTS.md +1 -0
  89. package/corpus/templates/content/actions/_content-database-mutation-lock.ts +41 -0
  90. package/corpus/templates/content/actions/_content-database-row-migration.ts +569 -0
  91. package/corpus/templates/content/actions/_database-source-utils.ts +82 -36
  92. package/corpus/templates/content/actions/_database-utils.ts +5 -0
  93. package/corpus/templates/content/actions/_delete-content-space.ts +25 -11
  94. package/corpus/templates/content/actions/add-database-item.ts +60 -42
  95. package/corpus/templates/content/actions/attach-content-database-source.ts +2 -0
  96. package/corpus/templates/content/actions/configure-document-property.ts +99 -104
  97. package/corpus/templates/content/actions/delete-content-database.ts +19 -7
  98. package/corpus/templates/content/actions/delete-document-property.ts +47 -58
  99. package/corpus/templates/content/actions/delete-document.ts +390 -167
  100. package/corpus/templates/content/actions/disconnect-content-database-source.ts +41 -24
  101. package/corpus/templates/content/actions/duplicate-database-item.ts +63 -31
  102. package/corpus/templates/content/actions/duplicate-database-items.ts +86 -43
  103. package/corpus/templates/content/actions/duplicate-document-property.ts +37 -14
  104. package/corpus/templates/content/actions/migrate-content-database-rows.ts +830 -0
  105. package/corpus/templates/content/actions/move-database-item.ts +14 -0
  106. package/corpus/templates/content/actions/permanently-delete-document.ts +27 -6
  107. package/corpus/templates/content/actions/remove-database-items.ts +13 -0
  108. package/corpus/templates/content/actions/reorder-document-property.ts +45 -46
  109. package/corpus/templates/content/actions/set-document-property.ts +68 -28
  110. package/corpus/templates/content/actions/submit-content-database-form.ts +49 -0
  111. package/corpus/templates/content/actions/transcribe-media.ts +1 -1
  112. package/corpus/templates/content/agent-native.json +12 -0
  113. package/corpus/templates/content/app/components/editor/image-upload.ts +2 -2
  114. package/corpus/templates/content/app/i18n-data.ts +1 -1
  115. package/corpus/templates/content/changelog/2026-08-01-content-can-reorganize-every-row-in-an-existing-database-as-.md +6 -0
  116. package/corpus/templates/content/parity/matrix.md +1 -1
  117. package/corpus/templates/content/parity/matrix.ts +4 -2
  118. package/corpus/templates/content/server/db/schema.ts +30 -0
  119. package/corpus/templates/content/server/plugins/db.ts +24 -0
  120. package/corpus/templates/content/server/plugins/onboarding.ts +2 -2
  121. package/corpus/templates/crm/.agents/skills/agent-native-docs/SKILL.md +23 -3
  122. package/corpus/templates/crm/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
  123. package/corpus/templates/crm/agent-native.json +12 -0
  124. package/corpus/templates/design/.agents/skills/agent-native-docs/SKILL.md +23 -3
  125. package/corpus/templates/design/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
  126. package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +2 -0
  127. package/corpus/templates/design/.agents/skills/frontend-design/SKILL.md +23 -2
  128. package/corpus/templates/design/.agents/skills/frontend-design/references/visual-direction.md +99 -0
  129. package/corpus/templates/design/CODE_NATIVE_DESIGN_STUDIO_IMPLEMENTATION_PLAN.md +2 -2
  130. package/corpus/templates/design/DESIGN-STUDIO-PLAN.md +2 -2
  131. package/corpus/templates/design/actions/apply-design-token-edit.ts +1 -1
  132. package/corpus/templates/design/actions/capture-design-state.ts +1 -1
  133. package/corpus/templates/design/actions/connect-builder-app.ts +2 -2
  134. package/corpus/templates/design/actions/create-design-branch.ts +1 -1
  135. package/corpus/templates/design/actions/create-fusion-app.ts +3 -3
  136. package/corpus/templates/design/actions/deploy-design-preview.ts +1 -1
  137. package/corpus/templates/design/actions/generate-design.ts +3 -2
  138. package/corpus/templates/design/actions/get-component-details.ts +1 -1
  139. package/corpus/templates/design/actions/get-design-branch-diff.ts +1 -1
  140. package/corpus/templates/design/actions/index-components.ts +3 -3
  141. package/corpus/templates/design/actions/index-design-system-with-builder.ts +1 -1
  142. package/corpus/templates/design/actions/migrate-inline-design-to-app.ts +3 -3
  143. package/corpus/templates/design/actions/open-component-source.ts +1 -1
  144. package/corpus/templates/design/actions/update-design.ts +96 -14
  145. package/corpus/templates/design/agent-native.json +12 -0
  146. package/corpus/templates/design/app/components/design/DesignImportPanel.tsx +7 -2
  147. package/corpus/templates/design/app/components/design/FigmaHydrationDialog.tsx +11 -2
  148. package/corpus/templates/design/app/components/design/edit-panel/component-section.tsx +1 -1
  149. package/corpus/templates/design/app/components/editor/PromptDialog.tsx +8 -1
  150. package/corpus/templates/design/app/i18n-data.ts +53 -22
  151. package/corpus/templates/design/app/lib/design-file-upload.ts +2 -3
  152. package/corpus/templates/design/app/lib/upload-limits.ts +4 -0
  153. package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +1 -1
  154. package/corpus/templates/design/changelog/2026-08-05-chat-attachments-now-warn-before-upload-when-they-exceed-the.md +6 -0
  155. package/corpus/templates/design/changelog/2026-08-05-figma-fig-uploads-now-show-a-clear-4-mb-limit-up-front-inste.md +6 -0
  156. package/corpus/templates/design/scripts/qa-figma-stress-import.ts +1 -1
  157. package/corpus/templates/design/server/handlers/import-design-file.ts +9 -5
  158. package/corpus/templates/design/server/handlers/uploads.ts +13 -9
  159. package/corpus/templates/design/server/lib/fig-file-limits.ts +2 -1
  160. package/corpus/templates/design/server/lib/figma-image-hydration.ts +1 -1
  161. package/corpus/templates/design/server/lib/figma-node-import.ts +1 -1
  162. package/corpus/templates/design/server/lib/request-body-limits.ts +11 -0
  163. package/corpus/templates/design/shared/canvas-frames.ts +81 -0
  164. package/corpus/templates/design/shared/design-source-capabilities.ts +25 -9
  165. package/corpus/templates/dispatch/.agents/skills/agent-native-docs/SKILL.md +23 -3
  166. package/corpus/templates/dispatch/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
  167. package/corpus/templates/dispatch/.agents/skills/frontend-design/SKILL.md +23 -2
  168. package/corpus/templates/dispatch/.agents/skills/frontend-design/references/visual-direction.md +99 -0
  169. package/corpus/templates/dispatch/agent-native.json +12 -0
  170. package/corpus/templates/factory/.agents/skills/agent-native-docs/SKILL.md +23 -3
  171. package/corpus/templates/factory/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
  172. package/corpus/templates/factory/.agents/skills/frontend-design/SKILL.md +23 -2
  173. package/corpus/templates/factory/.agents/skills/frontend-design/references/visual-direction.md +99 -0
  174. package/corpus/templates/factory/agent-native.json +12 -0
  175. package/corpus/templates/forms/.agents/skills/agent-native-docs/SKILL.md +23 -3
  176. package/corpus/templates/forms/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
  177. package/corpus/templates/forms/.agents/skills/frontend-design/SKILL.md +23 -2
  178. package/corpus/templates/forms/.agents/skills/frontend-design/references/visual-direction.md +99 -0
  179. package/corpus/templates/forms/actions/export-responses.ts +1 -1
  180. package/corpus/templates/forms/agent-native.json +12 -0
  181. package/corpus/templates/macros/.agents/skills/agent-native-docs/SKILL.md +23 -3
  182. package/corpus/templates/macros/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
  183. package/corpus/templates/macros/.agents/skills/frontend-design/SKILL.md +23 -2
  184. package/corpus/templates/macros/.agents/skills/frontend-design/references/visual-direction.md +99 -0
  185. package/corpus/templates/macros/agent-native.json +12 -0
  186. package/corpus/templates/mail/.agents/skills/agent-native-docs/SKILL.md +23 -3
  187. package/corpus/templates/mail/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
  188. package/corpus/templates/mail/.agents/skills/frontend-design/SKILL.md +23 -2
  189. package/corpus/templates/mail/.agents/skills/frontend-design/references/visual-direction.md +99 -0
  190. package/corpus/templates/mail/agent-native.json +12 -0
  191. package/corpus/templates/mail/app/i18n/en-US.ts +1 -1
  192. package/corpus/templates/mail/server/lib/media-upload.ts +1 -1
  193. package/corpus/templates/plan/.agents/skills/agent-native-docs/SKILL.md +23 -3
  194. package/corpus/templates/plan/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
  195. package/corpus/templates/plan/.agents/skills/frontend-design/SKILL.md +23 -2
  196. package/corpus/templates/plan/.agents/skills/frontend-design/references/visual-direction.md +99 -0
  197. package/corpus/templates/plan/agent-native.json +12 -0
  198. package/corpus/templates/plan/server/lib/plan-assets.ts +1 -1
  199. package/corpus/templates/slides/.agents/skills/agent-native-docs/SKILL.md +23 -3
  200. package/corpus/templates/slides/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
  201. package/corpus/templates/slides/.agents/skills/frontend-design/SKILL.md +23 -2
  202. package/corpus/templates/slides/.agents/skills/frontend-design/references/visual-direction.md +99 -0
  203. package/corpus/templates/slides/actions/generate-image-api.ts +1 -1
  204. package/corpus/templates/slides/actions/generate-slides-ai.ts +1 -1
  205. package/corpus/templates/slides/actions/import-file.ts +2 -2
  206. package/corpus/templates/slides/actions/index-design-system-with-builder.ts +1 -1
  207. package/corpus/templates/slides/agent-native.json +12 -0
  208. package/corpus/templates/slides/app/components/design-system/DesignSystemSetup.tsx +1 -1
  209. package/corpus/templates/slides/app/i18n/en-US.ts +2 -2
  210. package/corpus/templates/slides/app/lib/deck-sorting.ts +19 -0
  211. package/corpus/templates/slides/app/lib/image-drop-to-agent.ts +1 -1
  212. package/corpus/templates/slides/app/pages/Index.tsx +7 -2
  213. package/corpus/templates/slides/changelog/2026-08-05-decks-are-now-sorted-by-most-recently-updated.md +6 -0
  214. package/corpus/templates/slides/server/handlers/assets.ts +1 -1
  215. package/corpus/templates/slides/server/handlers/uploads.ts +1 -1
  216. package/corpus/templates/tasks/.agents/skills/agent-native-docs/SKILL.md +23 -3
  217. package/corpus/templates/tasks/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
  218. package/corpus/templates/tasks/.agents/skills/frontend-design/SKILL.md +23 -2
  219. package/corpus/templates/tasks/.agents/skills/frontend-design/references/visual-direction.md +99 -0
  220. package/corpus/templates/tasks/agent-native.json +12 -0
  221. package/dist/action.d.ts +6 -0
  222. package/dist/agent/engine/builder-engine.js +2 -2
  223. package/dist/agent/engine/credential-errors.d.ts +1 -1
  224. package/dist/agent/engine/credential-errors.js +2 -2
  225. package/dist/agent/production-agent.js +3 -2
  226. package/dist/brand-kit/fig/index.js +1 -1
  227. package/dist/cli/agent.js +45 -3
  228. package/dist/cli/code-agent-executor.js +2 -1
  229. package/dist/cli/create.d.ts +9 -1
  230. package/dist/cli/create.js +94 -1
  231. package/dist/cli/doctor.d.ts +8 -11
  232. package/dist/cli/doctor.js +92 -24
  233. package/dist/cli/index.js +6 -5
  234. package/dist/client/AgentAskPopover.d.ts +3 -1
  235. package/dist/client/AgentAskPopover.js +2 -2
  236. package/dist/client/AgentPanel.js +9 -3
  237. package/dist/client/AssistantChat.js +54 -33
  238. package/dist/client/MultiTabAssistantChat.js +1 -1
  239. package/dist/client/RouteTransitionIndicator.d.ts +7 -0
  240. package/dist/client/RouteTransitionIndicator.js +31 -0
  241. package/dist/client/agent-engine-key.js +1 -1
  242. package/dist/client/app-providers.js +11 -2
  243. package/dist/client/chat/message-components.js +1 -1
  244. package/dist/client/chat/run-recovery.js +1 -1
  245. package/dist/client/chat/tool-call-display.d.ts +3 -1
  246. package/dist/client/chat/tool-call-display.js +4 -3
  247. package/dist/client/chat-model-groups.d.ts +6 -0
  248. package/dist/client/chat-model-groups.js +11 -0
  249. package/dist/client/error-format.js +1 -1
  250. package/dist/client/i18n.js +1 -1
  251. package/dist/client/onboarding/FirstRunOnboarding.d.ts +5 -1
  252. package/dist/client/onboarding/FirstRunOnboarding.js +29 -13
  253. package/dist/client/onboarding/first-run-enabled.d.ts +6 -1
  254. package/dist/client/onboarding/first-run-enabled.js +33 -3
  255. package/dist/client/onboarding/use-onboarding.js +16 -11
  256. package/dist/client/require-session.js +13 -4
  257. package/dist/client/resources/mcp-integration-catalog.js +26 -0
  258. package/dist/client/resources/mcp-integration-logos.js +4 -0
  259. package/dist/client/route-warmup.js +56 -10
  260. package/dist/client/settings/AccountSettingsCard.js +78 -3
  261. package/dist/client/settings/SettingsPanel.js +1 -1
  262. package/dist/client/settings/VoiceTranscriptionSection.js +2 -2
  263. package/dist/client/settings/useBuilderStatus.js +1 -1
  264. package/dist/client/setup-connections/useBuilderConnectCardController.js +1 -1
  265. package/dist/client/ui/index.d.ts +1 -0
  266. package/dist/client/ui/index.js +1 -0
  267. package/dist/client/uploads/upload-editor-image.js +1 -1
  268. package/dist/client/use-chat-threads.js +3 -0
  269. package/dist/client/use-session.d.ts +11 -0
  270. package/dist/client/use-session.js +34 -6
  271. package/dist/collab/routes.d.ts +2 -2
  272. package/dist/config.d.ts +48 -0
  273. package/dist/config.js +111 -0
  274. package/dist/db/migrations.js +5 -0
  275. package/dist/eject/provider-api-definitions.d.ts +1 -1
  276. package/dist/eject/provider-api-definitions.js +1 -0
  277. package/dist/eject/remote-mcp-presets.js +1 -0
  278. package/dist/extensions/web-search-tool.js +2 -2
  279. package/dist/file-upload/actions/upload-image.js +1 -1
  280. package/dist/file-upload/registry.js +1 -1
  281. package/dist/guards/index.d.ts +3 -0
  282. package/dist/guards/index.js +2 -0
  283. package/dist/guards/no-empty-migrations.d.ts +14 -0
  284. package/dist/guards/no-empty-migrations.js +126 -0
  285. package/dist/index.browser.d.ts +1 -0
  286. package/dist/index.browser.js +3 -0
  287. package/dist/index.d.ts +1 -0
  288. package/dist/index.js +1 -0
  289. package/dist/localization/default-messages.d.ts +24 -0
  290. package/dist/localization/default-messages.js +26 -2
  291. package/dist/notifications/routes.d.ts +6 -6
  292. package/dist/onboarding/app-profile.js +1 -1
  293. package/dist/onboarding/plugin.d.ts +2 -0
  294. package/dist/onboarding/plugin.js +29 -2
  295. package/dist/progress/routes.d.ts +1 -1
  296. package/dist/provider-api/actions/custom-provider-registration.d.ts +16 -16
  297. package/dist/provider-api/actions/provider-api.d.ts +13 -13
  298. package/dist/provider-api/index.d.ts +4 -4
  299. package/dist/provider-api/index.js +35 -0
  300. package/dist/resources/handlers.d.ts +1 -1
  301. package/dist/resources/handlers.js +1 -1
  302. package/dist/scripts/docs/framework-search.d.ts +9 -0
  303. package/dist/scripts/docs/framework-search.js +239 -0
  304. package/dist/scripts/docs/index.js +1 -0
  305. package/dist/scripts/docs/search.d.ts +10 -0
  306. package/dist/scripts/docs/search.js +1 -1
  307. package/dist/scripts/docs/source-search.d.ts +10 -2
  308. package/dist/scripts/docs/source-search.js +108 -41
  309. package/dist/search-utils/index.d.ts +11 -0
  310. package/dist/search-utils/index.js +72 -0
  311. package/dist/server/action-change.d.ts +6 -0
  312. package/dist/server/action-change.js +28 -14
  313. package/dist/server/action-discovery.js +9 -0
  314. package/dist/server/action-routes.js +1 -0
  315. package/dist/server/agent-chat/browser-team-tools.js +1 -1
  316. package/dist/server/agent-chat/script-entries.js +43 -2
  317. package/dist/server/auth-login-mode.d.ts +8 -0
  318. package/dist/server/auth-login-mode.js +17 -0
  319. package/dist/server/auth.js +100 -15
  320. package/dist/server/better-auth-instance.d.ts +36 -0
  321. package/dist/server/better-auth-instance.js +25 -3
  322. package/dist/server/builder-design-systems.js +1 -1
  323. package/dist/server/core-routes-plugin.js +17 -14
  324. package/dist/server/credential-provider.js +3 -3
  325. package/dist/server/email-templates.d.ts +7 -0
  326. package/dist/server/email-templates.js +24 -0
  327. package/dist/server/email.d.ts +17 -0
  328. package/dist/server/email.js +22 -1
  329. package/dist/server/framework-request-handler.js +6 -0
  330. package/dist/server/onboarding-html.d.ts +2 -0
  331. package/dist/server/onboarding-html.js +169 -8
  332. package/dist/server/realtime-token.d.ts +1 -1
  333. package/dist/server/realtime-voice.js +1 -1
  334. package/dist/server/sentry.d.ts +1 -1
  335. package/dist/server/transcribe-voice.js +3 -3
  336. package/dist/shared/first-run-onboarding.d.ts +1 -0
  337. package/dist/shared/first-run-onboarding.js +1 -0
  338. package/dist/templates/chat/.agents/skills/agent-native-docs/SKILL.md +23 -3
  339. package/dist/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
  340. package/dist/templates/chat/.agents/skills/frontend-design/SKILL.md +23 -2
  341. package/dist/templates/chat/.agents/skills/frontend-design/references/visual-direction.md +99 -0
  342. package/dist/templates/chat/AGENTS.md +3 -0
  343. package/dist/templates/chat/DESIGN.md +28 -0
  344. package/dist/templates/chat/agent-native.json +12 -0
  345. package/dist/templates/default/.agents/skills/agent-native-docs/SKILL.md +23 -3
  346. package/dist/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
  347. package/dist/templates/default/.agents/skills/frontend-design/SKILL.md +23 -2
  348. package/dist/templates/default/.agents/skills/frontend-design/references/visual-direction.md +99 -0
  349. package/dist/templates/default/AGENTS.md +4 -0
  350. package/dist/templates/default/DESIGN.md +30 -0
  351. package/dist/templates/default/agent-native.json +9 -0
  352. package/dist/templates/default/app/i18n/ar-SA.ts +2 -2
  353. package/dist/templates/default/app/i18n/de-DE.ts +2 -2
  354. package/dist/templates/default/app/i18n/en-US.ts +2 -2
  355. package/dist/templates/default/app/i18n/es-ES.ts +2 -2
  356. package/dist/templates/default/app/i18n/fr-FR.ts +2 -2
  357. package/dist/templates/default/app/i18n/hi-IN.ts +2 -2
  358. package/dist/templates/default/app/i18n/ja-JP.ts +2 -2
  359. package/dist/templates/default/app/i18n/ko-KR.ts +2 -2
  360. package/dist/templates/default/app/i18n/pt-BR.ts +2 -2
  361. package/dist/templates/default/app/i18n/zh-CN.ts +2 -2
  362. package/dist/templates/default/app/i18n/zh-TW.ts +1 -1
  363. package/dist/templates/default/package.json +1 -0
  364. package/dist/templates/headless/.agents/skills/agent-native-docs/SKILL.md +23 -3
  365. package/dist/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
  366. package/dist/templates/headless/agent-native.json +9 -0
  367. package/dist/templates/headless/package.json +2 -0
  368. package/dist/templates/workspace-core/.agents/skills/agent-native-docs/SKILL.md +23 -3
  369. package/dist/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
  370. package/dist/templates/workspace-core/.agents/skills/frontend-design/SKILL.md +23 -2
  371. package/dist/templates/workspace-core/.agents/skills/frontend-design/references/visual-direction.md +99 -0
  372. package/dist/templates/workspace-core/AGENTS.md +3 -0
  373. package/dist/templates/workspace-core/DESIGN.md +35 -0
  374. package/dist/templates/workspace-root/AGENTS.md +3 -0
  375. package/dist/templates/workspace-root/DESIGN.md +35 -0
  376. package/dist/templates/workspace-root/agent-native.json +9 -0
  377. package/dist/templates/workspace-root/package.json +3 -0
  378. package/dist/transcription/builder-transcription.js +1 -1
  379. package/dist/user-profile/actions/change-password.d.ts +8 -0
  380. package/dist/user-profile/actions/change-password.js +24 -0
  381. package/dist/user-profile/actions/get-auth-methods.d.ts +6 -0
  382. package/dist/user-profile/actions/get-auth-methods.js +23 -0
  383. package/dist/user-profile/actions/set-password.d.ts +7 -0
  384. package/dist/user-profile/actions/set-password.js +23 -0
  385. package/dist/vite/client.d.ts +8 -1
  386. package/dist/vite/client.js +63 -12
  387. package/dist/vite/index.d.ts +1 -0
  388. package/dist/vite/index.js +1 -0
  389. package/docs/AGENTS.md +7 -2
  390. package/docs/SKILL.md +7 -5
  391. package/docs/content/agent-native-config.mdx +165 -0
  392. package/docs/content/agent-native-toolkit.mdx +1 -1
  393. package/docs/content/deployment.mdx +7 -2
  394. package/docs/content/doctor.mdx +21 -13
  395. package/docs/content/environment-variables.mdx +158 -0
  396. package/docs/content/file-uploads.mdx +1 -1
  397. package/docs/content/getting-started.mdx +1 -1
  398. package/docs/content/key-concepts.mdx +1 -1
  399. package/docs/content/multi-app-workspace.mdx +1 -1
  400. package/docs/content/template-clips-ai-and-editing.mdx +6 -6
  401. package/docs/content/template-clips-developers.mdx +3 -3
  402. package/docs/content/toolkit-settings.mdx +1 -1
  403. package/docs/content/voice-input.mdx +4 -4
  404. package/package.json +6 -2
  405. package/src/eject/provider-api-definitions.ts +1 -0
  406. package/src/eject/remote-mcp-presets.ts +1 -0
  407. package/src/templates/chat/.agents/skills/agent-native-docs/SKILL.md +23 -3
  408. package/src/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
  409. package/src/templates/chat/.agents/skills/frontend-design/SKILL.md +23 -2
  410. package/src/templates/chat/.agents/skills/frontend-design/references/visual-direction.md +99 -0
  411. package/src/templates/chat/AGENTS.md +3 -0
  412. package/src/templates/chat/DESIGN.md +28 -0
  413. package/src/templates/chat/agent-native.json +12 -0
  414. package/src/templates/default/.agents/skills/agent-native-docs/SKILL.md +23 -3
  415. package/src/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
  416. package/src/templates/default/.agents/skills/frontend-design/SKILL.md +23 -2
  417. package/src/templates/default/.agents/skills/frontend-design/references/visual-direction.md +99 -0
  418. package/src/templates/default/AGENTS.md +4 -0
  419. package/src/templates/default/DESIGN.md +30 -0
  420. package/src/templates/default/agent-native.json +9 -0
  421. package/src/templates/default/app/i18n/ar-SA.ts +2 -2
  422. package/src/templates/default/app/i18n/de-DE.ts +2 -2
  423. package/src/templates/default/app/i18n/en-US.ts +2 -2
  424. package/src/templates/default/app/i18n/es-ES.ts +2 -2
  425. package/src/templates/default/app/i18n/fr-FR.ts +2 -2
  426. package/src/templates/default/app/i18n/hi-IN.ts +2 -2
  427. package/src/templates/default/app/i18n/ja-JP.ts +2 -2
  428. package/src/templates/default/app/i18n/ko-KR.ts +2 -2
  429. package/src/templates/default/app/i18n/pt-BR.ts +2 -2
  430. package/src/templates/default/app/i18n/zh-CN.ts +2 -2
  431. package/src/templates/default/app/i18n/zh-TW.ts +1 -1
  432. package/src/templates/default/package.json +1 -0
  433. package/src/templates/headless/.agents/skills/agent-native-docs/SKILL.md +23 -3
  434. package/src/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
  435. package/src/templates/headless/agent-native.json +9 -0
  436. package/src/templates/headless/package.json +2 -0
  437. package/src/templates/workspace-core/.agents/skills/agent-native-docs/SKILL.md +23 -3
  438. package/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
  439. package/src/templates/workspace-core/.agents/skills/frontend-design/SKILL.md +23 -2
  440. package/src/templates/workspace-core/.agents/skills/frontend-design/references/visual-direction.md +99 -0
  441. package/src/templates/workspace-core/AGENTS.md +3 -0
  442. package/src/templates/workspace-core/DESIGN.md +35 -0
  443. package/src/templates/workspace-root/AGENTS.md +3 -0
  444. package/src/templates/workspace-root/DESIGN.md +35 -0
  445. package/src/templates/workspace-root/agent-native.json +9 -0
  446. package/src/templates/workspace-root/package.json +3 -0
@@ -28,6 +28,7 @@ import {
28
28
  } from "@/components/ui/dropdown-menu";
29
29
  import { Spinner } from "@/components/ui/spinner";
30
30
  import { useMseVideoSource } from "@/hooks/use-mse-video-source";
31
+ import { usePlaybackPosition } from "@/hooks/use-playback-position";
31
32
  import {
32
33
  parsePlaybackSpeed,
33
34
  readPlaybackSpeedPreference,
@@ -265,9 +266,12 @@ export const VideoPlayer = forwardRef<VideoPlayerHandle, VideoPlayerProps>(
265
266
  [videoUrl],
266
267
  );
267
268
  const videoRef = useRef<HTMLVideoElement | null>(null);
269
+ const [playbackVideoEl, setPlaybackVideoEl] =
270
+ useState<HTMLVideoElement | null>(null);
268
271
  const setVideoNode = useCallback(
269
272
  (el: HTMLVideoElement | null) => {
270
273
  videoRef.current = el;
274
+ setPlaybackVideoEl(el);
271
275
  onVideoElementChange?.(el);
272
276
  },
273
277
  [onVideoElementChange],
@@ -408,6 +412,50 @@ export const VideoPlayer = forwardRef<VideoPlayerHandle, VideoPlayerProps>(
408
412
  () => embedProvider === "loom" || isLoomEmbedUrl(activeVideoSrc),
409
413
  [activeVideoSrc, embedProvider],
410
414
  );
415
+ const restorePlaybackPosition = useCallback(
416
+ (positionMs: number) => {
417
+ const v = videoRef.current;
418
+ if (!v || (startMs && startMs > 0)) return;
419
+ if (hasPlaybackStarted && !autoPlay) return;
420
+ if (!autoPlay && isPlayPending) return;
421
+ if (!autoPlay && v.currentTime > 0.5) return;
422
+
423
+ const visibleMs = clampSeek(
424
+ skipExcludedRange(positionMs, excludedRanges, resolvedDurationMs),
425
+ v,
426
+ resolvedDurationMs,
427
+ );
428
+ if (visibleMs <= 0) return;
429
+
430
+ try {
431
+ initialVisibleFrameSeekedRef.current = true;
432
+ v.currentTime = visibleMs / 1000;
433
+ setCurrentMs(visibleMs);
434
+ setCanPlay(true);
435
+ setIsPreparing(false);
436
+ onTimeUpdate?.(visibleMs, resolvedDurationMs);
437
+ } catch (error) {
438
+ console.warn("[clips] playback position restore failed", error);
439
+ }
440
+ },
441
+ [
442
+ autoPlay,
443
+ excludedRanges,
444
+ hasPlaybackStarted,
445
+ isPlayPending,
446
+ onTimeUpdate,
447
+ resolvedDurationMs,
448
+ startMs,
449
+ ],
450
+ );
451
+ usePlaybackPosition({
452
+ recordingId,
453
+ videoEl: playbackVideoEl,
454
+ durationMs,
455
+ explicitStartMs: startMs,
456
+ allowRestoreWhilePlaying: autoPlay,
457
+ onRestore: restorePlaybackPosition,
458
+ });
411
459
  // Clips stores exactly one `videoUrl` per recording (no alternate-format
412
460
  // fallback to select between), and every browser MediaRecorder-based
413
461
  // recording is stored as `webm` — which Safari (desktop and iOS) cannot
@@ -1291,11 +1339,12 @@ export const VideoPlayer = forwardRef<VideoPlayerHandle, VideoPlayerProps>(
1291
1339
  ? "loading"
1292
1340
  : "ready"
1293
1341
  : null;
1294
- const centerOverlayLabel = isPlayPending
1295
- ? "Starting playback"
1296
- : isBuffering
1297
- ? "Buffering"
1298
- : "Preparing clip";
1342
+ const centerOverlayLabel =
1343
+ isPlayPending && !hasPlaybackStarted
1344
+ ? "Starting playback"
1345
+ : isPlayPending || isBuffering
1346
+ ? "Buffering"
1347
+ : "Preparing clip";
1299
1348
 
1300
1349
  return (
1301
1350
  <div
@@ -14,6 +14,16 @@ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
14
14
 
15
15
  import { CaptureInstallInlineLink } from "@/components/capture-install-options";
16
16
  import { ImportMenu } from "@/components/import-menu";
17
+ import {
18
+ AlertDialog,
19
+ AlertDialogAction,
20
+ AlertDialogCancel,
21
+ AlertDialogContent,
22
+ AlertDialogDescription,
23
+ AlertDialogFooter,
24
+ AlertDialogHeader,
25
+ AlertDialogTitle,
26
+ } from "@/components/ui/alert-dialog";
17
27
  import { Button } from "@/components/ui/button";
18
28
  import {
19
29
  Collapsible,
@@ -426,6 +436,35 @@ export function PreRecordPanel({
426
436
  );
427
437
  }, [micId, micLabel, mics, t]);
428
438
 
439
+ const [micWarningOpen, setMicWarningOpen] = useState(false);
440
+
441
+ const buildStartOpts = useCallback(
442
+ () => ({
443
+ // If the user toggled off the camera inside screen+camera mode,
444
+ // downgrade to screen-only so the recorder engine doesn't try
445
+ // to acquire a webcam stream.
446
+ mode: (mode === "screen+camera" && !needsCamera
447
+ ? "screen"
448
+ : mode) as RecordingMode,
449
+ displaySurface: normalizeDisplaySurfaceForRuntime(displaySurface),
450
+ micDeviceId: micId === "default" ? null : micId,
451
+ micDeviceLabel:
452
+ micId === "default" || micId === NO_MIC_DEVICE_ID
453
+ ? null
454
+ : selectedMicLabel,
455
+ cameraDeviceId: needsCamera && cameraId !== "default" ? cameraId : null,
456
+ }),
457
+ [mode, needsCamera, displaySurface, micId, selectedMicLabel, cameraId],
458
+ );
459
+
460
+ const handleStartClick = useCallback(() => {
461
+ if (micId === NO_MIC_DEVICE_ID) {
462
+ setMicWarningOpen(true);
463
+ return;
464
+ }
465
+ onStart(buildStartOpts());
466
+ }, [micId, buildStartOpts, onStart]);
467
+
429
468
  const selectedCameraLabel = useMemo(() => {
430
469
  if (!needsCamera) return null;
431
470
  if (cameraId === "default") return t("preRecord.defaultCamera");
@@ -893,24 +932,7 @@ export function PreRecordPanel({
893
932
  )}
894
933
  <Button
895
934
  disabled={startDisabled}
896
- onClick={() =>
897
- onStart({
898
- // If the user toggled off the camera inside screen+camera mode,
899
- // downgrade to screen-only so the recorder engine doesn't try
900
- // to acquire a webcam stream.
901
- mode:
902
- mode === "screen+camera" && !needsCamera ? "screen" : mode,
903
- displaySurface:
904
- normalizeDisplaySurfaceForRuntime(displaySurface),
905
- micDeviceId: micId === "default" ? null : micId,
906
- micDeviceLabel:
907
- micId === "default" || micId === NO_MIC_DEVICE_ID
908
- ? null
909
- : selectedMicLabel,
910
- cameraDeviceId:
911
- needsCamera && cameraId !== "default" ? cameraId : null,
912
- })
913
- }
935
+ onClick={handleStartClick}
914
936
  className={cn("h-12", onCancel ? "flex-1" : "w-full")}
915
937
  >
916
938
  {t("preRecord.startRecording")}
@@ -943,6 +965,31 @@ export function PreRecordPanel({
943
965
  </>
944
966
  )}
945
967
  </div>
968
+
969
+ <AlertDialog open={micWarningOpen} onOpenChange={setMicWarningOpen}>
970
+ <AlertDialogContent>
971
+ <AlertDialogHeader>
972
+ <AlertDialogTitle>
973
+ {t("preRecord.micOffConfirmTitle")}
974
+ </AlertDialogTitle>
975
+ <AlertDialogDescription>
976
+ {t("preRecord.micOffConfirmDescription")}
977
+ </AlertDialogDescription>
978
+ </AlertDialogHeader>
979
+ <AlertDialogFooter>
980
+ <AlertDialogCancel>{t("common.cancel")}</AlertDialogCancel>
981
+ <AlertDialogAction
982
+ onClick={(event) => {
983
+ event.preventDefault();
984
+ setMicWarningOpen(false);
985
+ onStart(buildStartOpts());
986
+ }}
987
+ >
988
+ {t("preRecord.startWithoutMic")}
989
+ </AlertDialogAction>
990
+ </AlertDialogFooter>
991
+ </AlertDialogContent>
992
+ </AlertDialog>
946
993
  </div>
947
994
  );
948
995
  }
@@ -0,0 +1,188 @@
1
+ import { useEffect, useRef } from "react";
2
+
3
+ import {
4
+ getPlaybackPosition,
5
+ savePlaybackPosition,
6
+ } from "@/lib/playback-position";
7
+
8
+ const SAVE_INTERVAL_MS = 5_000;
9
+ const MIN_POSITION_MS = 50;
10
+ const COMPLETION_TAIL_MS = 1_500;
11
+
12
+ export interface UsePlaybackPositionOptions {
13
+ recordingId: string;
14
+ videoEl: HTMLVideoElement | null;
15
+ durationMs: number;
16
+ explicitStartMs?: number;
17
+ allowRestoreWhilePlaying?: boolean;
18
+ onRestore?: (positionMs: number) => void;
19
+ }
20
+
21
+ /**
22
+ * Persists the latest native-video position for the current viewer. This is
23
+ * separate from view analytics so the recording owner can resume without
24
+ * becoming one of the clip's counted viewers.
25
+ */
26
+ export function usePlaybackPosition({
27
+ recordingId,
28
+ videoEl,
29
+ durationMs,
30
+ explicitStartMs,
31
+ allowRestoreWhilePlaying = false,
32
+ onRestore,
33
+ }: UsePlaybackPositionOptions) {
34
+ const durationMsRef = useRef(durationMs);
35
+ const onRestoreRef = useRef(onRestore);
36
+
37
+ durationMsRef.current = durationMs;
38
+ onRestoreRef.current = onRestore;
39
+
40
+ useEffect(() => {
41
+ if (!videoEl || !recordingId) return;
42
+
43
+ const controller = new AbortController();
44
+ let cancelled = false;
45
+ let playbackStarted = false;
46
+ let restoreApplied = false;
47
+ let saveInFlight = false;
48
+ let pendingSave: { positionMs: number; keepalive: boolean } | null = null;
49
+ let lastSavedPositionMs = -1;
50
+ let lastSavedAt = -SAVE_INTERVAL_MS;
51
+ let removePendingRestoreListeners: (() => void) | null = null;
52
+
53
+ const readPositionMs = (): number | null => {
54
+ const seconds = videoEl.currentTime;
55
+ if (!Number.isFinite(seconds) || seconds < 0 || seconds >= 1e7) {
56
+ return null;
57
+ }
58
+ return Math.floor(seconds * 1000);
59
+ };
60
+
61
+ const persist = (keepalive: boolean) => {
62
+ const positionMs = readPositionMs();
63
+ if (
64
+ positionMs === null ||
65
+ (!playbackStarted && positionMs < MIN_POSITION_MS)
66
+ ) {
67
+ return;
68
+ }
69
+
70
+ const now = Date.now();
71
+ if (!keepalive && now - lastSavedAt < SAVE_INTERVAL_MS) {
72
+ return;
73
+ }
74
+
75
+ if (saveInFlight) {
76
+ pendingSave = { positionMs, keepalive };
77
+ return;
78
+ }
79
+
80
+ saveInFlight = true;
81
+ lastSavedPositionMs = positionMs;
82
+ lastSavedAt = now;
83
+ void savePlaybackPosition(recordingId, positionMs, { keepalive })
84
+ .catch((error) => {
85
+ if (!cancelled) {
86
+ console.warn("[clips] playback position save failed", error);
87
+ }
88
+ })
89
+ .finally(() => {
90
+ saveInFlight = false;
91
+ if (!pendingSave) return;
92
+ const next = pendingSave;
93
+ pendingSave = null;
94
+ persist(next.keepalive);
95
+ });
96
+ };
97
+
98
+ const restore = (positionMs: number) => {
99
+ if (cancelled || restoreApplied || explicitStartMs) return;
100
+ if (positionMs <= 0) return;
101
+ const duration = durationMsRef.current;
102
+ if (duration > 0 && positionMs >= duration - COMPLETION_TAIL_MS) {
103
+ return;
104
+ }
105
+ if (
106
+ playbackStarted &&
107
+ !allowRestoreWhilePlaying &&
108
+ readPositionMs() !== 0
109
+ ) {
110
+ return;
111
+ }
112
+
113
+ restoreApplied = true;
114
+ onRestoreRef.current?.(positionMs);
115
+ };
116
+
117
+ const restoreWhenReady = (positionMs: number) => {
118
+ if (videoEl.readyState >= 1) {
119
+ restore(positionMs);
120
+ return;
121
+ }
122
+
123
+ const apply = () => {
124
+ removePendingRestoreListeners?.();
125
+ removePendingRestoreListeners = null;
126
+ restore(positionMs);
127
+ };
128
+ videoEl.addEventListener("loadedmetadata", apply);
129
+ videoEl.addEventListener("loadeddata", apply);
130
+ removePendingRestoreListeners = () => {
131
+ videoEl.removeEventListener("loadedmetadata", apply);
132
+ videoEl.removeEventListener("loadeddata", apply);
133
+ };
134
+ };
135
+
136
+ const onPlay = () => {
137
+ playbackStarted = true;
138
+ };
139
+ const onTimeUpdate = () => {
140
+ if (playbackStarted) persist(false);
141
+ };
142
+ const onPause = () => persist(true);
143
+ const onSeeked = () => persist(true);
144
+ const onEnded = () => persist(true);
145
+ const onPageHide = () => persist(true);
146
+ const onVisibilityChange = () => {
147
+ if (document.visibilityState === "hidden") persist(true);
148
+ };
149
+
150
+ videoEl.addEventListener("play", onPlay);
151
+ videoEl.addEventListener("timeupdate", onTimeUpdate);
152
+ videoEl.addEventListener("pause", onPause);
153
+ videoEl.addEventListener("seeked", onSeeked);
154
+ videoEl.addEventListener("ended", onEnded);
155
+ window.addEventListener("pagehide", onPageHide);
156
+ document.addEventListener("visibilitychange", onVisibilityChange);
157
+
158
+ if (!explicitStartMs) {
159
+ void getPlaybackPosition(recordingId, { signal: controller.signal })
160
+ .then((positionMs) => {
161
+ if (positionMs !== null) restoreWhenReady(positionMs);
162
+ })
163
+ .catch((error) => {
164
+ if (
165
+ !cancelled &&
166
+ (error as { name?: string })?.name !== "AbortError"
167
+ ) {
168
+ console.warn("[clips] playback position load failed", error);
169
+ }
170
+ });
171
+ }
172
+
173
+ return () => {
174
+ persist(true);
175
+ cancelled = true;
176
+ controller.abort();
177
+ removePendingRestoreListeners?.();
178
+ removePendingRestoreListeners = null;
179
+ videoEl.removeEventListener("play", onPlay);
180
+ videoEl.removeEventListener("timeupdate", onTimeUpdate);
181
+ videoEl.removeEventListener("pause", onPause);
182
+ videoEl.removeEventListener("seeked", onSeeked);
183
+ videoEl.removeEventListener("ended", onEnded);
184
+ window.removeEventListener("pagehide", onPageHide);
185
+ document.removeEventListener("visibilitychange", onVisibilityChange);
186
+ };
187
+ }, [allowRestoreWhilePlaying, explicitStartMs, recordingId, videoEl]);
188
+ }
@@ -1,27 +1,9 @@
1
1
  import { appBasePath } from "@agent-native/core/client/api-path";
2
2
  import { useEffect, useRef } from "react";
3
3
 
4
- import { clampCompletionPct } from "../../shared/view-analytics";
5
-
6
- const SESSION_KEY = "clips-view-session-id";
4
+ import { getViewerSessionId } from "@/lib/viewer-session";
7
5
 
8
- function getSessionId(): string {
9
- if (typeof window === "undefined") return "server";
10
- try {
11
- let id = localStorage.getItem(SESSION_KEY);
12
- if (!id) {
13
- id =
14
- "s-" +
15
- Date.now().toString(36) +
16
- "-" +
17
- Math.random().toString(36).slice(2, 8);
18
- localStorage.setItem(SESSION_KEY, id);
19
- }
20
- return id;
21
- } catch {
22
- return "s-" + Math.random().toString(36).slice(2, 8);
23
- }
24
- }
6
+ import { clampCompletionPct } from "../../shared/view-analytics";
25
7
 
26
8
  function createViewSessionId(recordingId: string): string {
27
9
  return [
@@ -118,7 +100,7 @@ export function useViewTracking(opts: UseViewTrackingOpts) {
118
100
  recordingId,
119
101
  kind: "view-start",
120
102
  timestampMs: 0,
121
- sessionId: getSessionId(),
103
+ sessionId: getViewerSessionId(),
122
104
  viewSessionId: viewSessionRef.current,
123
105
  totalWatchMs: 0,
124
106
  completedPct: 0,
@@ -130,7 +112,7 @@ export function useViewTracking(opts: UseViewTrackingOpts) {
130
112
  }
131
113
 
132
114
  const video = videoEl;
133
- const sessionId = getSessionId();
115
+ const sessionId = getViewerSessionId();
134
116
  viewSessionRef.current = createViewSessionId(recordingId);
135
117
  let progressTimer: ReturnType<typeof setInterval> | null = null;
136
118
 
@@ -243,7 +225,7 @@ export function useViewTracking(opts: UseViewTrackingOpts) {
243
225
  body: JSON.stringify({
244
226
  recordingId: recordingIdRef.current,
245
227
  kind: "cta-click",
246
- sessionId: getSessionId(),
228
+ sessionId: getViewerSessionId(),
247
229
  }),
248
230
  }).catch(() => {});
249
231
  },
@@ -255,7 +237,7 @@ export function useViewTracking(opts: UseViewTrackingOpts) {
255
237
  body: JSON.stringify({
256
238
  recordingId: recordingIdRef.current,
257
239
  kind: "reaction",
258
- sessionId: getSessionId(),
240
+ sessionId: getViewerSessionId(),
259
241
  payload: { emoji },
260
242
  }),
261
243
  }).catch(() => {});
@@ -1274,6 +1274,10 @@ All notable user-facing changes to Clips are documented here. Open it any time f
1274
1274
  cameraOff: "Camera off",
1275
1275
  includeCameraAria: "Include camera in this recording",
1276
1276
  startRecording: "Start recording",
1277
+ micOffConfirmTitle: "Record without a microphone?",
1278
+ micOffConfirmDescription:
1279
+ "Your mic is off, so this recording won't capture any audio. Turn it on before starting if you want narration.",
1280
+ startWithoutMic: "Start anyway",
1277
1281
  uploadVideo: "Upload video",
1278
1282
  importLoom: "Import Loom",
1279
1283
  importing: "Importing...",
@@ -0,0 +1,99 @@
1
+ import {
2
+ callAction,
3
+ tryCallActionKeepalive,
4
+ } from "@agent-native/core/client/hooks";
5
+
6
+ import { getViewerSessionId } from "./viewer-session";
7
+
8
+ export interface PlaybackPositionRecord {
9
+ recordingId: string;
10
+ viewerKey: string;
11
+ viewerEmail: string | null;
12
+ positionMs: number;
13
+ updatedAt: string | null;
14
+ }
15
+
16
+ interface PlaybackPositionActionResult {
17
+ playbackPosition: PlaybackPositionRecord | null;
18
+ }
19
+
20
+ function parsePlaybackPosition(payload: unknown): number | null {
21
+ if (
22
+ !payload ||
23
+ typeof payload !== "object" ||
24
+ !("playbackPosition" in payload)
25
+ ) {
26
+ throw new Error("Invalid playback position response");
27
+ }
28
+ const playbackPosition = (payload as { playbackPosition?: unknown })
29
+ .playbackPosition;
30
+ if (playbackPosition === null) return null;
31
+ if (typeof playbackPosition !== "object") {
32
+ throw new Error("Invalid playback position payload");
33
+ }
34
+ const positionMs = (playbackPosition as { positionMs?: unknown }).positionMs;
35
+ if (
36
+ typeof positionMs !== "number" ||
37
+ !Number.isFinite(positionMs) ||
38
+ positionMs < 0
39
+ ) {
40
+ throw new Error("Invalid playback position payload");
41
+ }
42
+ return positionMs;
43
+ }
44
+
45
+ export async function getPlaybackPosition(
46
+ recordingId: string,
47
+ options: {
48
+ sessionId?: string;
49
+ signal?: AbortSignal;
50
+ } = {},
51
+ ): Promise<number | null> {
52
+ const sessionId = options.sessionId ?? getViewerSessionId();
53
+ const payload = await callAction<PlaybackPositionActionResult>(
54
+ "get-playback-position",
55
+ { recordingId, sessionId },
56
+ { method: "GET", signal: options.signal },
57
+ );
58
+ return parsePlaybackPosition(payload);
59
+ }
60
+
61
+ export async function savePlaybackPosition(
62
+ recordingId: string,
63
+ positionMs: number,
64
+ options: {
65
+ sessionId?: string;
66
+ signal?: AbortSignal;
67
+ keepalive?: boolean;
68
+ } = {},
69
+ ): Promise<void> {
70
+ const sessionId = options.sessionId ?? getViewerSessionId();
71
+ const params = { recordingId, positionMs, sessionId };
72
+
73
+ if (options.keepalive) {
74
+ const request = tryCallActionKeepalive<PlaybackPositionActionResult>(
75
+ "save-playback-position",
76
+ params,
77
+ { signal: options.signal },
78
+ );
79
+ if (!request.accepted) {
80
+ throw new Error(
81
+ `Failed to save playback position during unload (${request.reason})`,
82
+ );
83
+ }
84
+ const payload = await request.completion;
85
+ if (parsePlaybackPosition(payload) === null) {
86
+ throw new Error("Invalid playback position payload");
87
+ }
88
+ return;
89
+ }
90
+
91
+ const payload = await callAction<PlaybackPositionActionResult>(
92
+ "save-playback-position",
93
+ params,
94
+ { signal: options.signal },
95
+ );
96
+ if (parsePlaybackPosition(payload) === null) {
97
+ throw new Error("Invalid playback position payload");
98
+ }
99
+ }
@@ -0,0 +1,29 @@
1
+ const VIEWER_SESSION_STORAGE_KEY = "clips-view-session-id";
2
+ let inMemoryViewerSessionId: string | null = null;
3
+
4
+ function fallbackSessionId(): string {
5
+ return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
6
+ }
7
+
8
+ export function getViewerSessionId(): string {
9
+ if (typeof window === "undefined") {
10
+ if (inMemoryViewerSessionId) return inMemoryViewerSessionId;
11
+ inMemoryViewerSessionId = fallbackSessionId();
12
+ return inMemoryViewerSessionId;
13
+ }
14
+
15
+ try {
16
+ const existing = window.localStorage.getItem(VIEWER_SESSION_STORAGE_KEY);
17
+ if (existing) return existing;
18
+ const next =
19
+ typeof window.crypto?.randomUUID === "function"
20
+ ? window.crypto.randomUUID()
21
+ : fallbackSessionId();
22
+ window.localStorage.setItem(VIEWER_SESSION_STORAGE_KEY, next);
23
+ return next;
24
+ } catch {
25
+ if (inMemoryViewerSessionId) return inMemoryViewerSessionId;
26
+ inMemoryViewerSessionId = fallbackSessionId();
27
+ return inMemoryViewerSessionId;
28
+ }
29
+ }
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-08-05
4
+ ---
5
+
6
+ Clip buffering now shows buffering copy after playback starts.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-08-05
4
+ ---
5
+
6
+ Clips remembers your playback position when you reopen a clip.
@@ -18,6 +18,7 @@
18
18
  "test": "vitest --run"
19
19
  },
20
20
  "dependencies": {
21
+ "@radix-ui/react-alert-dialog": "^1.1.23",
21
22
  "@radix-ui/react-popover": "^1.1.15",
22
23
  "@radix-ui/react-tooltip": "^1.2.8",
23
24
  "@sentry/browser": "10.62.0",