@agent-native/core 0.100.2 → 0.101.2

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 (345) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +65 -0
  3. package/corpus/core/docs/content/locales/ar-SA/pr-visual-recap.mdx +48 -30
  4. package/corpus/core/docs/content/locales/ar-SA/template-plan.mdx +7 -0
  5. package/corpus/core/docs/content/locales/de-DE/pr-visual-recap.mdx +48 -30
  6. package/corpus/core/docs/content/locales/de-DE/template-plan.mdx +7 -0
  7. package/corpus/core/docs/content/locales/es-ES/pr-visual-recap.mdx +48 -30
  8. package/corpus/core/docs/content/locales/es-ES/template-plan.mdx +14 -0
  9. package/corpus/core/docs/content/locales/fr-FR/pr-visual-recap.mdx +48 -30
  10. package/corpus/core/docs/content/locales/fr-FR/template-plan.mdx +7 -0
  11. package/corpus/core/docs/content/locales/hi-IN/pr-visual-recap.mdx +48 -30
  12. package/corpus/core/docs/content/locales/hi-IN/template-plan.mdx +7 -0
  13. package/corpus/core/docs/content/locales/ja-JP/pr-visual-recap.mdx +48 -30
  14. package/corpus/core/docs/content/locales/ja-JP/template-plan.mdx +7 -0
  15. package/corpus/core/docs/content/locales/ko-KR/pr-visual-recap.mdx +48 -30
  16. package/corpus/core/docs/content/locales/ko-KR/template-plan.mdx +7 -0
  17. package/corpus/core/docs/content/locales/pt-BR/pr-visual-recap.mdx +48 -30
  18. package/corpus/core/docs/content/locales/pt-BR/template-plan.mdx +14 -0
  19. package/corpus/core/docs/content/locales/zh-CN/pr-visual-recap.mdx +48 -30
  20. package/corpus/core/docs/content/locales/zh-CN/template-plan.mdx +7 -0
  21. package/corpus/core/docs/content/locales/zh-TW/pr-visual-recap.mdx +48 -30
  22. package/corpus/core/docs/content/locales/zh-TW/template-plan.mdx +7 -0
  23. package/corpus/core/docs/content/pr-visual-recap.mdx +50 -32
  24. package/corpus/core/docs/content/template-plan.mdx +14 -0
  25. package/corpus/core/docs/content/toolkit-comments-review.mdx +16 -2
  26. package/corpus/core/package.json +4 -1
  27. package/corpus/core/src/a2a/index.ts +2 -1
  28. package/corpus/core/src/a2a/server.ts +34 -9
  29. package/corpus/core/src/agent/production-agent.ts +56 -10
  30. package/corpus/core/src/cli/create.ts +47 -19
  31. package/corpus/core/src/cli/pr-visual-recap-workflow.ts +2 -3
  32. package/corpus/core/src/cli/recap.ts +3 -4932
  33. package/corpus/core/src/cli/skills-content/visual-plan-skill.ts +6 -4
  34. package/corpus/core/src/cli/skills-content/visual-recap-skill.ts +7 -1
  35. package/corpus/core/src/client/AgentPanel.tsx +19 -17
  36. package/corpus/core/src/client/analytics.ts +8 -1
  37. package/corpus/core/src/client/chat/markdown-renderer.tsx +54 -8
  38. package/corpus/core/src/client/chat/message-components.tsx +8 -2
  39. package/corpus/core/src/client/clipboard.ts +28 -1
  40. package/corpus/core/src/client/guided-questions.tsx +4 -0
  41. package/corpus/core/src/client/i18n.tsx +2 -1
  42. package/corpus/core/src/client/index.ts +4 -0
  43. package/corpus/core/src/client/review/ReviewCommentComposer.tsx +108 -0
  44. package/corpus/core/src/client/review/ReviewThreadPanel.tsx +482 -150
  45. package/corpus/core/src/client/review/index.ts +8 -0
  46. package/corpus/core/src/client/review/use-review.ts +35 -1
  47. package/corpus/core/src/client/use-agent-chat-context.ts +3 -2
  48. package/corpus/core/src/review/actions/create-review-comment.ts +2 -1
  49. package/corpus/core/src/review/actions/get-review-feedback.ts +6 -11
  50. package/corpus/core/src/review/actions/list-review-comments.ts +38 -4
  51. package/corpus/core/src/review/actions/reply-review-comment.ts +33 -22
  52. package/corpus/core/src/review/actions/resolve-review-thread.ts +29 -2
  53. package/corpus/core/src/review/actions/send-review-thread-to-agent.ts +62 -0
  54. package/corpus/core/src/review/identity.ts +101 -0
  55. package/corpus/core/src/review/index.ts +14 -0
  56. package/corpus/core/src/review/store.ts +315 -8
  57. package/corpus/core/src/review/types.ts +4 -0
  58. package/corpus/core/src/server/action-discovery.ts +4 -0
  59. package/corpus/core/src/server/action-routes.ts +125 -4
  60. package/corpus/core/src/server/agent-chat/plugin-options.ts +16 -0
  61. package/corpus/core/src/server/agent-chat-plugin.ts +1 -0
  62. package/corpus/core/src/server/index.ts +8 -0
  63. package/corpus/core/src/vite/action-types-plugin.ts +4 -0
  64. package/corpus/templates/analytics/changelog/2026-07-14-daily-dashboard-email-captures-authenticate-with-a-sessi.md +6 -0
  65. package/corpus/templates/analytics/server/lib/dashboard-report.ts +156 -3
  66. package/corpus/templates/assets/app/components/generation/GenerationResults.tsx +402 -142
  67. package/corpus/templates/assets/app/i18n/zh-TW.ts +1 -0
  68. package/corpus/templates/assets/app/i18n-data.ts +1 -0
  69. package/corpus/templates/assets/app/routes/library.tsx +187 -48
  70. package/corpus/templates/assets/changelog/2026-07-13-merged-the-candidates-panel-into-the-library-as-a-drafts-tab.md +6 -0
  71. package/corpus/templates/chat/app/lib/agent-page.tsx +40 -0
  72. package/corpus/templates/chat/app/routes/agent.tsx +5 -3
  73. package/corpus/templates/chat/changelog/2026-07-14-fixed-chat-template-startup-with-older-core-versions.md +6 -0
  74. package/corpus/templates/clips/.agents/skills/ai-video-tools/SKILL.md +5 -0
  75. package/corpus/templates/clips/AGENTS.md +4 -0
  76. package/corpus/templates/clips/actions/get-feature-flags.ts +30 -0
  77. package/corpus/templates/clips/actions/lib/transcript-preview.ts +48 -0
  78. package/corpus/templates/clips/actions/request-transcript.ts +41 -1
  79. package/corpus/templates/clips/actions/view-screen.ts +5 -9
  80. package/corpus/templates/clips/app/components/library/library-layout.tsx +1 -1
  81. package/corpus/templates/clips/app/components/player/video-player.tsx +39 -1
  82. package/corpus/templates/clips/app/hooks/use-desktop-promo.ts +6 -12
  83. package/corpus/templates/clips/app/hooks/use-mse-video-source.ts +146 -0
  84. package/corpus/templates/clips/app/lib/capture-install-options.ts +21 -0
  85. package/corpus/templates/clips/app/lib/fmp4.ts +271 -0
  86. package/corpus/templates/clips/app/lib/mse-video-loader.ts +585 -0
  87. package/corpus/templates/clips/app/routes/_app.dictate.tsx +0 -4
  88. package/corpus/templates/clips/app/routes/_app.meetings.$meetingId.tsx +5 -13
  89. package/corpus/templates/clips/app/routes/_app.meetings._index.tsx +2 -37
  90. package/corpus/templates/clips/app/routes/download.tsx +3 -2
  91. package/corpus/templates/clips/changelog/2026-07-10-shared-clips-now-start-playing-instantly-instead-of-showing-.md +6 -0
  92. package/corpus/templates/clips/changelog/2026-07-14-clips-now-distinguishes-transcript-previews-from-incomplete-.md +6 -0
  93. package/corpus/templates/clips/changelog/2026-07-14-desktop-app-prompts-stay-hidden-after-you-download-the-insta.md +6 -0
  94. package/corpus/templates/clips/desktop/src/lib/recorder.ts +5 -0
  95. package/corpus/templates/clips/desktop/src/overlays/recording-pill.tsx +10 -0
  96. package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +4 -0
  97. package/corpus/templates/clips/desktop/src-tauri/src/native_screen/custom_capture.rs +2518 -0
  98. package/corpus/templates/clips/desktop/src-tauri/src/native_screen/live_upload.rs +353 -0
  99. package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +558 -67
  100. package/corpus/templates/clips/desktop/src-tauri/src/recording_indicator.rs +11 -1
  101. package/corpus/templates/clips/desktop/src-tauri/src/remote_flags.rs +188 -0
  102. package/corpus/templates/clips/desktop/src-tauri/src/whisper_speech.rs +1 -1
  103. package/corpus/templates/clips/server/lib/post-finalize-dispatch.ts +1 -0
  104. package/corpus/templates/clips/server/plugins/agent-chat.ts +5 -0
  105. package/corpus/templates/clips/server/routes/api/_agent-native-background/post-finalize-worker.post.ts +5 -1
  106. package/corpus/templates/clips/shared/feature-flags.ts +41 -0
  107. package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +3 -0
  108. package/corpus/templates/design/.agents/skills/design-review-feedback/SKILL.md +42 -0
  109. package/corpus/templates/design/AGENTS.md +6 -0
  110. package/corpus/templates/design/README.md +1 -0
  111. package/corpus/templates/design/actions/navigate.ts +4 -4
  112. package/corpus/templates/design/actions/view-screen.ts +116 -2
  113. package/corpus/templates/design/agent-native.app-skill.json +5 -0
  114. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +52 -59
  115. package/corpus/templates/design/app/components/design/DesignExtensionsPanel.tsx +13 -9
  116. package/corpus/templates/design/app/components/design/EditPanel.tsx +79 -11
  117. package/corpus/templates/design/app/components/design/LayersPanel.tsx +78 -65
  118. package/corpus/templates/design/app/components/design/ReviewCommentsPanel.tsx +161 -0
  119. package/corpus/templates/design/app/components/design/ReviewStatusControl.tsx +96 -0
  120. package/corpus/templates/design/app/components/design/bridge/hit-test.bridge.ts +166 -0
  121. package/corpus/templates/design/app/components/layout/Layout.tsx +1 -0
  122. package/corpus/templates/design/app/components/visual-editor/ReviewCanvasPins.tsx +1077 -0
  123. package/corpus/templates/design/app/components/visual-editor/index.ts +1 -0
  124. package/corpus/templates/design/app/components/visual-editor/review-canvas-state.ts +42 -0
  125. package/corpus/templates/design/app/hooks/use-design-systems.ts +2 -2
  126. package/corpus/templates/design/app/hooks/use-navigation-state.ts +9 -6
  127. package/corpus/templates/design/app/hooks/use-question-flow.ts +7 -1
  128. package/corpus/templates/design/app/i18n/ar-SA.ts +56 -1
  129. package/corpus/templates/design/app/i18n/de-DE.ts +57 -1
  130. package/corpus/templates/design/app/i18n/en-US.ts +56 -1
  131. package/corpus/templates/design/app/i18n/es-ES.ts +56 -1
  132. package/corpus/templates/design/app/i18n/fr-FR.ts +57 -1
  133. package/corpus/templates/design/app/i18n/hi-IN.ts +56 -1
  134. package/corpus/templates/design/app/i18n/ja-JP.ts +56 -1
  135. package/corpus/templates/design/app/i18n/ko-KR.ts +56 -1
  136. package/corpus/templates/design/app/i18n/pt-BR.ts +57 -1
  137. package/corpus/templates/design/app/i18n/zh-CN.ts +56 -1
  138. package/corpus/templates/design/app/i18n/zh-TW.ts +51 -0
  139. package/corpus/templates/design/app/pages/Present.tsx +172 -14
  140. package/corpus/templates/design/app/pages/design-editor/overview-camera.ts +23 -0
  141. package/corpus/templates/design/app/pages/design-editor/tool-state.ts +10 -0
  142. package/corpus/templates/design/app/pages/present-review-state.ts +18 -0
  143. package/corpus/templates/design/app/public-routes.ts +8 -0
  144. package/corpus/templates/design/app/root.tsx +7 -6
  145. package/corpus/templates/design/changelog/2026-07-13-dragged-design-assets-now-appear-at-the-visible-drop-locatio.md +6 -0
  146. package/corpus/templates/design/changelog/2026-07-13-reviewers-can-pin-comments-on-shared-designs-and-apply-verif.md +6 -0
  147. package/corpus/templates/design/server/plugins/agent-chat.ts +10 -0
  148. package/corpus/templates/design/server/plugins/auth.ts +7 -5
  149. package/corpus/templates/design/server/plugins/review.ts +9 -0
  150. package/corpus/templates/design/shared/review-anchor.ts +83 -0
  151. package/corpus/templates/design/shared/review-summary.ts +25 -0
  152. package/corpus/templates/forms/.agents/skills/form-publishing/SKILL.md +2 -0
  153. package/corpus/templates/forms/AGENTS.md +4 -0
  154. package/corpus/templates/forms/actions/create-form.ts +2 -1
  155. package/corpus/templates/forms/actions/update-form.ts +5 -2
  156. package/corpus/templates/forms/app/i18n/ar-SA.ts +3 -0
  157. package/corpus/templates/forms/app/i18n/de-DE.ts +3 -0
  158. package/corpus/templates/forms/app/i18n/en-US.ts +3 -0
  159. package/corpus/templates/forms/app/i18n/es-ES.ts +3 -0
  160. package/corpus/templates/forms/app/i18n/fr-FR.ts +3 -0
  161. package/corpus/templates/forms/app/i18n/hi-IN.ts +3 -0
  162. package/corpus/templates/forms/app/i18n/ja-JP.ts +3 -0
  163. package/corpus/templates/forms/app/i18n/ko-KR.ts +3 -0
  164. package/corpus/templates/forms/app/i18n/pt-BR.ts +3 -0
  165. package/corpus/templates/forms/app/i18n/zh-CN.ts +3 -0
  166. package/corpus/templates/forms/app/i18n/zh-TW.ts +3 -0
  167. package/corpus/templates/forms/app/pages/FormBuilderPage.tsx +19 -0
  168. package/corpus/templates/forms/changelog/2026-07-14-fixed-the-ask-forms-loading-input-appearing-above-the-welcom.md +6 -0
  169. package/corpus/templates/forms/changelog/2026-07-14-form-social-previews-now-show-the-form-title-description-and.md +6 -0
  170. package/corpus/templates/forms/changelog/2026-07-14-forms-can-email-the-form-owner-when-new-responses-arrive.md +6 -0
  171. package/corpus/templates/forms/server/handlers/submissions.ts +17 -0
  172. package/corpus/templates/forms/server/lib/form-og-image.ts +64 -6
  173. package/corpus/templates/forms/server/lib/public-form-ssr.ts +6 -2
  174. package/corpus/templates/forms/server/lib/response-email.ts +65 -0
  175. package/corpus/templates/forms/server/plugins/agent-chat.ts +1 -0
  176. package/corpus/templates/forms/server/routes/api/forms/og/[...slug]/og.png.get.ts +184 -0
  177. package/corpus/templates/forms/shared/types.ts +2 -0
  178. package/corpus/templates/plan/.agents/skills/visual-plan/SKILL.md +6 -4
  179. package/corpus/templates/plan/.agents/skills/visual-recap/SKILL.md +7 -1
  180. package/dist/a2a/index.d.ts +2 -1
  181. package/dist/a2a/index.d.ts.map +1 -1
  182. package/dist/a2a/index.js +1 -1
  183. package/dist/a2a/index.js.map +1 -1
  184. package/dist/a2a/server.d.ts +25 -0
  185. package/dist/a2a/server.d.ts.map +1 -1
  186. package/dist/a2a/server.js +30 -6
  187. package/dist/a2a/server.js.map +1 -1
  188. package/dist/agent/production-agent.d.ts +2 -0
  189. package/dist/agent/production-agent.d.ts.map +1 -1
  190. package/dist/agent/production-agent.js +37 -12
  191. package/dist/agent/production-agent.js.map +1 -1
  192. package/dist/cli/create.d.ts +5 -3
  193. package/dist/cli/create.d.ts.map +1 -1
  194. package/dist/cli/create.js +44 -19
  195. package/dist/cli/create.js.map +1 -1
  196. package/dist/cli/pr-visual-recap-workflow.d.ts +2 -2
  197. package/dist/cli/pr-visual-recap-workflow.d.ts.map +1 -1
  198. package/dist/cli/pr-visual-recap-workflow.js +2 -2
  199. package/dist/cli/pr-visual-recap-workflow.js.map +1 -1
  200. package/dist/cli/recap.d.ts +3 -562
  201. package/dist/cli/recap.d.ts.map +1 -1
  202. package/dist/cli/recap.js +3 -3875
  203. package/dist/cli/recap.js.map +1 -1
  204. package/dist/cli/skills-content/visual-plan-skill.d.ts +1 -1
  205. package/dist/cli/skills-content/visual-plan-skill.d.ts.map +1 -1
  206. package/dist/cli/skills-content/visual-plan-skill.js +6 -4
  207. package/dist/cli/skills-content/visual-plan-skill.js.map +1 -1
  208. package/dist/cli/skills-content/visual-recap-skill.d.ts +1 -1
  209. package/dist/cli/skills-content/visual-recap-skill.d.ts.map +1 -1
  210. package/dist/cli/skills-content/visual-recap-skill.js +7 -1
  211. package/dist/cli/skills-content/visual-recap-skill.js.map +1 -1
  212. package/dist/client/AgentPanel.d.ts.map +1 -1
  213. package/dist/client/AgentPanel.js +3 -3
  214. package/dist/client/AgentPanel.js.map +1 -1
  215. package/dist/client/analytics.d.ts +5 -0
  216. package/dist/client/analytics.d.ts.map +1 -1
  217. package/dist/client/analytics.js +3 -1
  218. package/dist/client/analytics.js.map +1 -1
  219. package/dist/client/chat/markdown-renderer.d.ts +1 -0
  220. package/dist/client/chat/markdown-renderer.d.ts.map +1 -1
  221. package/dist/client/chat/markdown-renderer.js +36 -1
  222. package/dist/client/chat/markdown-renderer.js.map +1 -1
  223. package/dist/client/chat/message-components.d.ts.map +1 -1
  224. package/dist/client/chat/message-components.js +5 -2
  225. package/dist/client/chat/message-components.js.map +1 -1
  226. package/dist/client/clipboard.d.ts +3 -1
  227. package/dist/client/clipboard.d.ts.map +1 -1
  228. package/dist/client/clipboard.js +24 -1
  229. package/dist/client/clipboard.js.map +1 -1
  230. package/dist/client/guided-questions.d.ts +3 -1
  231. package/dist/client/guided-questions.d.ts.map +1 -1
  232. package/dist/client/guided-questions.js +2 -1
  233. package/dist/client/guided-questions.js.map +1 -1
  234. package/dist/client/i18n.d.ts.map +1 -1
  235. package/dist/client/i18n.js +3 -1
  236. package/dist/client/i18n.js.map +1 -1
  237. package/dist/client/index.d.ts +1 -1
  238. package/dist/client/index.d.ts.map +1 -1
  239. package/dist/client/index.js +1 -1
  240. package/dist/client/index.js.map +1 -1
  241. package/dist/client/review/ReviewCommentComposer.d.ts +18 -0
  242. package/dist/client/review/ReviewCommentComposer.d.ts.map +1 -0
  243. package/dist/client/review/ReviewCommentComposer.js +30 -0
  244. package/dist/client/review/ReviewCommentComposer.js.map +1 -0
  245. package/dist/client/review/ReviewThreadPanel.d.ts +28 -1
  246. package/dist/client/review/ReviewThreadPanel.d.ts.map +1 -1
  247. package/dist/client/review/ReviewThreadPanel.js +151 -39
  248. package/dist/client/review/ReviewThreadPanel.js.map +1 -1
  249. package/dist/client/review/index.d.ts +3 -2
  250. package/dist/client/review/index.d.ts.map +1 -1
  251. package/dist/client/review/index.js +2 -1
  252. package/dist/client/review/index.js.map +1 -1
  253. package/dist/client/review/use-review.d.ts +23 -0
  254. package/dist/client/review/use-review.d.ts.map +1 -1
  255. package/dist/client/review/use-review.js +3 -0
  256. package/dist/client/review/use-review.js.map +1 -1
  257. package/dist/client/use-agent-chat-context.d.ts +1 -1
  258. package/dist/client/use-agent-chat-context.d.ts.map +1 -1
  259. package/dist/client/use-agent-chat-context.js +4 -2
  260. package/dist/client/use-agent-chat-context.js.map +1 -1
  261. package/dist/collab/awareness.d.ts +2 -2
  262. package/dist/collab/awareness.d.ts.map +1 -1
  263. package/dist/collab/struct-routes.d.ts +1 -1
  264. package/dist/notifications/routes.d.ts +3 -3
  265. package/dist/observability/routes.d.ts +5 -5
  266. package/dist/progress/routes.d.ts +1 -1
  267. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  268. package/dist/resources/handlers.d.ts +2 -2
  269. package/dist/review/actions/create-review-comment.js +2 -1
  270. package/dist/review/actions/create-review-comment.js.map +1 -1
  271. package/dist/review/actions/get-review-feedback.js +6 -11
  272. package/dist/review/actions/get-review-feedback.js.map +1 -1
  273. package/dist/review/actions/list-review-comments.d.ts +1 -0
  274. package/dist/review/actions/list-review-comments.js +25 -4
  275. package/dist/review/actions/list-review-comments.js.map +1 -1
  276. package/dist/review/actions/reply-review-comment.js +12 -5
  277. package/dist/review/actions/reply-review-comment.js.map +1 -1
  278. package/dist/review/actions/resolve-review-thread.d.ts +3 -0
  279. package/dist/review/actions/resolve-review-thread.js +20 -3
  280. package/dist/review/actions/resolve-review-thread.js.map +1 -1
  281. package/dist/review/actions/send-review-thread-to-agent.d.ts +17 -0
  282. package/dist/review/actions/send-review-thread-to-agent.d.ts.map +1 -0
  283. package/dist/review/actions/send-review-thread-to-agent.js +49 -0
  284. package/dist/review/actions/send-review-thread-to-agent.js.map +1 -0
  285. package/dist/review/identity.d.ts +6 -0
  286. package/dist/review/identity.d.ts.map +1 -0
  287. package/dist/review/identity.js +68 -0
  288. package/dist/review/identity.js.map +1 -0
  289. package/dist/review/index.d.ts +3 -1
  290. package/dist/review/index.d.ts.map +1 -1
  291. package/dist/review/index.js +2 -1
  292. package/dist/review/index.js.map +1 -1
  293. package/dist/review/store.d.ts +36 -0
  294. package/dist/review/store.d.ts.map +1 -1
  295. package/dist/review/store.js +223 -8
  296. package/dist/review/store.js.map +1 -1
  297. package/dist/review/types.d.ts +4 -0
  298. package/dist/review/types.d.ts.map +1 -1
  299. package/dist/review/types.js.map +1 -1
  300. package/dist/secrets/routes.d.ts +9 -9
  301. package/dist/server/action-discovery.d.ts.map +1 -1
  302. package/dist/server/action-discovery.js +4 -0
  303. package/dist/server/action-discovery.js.map +1 -1
  304. package/dist/server/action-routes.d.ts +45 -0
  305. package/dist/server/action-routes.d.ts.map +1 -1
  306. package/dist/server/action-routes.js +71 -5
  307. package/dist/server/action-routes.js.map +1 -1
  308. package/dist/server/agent-chat/plugin-options.d.ts +16 -0
  309. package/dist/server/agent-chat/plugin-options.d.ts.map +1 -1
  310. package/dist/server/agent-chat/plugin-options.js.map +1 -1
  311. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  312. package/dist/server/agent-chat-plugin.js +1 -0
  313. package/dist/server/agent-chat-plugin.js.map +1 -1
  314. package/dist/server/index.d.ts +3 -1
  315. package/dist/server/index.d.ts.map +1 -1
  316. package/dist/server/index.js +2 -0
  317. package/dist/server/index.js.map +1 -1
  318. package/dist/vite/action-types-plugin.d.ts.map +1 -1
  319. package/dist/vite/action-types-plugin.js +4 -0
  320. package/dist/vite/action-types-plugin.js.map +1 -1
  321. package/docs/content/locales/ar-SA/pr-visual-recap.mdx +48 -30
  322. package/docs/content/locales/ar-SA/template-plan.mdx +7 -0
  323. package/docs/content/locales/de-DE/pr-visual-recap.mdx +48 -30
  324. package/docs/content/locales/de-DE/template-plan.mdx +7 -0
  325. package/docs/content/locales/es-ES/pr-visual-recap.mdx +48 -30
  326. package/docs/content/locales/es-ES/template-plan.mdx +14 -0
  327. package/docs/content/locales/fr-FR/pr-visual-recap.mdx +48 -30
  328. package/docs/content/locales/fr-FR/template-plan.mdx +7 -0
  329. package/docs/content/locales/hi-IN/pr-visual-recap.mdx +48 -30
  330. package/docs/content/locales/hi-IN/template-plan.mdx +7 -0
  331. package/docs/content/locales/ja-JP/pr-visual-recap.mdx +48 -30
  332. package/docs/content/locales/ja-JP/template-plan.mdx +7 -0
  333. package/docs/content/locales/ko-KR/pr-visual-recap.mdx +48 -30
  334. package/docs/content/locales/ko-KR/template-plan.mdx +7 -0
  335. package/docs/content/locales/pt-BR/pr-visual-recap.mdx +48 -30
  336. package/docs/content/locales/pt-BR/template-plan.mdx +14 -0
  337. package/docs/content/locales/zh-CN/pr-visual-recap.mdx +48 -30
  338. package/docs/content/locales/zh-CN/template-plan.mdx +7 -0
  339. package/docs/content/locales/zh-TW/pr-visual-recap.mdx +48 -30
  340. package/docs/content/locales/zh-TW/template-plan.mdx +7 -0
  341. package/docs/content/pr-visual-recap.mdx +50 -32
  342. package/docs/content/template-plan.mdx +14 -0
  343. package/docs/content/toolkit-comments-review.mdx +16 -2
  344. package/package.json +4 -1
  345. package/corpus/templates/forms/server/routes/api/forms/og/[slug]/og.png.get.ts +0 -45
@@ -37,7 +37,14 @@ import {
37
37
  IconX,
38
38
  } from "@tabler/icons-react";
39
39
  import { useQuery, useQueryClient } from "@tanstack/react-query";
40
- import { useCallback, useEffect, useMemo, useRef, useState } from "react";
40
+ import {
41
+ useCallback,
42
+ useEffect,
43
+ useMemo,
44
+ useRef,
45
+ useState,
46
+ type ReactNode,
47
+ } from "react";
41
48
  import {
42
49
  Link,
43
50
  useSearchParams,
@@ -1094,26 +1101,55 @@ function LibraryKitSelector({
1094
1101
  );
1095
1102
  }
1096
1103
 
1097
- function AllAssetsBrowser() {
1104
+ function AllAssetsBrowser({
1105
+ foldersByLibraryId = {},
1106
+ }: {
1107
+ foldersByLibraryId?: Record<string, any[]>;
1108
+ }) {
1098
1109
  const t = useT();
1099
1110
  const navigate = useNavigate();
1100
- const [query, setQuery] = useState("");
1101
- const [assetTab, setAssetTab] = useState<AssetTab>("all");
1111
+ const queryClient = useQueryClient();
1112
+ const [searchParams, setSearchParams] = useSearchParams();
1113
+ const searchParamsKey = searchParams.toString();
1114
+ // The root Library view keeps its tab/search in the URL so deep links,
1115
+ // refreshes, and agent `navigate` commands are honored (the framework's
1116
+ // useNavigationState reads the same `?tab=`/`?q=` params). Absent a tab param,
1117
+ // default to Drafts.
1118
+ const urlAssetTab = useMemo<AssetTab>(() => {
1119
+ const tab = new URLSearchParams(searchParamsKey).get("tab");
1120
+ return tab === "drafts" || tab === "generated" || tab === "references"
1121
+ ? tab
1122
+ : "drafts";
1123
+ }, [searchParamsKey]);
1124
+ const urlQuery = useMemo(
1125
+ () => new URLSearchParams(searchParamsKey).get("q") ?? "",
1126
+ [searchParamsKey],
1127
+ );
1128
+ const [query, setQuery] = useState(urlQuery);
1129
+ const [assetTab, setAssetTab] = useState<AssetTab>(urlAssetTab);
1102
1130
  const [previewAsset, setPreviewAsset] = useState<Asset | null>(null);
1103
1131
  const [standaloneSelection, setStandaloneSelection] = useState<ReturnType<
1104
1132
  typeof assetPayload
1105
1133
  > | null>(null);
1106
1134
  const [standaloneCopyOk, setStandaloneCopyOk] = useState(false);
1107
1135
 
1136
+ const isDraftsTab = assetTab === "drafts";
1137
+
1138
+ // The Drafts tab renders its own candidate queries via LibraryCandidateStage,
1139
+ // so skip the cross-library asset scan while it is the active tab.
1108
1140
  const {
1109
1141
  data: assetData,
1110
1142
  isLoading,
1111
1143
  isError,
1112
1144
  isFetching,
1113
1145
  refetch,
1114
- } = useActionQuery("list-assets", {
1115
- query: query.trim() || undefined,
1116
- } as any) as {
1146
+ } = useActionQuery(
1147
+ "list-assets",
1148
+ {
1149
+ query: query.trim() || undefined,
1150
+ } as any,
1151
+ { enabled: !isDraftsTab } as any,
1152
+ ) as {
1117
1153
  data?: { assets?: Asset[] };
1118
1154
  isLoading: boolean;
1119
1155
  isError: boolean;
@@ -1127,11 +1163,11 @@ function AllAssetsBrowser() {
1127
1163
  [allAssets, assetTab],
1128
1164
  );
1129
1165
  const visibleAssetCount = assets.length;
1166
+ // The badge only renders on the Generated/References tabs, which are always a
1167
+ // filtered subset, so report the shown count rather than the library total.
1130
1168
  const assetCountLabel = isLoading
1131
1169
  ? t("library.loading")
1132
- : query.trim() || assetTab !== "all"
1133
- ? t("library.shownCount", { count: visibleAssetCount })
1134
- : t("library.assetCount", { count: allAssets.length });
1170
+ : t("library.shownCount", { count: visibleAssetCount });
1135
1171
  const standaloneSelectionText = useMemo(
1136
1172
  () =>
1137
1173
  standaloneSelection
@@ -1166,6 +1202,57 @@ function AllAssetsBrowser() {
1166
1202
  void copyStandaloneSelection(payload);
1167
1203
  }
1168
1204
 
1205
+ // Keep local state in sync when the URL changes externally (back/forward,
1206
+ // agent navigation, deep links) since the component stays mounted.
1207
+ useEffect(() => {
1208
+ setAssetTab(urlAssetTab);
1209
+ }, [urlAssetTab]);
1210
+ useEffect(() => {
1211
+ setQuery(urlQuery);
1212
+ }, [urlQuery]);
1213
+
1214
+ const handleAssetTabChange = useCallback(
1215
+ (value: AssetTab) => {
1216
+ setAssetTab(value);
1217
+ setSearchParams(
1218
+ (prev) => {
1219
+ const next = new URLSearchParams(prev);
1220
+ // Drafts is the default, so keep it out of the URL for clean links.
1221
+ if (value === "drafts") next.delete("tab");
1222
+ else next.set("tab", value);
1223
+ return next;
1224
+ },
1225
+ { replace: true },
1226
+ );
1227
+ },
1228
+ [setSearchParams],
1229
+ );
1230
+
1231
+ const handleQueryChange = useCallback(
1232
+ (value: string) => {
1233
+ setQuery(value);
1234
+ setSearchParams(
1235
+ (prev) => {
1236
+ const next = new URLSearchParams(prev);
1237
+ if (value.trim()) next.set("q", value);
1238
+ else next.delete("q");
1239
+ return next;
1240
+ },
1241
+ { replace: true },
1242
+ );
1243
+ },
1244
+ [setSearchParams],
1245
+ );
1246
+
1247
+ // The Drafts tab's candidate queries live inside LibraryCandidateStage;
1248
+ // refetch them by key so the error state offers a working retry.
1249
+ const retryDrafts = useCallback(() => {
1250
+ void queryClient.refetchQueries({
1251
+ queryKey: ["app-state", assetVariantStateKey(null)],
1252
+ });
1253
+ void queryClient.refetchQueries({ queryKey: ["action", "list-assets"] });
1254
+ }, [queryClient]);
1255
+
1169
1256
  return (
1170
1257
  <div className="flex min-w-0 flex-col">
1171
1258
  <div className="border-b border-border px-4 py-3 md:px-6">
@@ -1173,10 +1260,10 @@ function AllAssetsBrowser() {
1173
1260
  <div className="flex min-w-0 items-center gap-2">
1174
1261
  <Tabs
1175
1262
  value={assetTab}
1176
- onValueChange={(value) => setAssetTab(value as AssetTab)}
1263
+ onValueChange={(value) => handleAssetTabChange(value as AssetTab)}
1177
1264
  >
1178
1265
  <TabsList className="h-9">
1179
- <TabsTrigger value="all">{t("library.tabsAll")}</TabsTrigger>
1266
+ <TabsTrigger value="drafts">{t("library.drafts")}</TabsTrigger>
1180
1267
  <TabsTrigger value="generated">
1181
1268
  {t("library.generated")}
1182
1269
  </TabsTrigger>
@@ -1185,24 +1272,30 @@ function AllAssetsBrowser() {
1185
1272
  </TabsTrigger>
1186
1273
  </TabsList>
1187
1274
  </Tabs>
1188
- <Badge
1189
- variant="secondary"
1190
- className="h-6 max-w-full rounded-full px-2 text-xs"
1191
- >
1192
- {assetCountLabel}
1193
- </Badge>
1194
- </div>
1195
- <div className="flex h-9 min-w-0 flex-1 items-center gap-2 rounded-md border border-border/70 bg-background px-3 focus-within:ring-1 focus-within:ring-ring sm:max-w-sm">
1196
- <IconSearch className="h-4 w-4 shrink-0 text-muted-foreground" />
1197
- <input
1198
- type="search"
1199
- value={query}
1200
- onInput={(event) => setQuery(event.currentTarget.value)}
1201
- onChange={(event) => setQuery(event.target.value)}
1202
- placeholder={t("library.searchAssets")}
1203
- className="h-full min-w-0 flex-1 bg-transparent text-sm outline-none placeholder:text-muted-foreground"
1204
- />
1275
+ {!isDraftsTab && (
1276
+ <Badge
1277
+ variant="secondary"
1278
+ className="h-6 max-w-full rounded-full px-2 text-xs"
1279
+ >
1280
+ {assetCountLabel}
1281
+ </Badge>
1282
+ )}
1205
1283
  </div>
1284
+ {!isDraftsTab && (
1285
+ <div className="flex h-9 min-w-0 flex-1 items-center gap-2 rounded-md border border-border/70 bg-background px-3 focus-within:ring-1 focus-within:ring-ring sm:max-w-sm">
1286
+ <IconSearch className="h-4 w-4 shrink-0 text-muted-foreground" />
1287
+ <input
1288
+ type="search"
1289
+ value={query}
1290
+ onInput={(event) =>
1291
+ handleQueryChange(event.currentTarget.value)
1292
+ }
1293
+ onChange={(event) => handleQueryChange(event.target.value)}
1294
+ placeholder={t("library.searchAssets")}
1295
+ className="h-full min-w-0 flex-1 bg-transparent text-sm outline-none placeholder:text-muted-foreground"
1296
+ />
1297
+ </div>
1298
+ )}
1206
1299
  </div>
1207
1300
  </div>
1208
1301
 
@@ -1278,7 +1371,31 @@ function AllAssetsBrowser() {
1278
1371
  )}
1279
1372
 
1280
1373
  <main className="p-4 md:p-6">
1281
- {isLoading ? (
1374
+ {isDraftsTab ? (
1375
+ <LibraryCandidateStage
1376
+ activeLibraryId={null}
1377
+ foldersByLibraryId={foldersByLibraryId}
1378
+ inline
1379
+ emptyState={
1380
+ <div className="flex min-h-64 items-center justify-center text-center">
1381
+ <div className="max-w-sm text-sm text-muted-foreground">
1382
+ {t("library.noDrafts")}
1383
+ </div>
1384
+ </div>
1385
+ }
1386
+ errorState={
1387
+ <div className="flex min-h-64 flex-col items-center justify-center gap-3 px-6 text-center">
1388
+ <IconAlertTriangle className="size-9 text-destructive" />
1389
+ <p className="max-w-sm text-sm text-muted-foreground">
1390
+ {t("audit.unknownError")}
1391
+ </p>
1392
+ <Button size="sm" variant="outline" onClick={retryDrafts}>
1393
+ {t("brandKitDetail.refresh")}
1394
+ </Button>
1395
+ </div>
1396
+ }
1397
+ />
1398
+ ) : isLoading ? (
1282
1399
  <div className="assets-library-grid grid grid-cols-2 gap-4">
1283
1400
  {Array.from({ length: 12 }).map((_, index) => (
1284
1401
  <Skeleton key={index} className="aspect-[4/3] rounded-lg" />
@@ -1593,12 +1710,16 @@ function LibraryCandidateStage({
1593
1710
  variantScopeId = null,
1594
1711
  onUseAsset,
1595
1712
  inline = false,
1713
+ emptyState = null,
1714
+ errorState = null,
1596
1715
  }: {
1597
1716
  activeLibraryId?: string | null;
1598
1717
  foldersByLibraryId?: Record<string, any[]>;
1599
1718
  variantScopeId?: string | null;
1600
1719
  onUseAsset?: (asset: Asset) => void;
1601
1720
  inline?: boolean;
1721
+ emptyState?: ReactNode;
1722
+ errorState?: ReactNode;
1602
1723
  }) {
1603
1724
  const t = useT();
1604
1725
  const queryClient = useQueryClient();
@@ -1608,7 +1729,11 @@ function LibraryCandidateStage({
1608
1729
  const [promotingReferenceKeys, setPromotingReferenceKeys] = useState<
1609
1730
  Set<string>
1610
1731
  >(() => new Set());
1611
- const { data: variants } = useQuery({
1732
+ const {
1733
+ data: variants,
1734
+ isLoading: variantsLoading,
1735
+ isError: variantsError,
1736
+ } = useQuery({
1612
1737
  queryKey: ["app-state", assetVariantStateKey(variantScopeId)],
1613
1738
  queryFn: ({ signal }) => {
1614
1739
  return readClientAppState<AssetVariantState>(
@@ -1626,11 +1751,15 @@ function LibraryCandidateStage({
1626
1751
  { id: activeLibraryId ?? "" } as any,
1627
1752
  { enabled: Boolean(activeLibraryId) } as any,
1628
1753
  ) as { data?: { library?: Library; assets?: Asset[]; folders?: any[] } };
1629
- const { data: allCandidateData } = useActionQuery(
1754
+ const {
1755
+ data: allCandidateData,
1756
+ isLoading: allCandidatesLoading,
1757
+ isError: allCandidatesError,
1758
+ } = useActionQuery(
1630
1759
  "list-assets",
1631
1760
  { includeCandidates: true, status: "candidate" } as any,
1632
1761
  { enabled: isAllAssetsStage } as any,
1633
- ) as { data?: { assets?: Asset[] } };
1762
+ ) as { data?: { assets?: Asset[] }; isLoading: boolean; isError: boolean };
1634
1763
  const saveGenerated = useActionMutation("save-generated-image");
1635
1764
  const updateAsset = useActionMutation("update-asset");
1636
1765
  const libraryAssets = isAllAssetsStage
@@ -1675,10 +1804,20 @@ function LibraryCandidateStage({
1675
1804
  [libraryAssets, liveAssetIds],
1676
1805
  );
1677
1806
  const totalCount = slots.length + draftAssets.length;
1678
-
1679
- if (totalCount === 0) return null;
1807
+ // Don't flash the empty state before the candidate sources have resolved, and
1808
+ // don't misreport a load failure as "no drafts".
1809
+ const candidatesLoading =
1810
+ variantsLoading || (isAllAssetsStage && allCandidatesLoading);
1811
+ const candidatesError =
1812
+ variantsError || (isAllAssetsStage && allCandidatesError);
1813
+
1814
+ if (totalCount === 0) {
1815
+ if (candidatesLoading) return null;
1816
+ if (candidatesError) return errorState ? <>{errorState}</> : null;
1817
+ return emptyState ? <>{emptyState}</> : null;
1818
+ }
1680
1819
  const stageLibraryId = liveLibraryId ?? draftAssets[0]?.libraryId ?? null;
1681
- if (!stageLibraryId) return null;
1820
+ if (!stageLibraryId) return emptyState ? <>{emptyState}</> : null;
1682
1821
 
1683
1822
  function invalidateStage(
1684
1823
  libraryIdToInvalidate: string | null = stageLibraryId,
@@ -1982,22 +2121,22 @@ export function LibraryWorkspace({
1982
2121
  </Button>
1983
2122
  </div>
1984
2123
  ) : routeSelectedLibraryId || hasLibraries ? (
1985
- <>
1986
- <LibraryCandidateStage
1987
- activeLibraryId={routeSelectedLibraryId}
1988
- foldersByLibraryId={foldersByLibraryId}
1989
- />
1990
- <div className="min-w-0">
1991
- {routeSelectedLibraryId ? (
2124
+ <div className="min-w-0">
2125
+ {routeSelectedLibraryId ? (
2126
+ <>
2127
+ <LibraryCandidateStage
2128
+ activeLibraryId={routeSelectedLibraryId}
2129
+ foldersByLibraryId={foldersByLibraryId}
2130
+ />
1992
2131
  <BrandKitDetailRoute
1993
2132
  libraryId={routeSelectedLibraryId}
1994
2133
  headerMode="actions"
1995
2134
  />
1996
- ) : (
1997
- <AllAssetsBrowser />
1998
- )}
1999
- </div>
2000
- </>
2135
+ </>
2136
+ ) : (
2137
+ <AllAssetsBrowser foldersByLibraryId={foldersByLibraryId} />
2138
+ )}
2139
+ </div>
2001
2140
  ) : (
2002
2141
  <EmptyLibraryStarter onCreateBlank={() => setCreateOpen(true)} />
2003
2142
  )}
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-07-13
4
+ ---
5
+
6
+ Merged the Candidates panel into the Library as a Drafts tab that opens by default
@@ -0,0 +1,40 @@
1
+ import type { ComponentType } from "react";
2
+
3
+ export type AgentPageProps = {
4
+ appName?: string;
5
+ };
6
+
7
+ type AgentClientModule = {
8
+ AgentChatSurface: ComponentType<{
9
+ mode?: "panel" | "page";
10
+ className?: string;
11
+ }>;
12
+ AgentTabsPage?: ComponentType<AgentPageProps>;
13
+ };
14
+
15
+ const legacyAgentPages = new WeakMap<
16
+ AgentClientModule,
17
+ ComponentType<AgentPageProps>
18
+ >();
19
+
20
+ /**
21
+ * Keep the chat scaffold runnable when its template and core package are
22
+ * briefly out of sync during a release. Older core versions do not export
23
+ * AgentTabsPage, but they do expose the page-level chat surface.
24
+ */
25
+ export function resolveAgentPageComponent(
26
+ client: AgentClientModule,
27
+ ): ComponentType<AgentPageProps> {
28
+ if (typeof client.AgentTabsPage === "function") {
29
+ return client.AgentTabsPage;
30
+ }
31
+
32
+ const existing = legacyAgentPages.get(client);
33
+ if (existing) return existing;
34
+
35
+ const legacyAgentPage = function LegacyAgentPage() {
36
+ return <client.AgentChatSurface mode="page" className="h-full" />;
37
+ };
38
+ legacyAgentPages.set(client, legacyAgentPage);
39
+ return legacyAgentPage;
40
+ }
@@ -1,6 +1,7 @@
1
- import { AgentTabsPage, useT } from "@agent-native/core/client";
1
+ import * as AgentClient from "@agent-native/core/client";
2
2
  import { useSetPageTitle } from "@agent-native/toolkit/app-shell";
3
3
 
4
+ import { resolveAgentPageComponent } from "@/lib/agent-page";
4
5
  import { APP_TITLE } from "@/lib/app-config";
5
6
 
6
7
  export function meta() {
@@ -8,8 +9,9 @@ export function meta() {
8
9
  }
9
10
 
10
11
  export default function AgentRoute() {
11
- const t = useT();
12
+ const t = AgentClient.useT();
12
13
  useSetPageTitle(t("settings.agentTitle"));
13
14
 
14
- return <AgentTabsPage appName={APP_TITLE} />;
15
+ const AgentPage = resolveAgentPageComponent(AgentClient);
16
+ return <AgentPage appName={APP_TITLE} />;
15
17
  }
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-07-14
4
+ ---
5
+
6
+ Fixed chat template startup with older core versions
@@ -131,6 +131,11 @@ Transcription takes an audio file and returns text + segments. That's not a prom
131
131
  2. **Cloud fallback — Builder.io managed (Gemini).** When a Builder account is connected (`BUILDER_PRIVATE_KEY` or per-user OAuth, no separate API key needed), `request-transcript` calls `transcribeWithBuilder()`, which routes audio to Builder.io's managed Gemini transcription. Returns text plus timestamped segments. Retry a failed transcript with `force: true`; pass `regenerate: true` to replace an existing ready transcript from the stored recording media. Regeneration keeps the prior ready transcript available if the new provider attempt fails.
132
132
  3. **Cloud fallback — Groq Whisper.** `GROQ_API_KEY` → `https://api.groq.com/openai/v1/audio/transcriptions`, model `whisper-large-v3-turbo`. Fast (~$0.04/hour of audio) Whisper-compatible speech-to-text used when Builder is unavailable.
133
133
 
134
+ The transcript included by `view-screen` is only a bounded preview. When its
135
+ `previewTruncated` field is true, the preview may end mid-sentence and does not
136
+ show where transcription ended. Call `get-recording-player-data` before
137
+ judging completeness or quoting the full transcript.
138
+
134
139
  Clips never routes recording/meeting audio to OpenAI for transcription. (Groq's endpoint is OpenAI-_compatible_ in request shape only — the audio goes to Groq, not OpenAI.)
135
140
 
136
141
  If no native transcript exists and no cloud fallback is available (no Builder connection and no Groq key), the action writes `status="failed"` so the UI can show a friendly prompt.
@@ -43,6 +43,10 @@ Detailed media, meeting, dictation, editing, and sharing rules live in
43
43
  transcript. Pass `--regenerate=true` to replace an existing ready transcript
44
44
  from the stored recording media; if regeneration fails, keep the prior ready
45
45
  transcript available.
46
+ - The transcript embedded by `view-screen` is a bounded preview. If
47
+ `previewTruncated` is true, it may end mid-sentence and does not show where
48
+ transcription ended. Call `get-recording-player-data` before judging
49
+ completeness or quoting the full transcript.
46
50
  - Dictation cleanup, Clip title/cleanup, and meeting summaries should pass
47
51
  bounded `voiceContext` to the shared cleanup/transcription path when active
48
52
  app context, learned vocabulary, user notes, or AGENTS.md preferences are
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Read global, server-controlled feature flags (e.g. desktop capture
3
+ * pipeline toggles) so they can change without a redeploy. The desktop app
4
+ * polls this using the same session cookie/bearer token it already sends to
5
+ * other actions (e.g. `list-meetings`).
6
+ *
7
+ * Usage:
8
+ * pnpm action get-feature-flags
9
+ */
10
+
11
+ import { defineAction } from "@agent-native/core";
12
+ import { getSetting } from "@agent-native/core/settings";
13
+ import { z } from "zod";
14
+
15
+ import {
16
+ FEATURE_FLAGS_KEY,
17
+ withFeatureFlagDefaults,
18
+ } from "../shared/feature-flags.js";
19
+
20
+ export default defineAction({
21
+ description:
22
+ "Get global server-controlled feature flags (e.g. desktop capture pipeline toggles). Returns defaults for any flag never explicitly set.",
23
+ schema: z.object({}),
24
+ http: { method: "GET" },
25
+ readOnly: true,
26
+ run: async () => {
27
+ const stored = await getSetting(FEATURE_FLAGS_KEY);
28
+ return withFeatureFlagDefaults(stored);
29
+ },
30
+ });
@@ -0,0 +1,48 @@
1
+ export const TRANSCRIPT_PREVIEW_CHARS = 2_000;
2
+
3
+ export interface TranscriptPreview {
4
+ recordingId: string;
5
+ language: string | null | undefined;
6
+ status: string | null | undefined;
7
+ fullTextSnippet: string;
8
+ fullTextLength: number;
9
+ previewTruncated: boolean;
10
+ omittedCharacterCount: number;
11
+ segmentCount: number;
12
+ note: string;
13
+ }
14
+
15
+ export function buildTranscriptPreview({
16
+ recordingId,
17
+ language,
18
+ status,
19
+ fullText,
20
+ segments,
21
+ }: {
22
+ recordingId: string;
23
+ language: string | null | undefined;
24
+ status: string | null | undefined;
25
+ fullText: string | null | undefined;
26
+ segments: unknown;
27
+ }): TranscriptPreview {
28
+ const text = fullText ?? "";
29
+ const previewTruncated = text.length > TRANSCRIPT_PREVIEW_CHARS;
30
+ const omittedCharacterCount = Math.max(
31
+ 0,
32
+ text.length - TRANSCRIPT_PREVIEW_CHARS,
33
+ );
34
+
35
+ return {
36
+ recordingId,
37
+ language,
38
+ status,
39
+ fullTextSnippet: text.slice(0, TRANSCRIPT_PREVIEW_CHARS),
40
+ fullTextLength: text.length,
41
+ previewTruncated,
42
+ omittedCharacterCount,
43
+ segmentCount: Array.isArray(segments) ? segments.length : 0,
44
+ note: previewTruncated
45
+ ? `Bounded preview only: showing the first ${TRANSCRIPT_PREVIEW_CHARS.toLocaleString()} of ${text.length.toLocaleString()} characters. It may end mid-sentence; do not infer that the transcript is incomplete. Call get-recording-player-data for the complete transcript and segments.`
46
+ : "The complete transcript fits in this snapshot.",
47
+ };
48
+ }
@@ -33,6 +33,7 @@
33
33
  */
34
34
 
35
35
  import { defineAction } from "@agent-native/core";
36
+ import type { ActionRunContext } from "@agent-native/core/action";
36
37
  import {
37
38
  readAppState,
38
39
  writeAppState,
@@ -1054,10 +1055,49 @@ const requestTranscriptAction = defineAction({
1054
1055
  "Internal — set only by the bounded automatic retry scheduler after a transient failure (ffmpeg timeout, transient provider error). Do not set this when calling request-transcript manually or from the agent; omitting it means the retry budget never applies to this call.",
1055
1056
  ),
1056
1057
  }),
1057
- run: async (args) => {
1058
+ run: async (args, context?: ActionRunContext) => {
1058
1059
  await assertAccess("recording", args.recordingId, "editor");
1059
1060
 
1060
1061
  const db = getDb();
1062
+
1063
+ if (context?.caller === "tool") {
1064
+ const [existingTranscript] = await db
1065
+ .select({
1066
+ status: schema.recordingTranscripts.status,
1067
+ updatedAt: schema.recordingTranscripts.updatedAt,
1068
+ })
1069
+ .from(schema.recordingTranscripts)
1070
+ .where(eq(schema.recordingTranscripts.recordingId, args.recordingId))
1071
+ .limit(1);
1072
+ if (
1073
+ existingTranscript &&
1074
+ isRecentlyPendingTranscript(existingTranscript)
1075
+ ) {
1076
+ console.log(
1077
+ `[clips] Transcript already pending for ${args.recordingId}; skipping duplicate agent request.`,
1078
+ );
1079
+ return {
1080
+ recordingId: args.recordingId,
1081
+ status: "pending" as const,
1082
+ skipped: true,
1083
+ reason: "already-pending",
1084
+ };
1085
+ }
1086
+
1087
+ await dispatchPostFinalizeJob({
1088
+ recordingId: args.recordingId,
1089
+ kind: "transcript",
1090
+ ...(args.regenerate ? { regenerate: true } : {}),
1091
+ });
1092
+ return {
1093
+ recordingId: args.recordingId,
1094
+ status: "pending" as const,
1095
+ queued: true,
1096
+ regenerate: Boolean(args.regenerate),
1097
+ provider: "background" as const,
1098
+ };
1099
+ }
1100
+
1061
1101
  const ownerEmail = getCurrentOwnerEmail();
1062
1102
  const now = new Date().toISOString();
1063
1103
 
@@ -38,6 +38,7 @@ import {
38
38
  parseSpaceIds,
39
39
  } from "../server/lib/recordings.js";
40
40
  import { parseBrowserDiagnosticsRow } from "../shared/browser-diagnostics.js";
41
+ import { buildTranscriptPreview } from "./lib/transcript-preview.js";
41
42
 
42
43
  interface NavigationState {
43
44
  view?: string;
@@ -540,18 +541,13 @@ export default defineAction({
540
541
  // and is injected into <current-screen> on EVERY message, which
541
542
  // can blow the model's context window. The agent calls
542
543
  // get-recording-player-data for the complete transcript/segments.
543
- const segmentCount = Array.isArray(transcript.segments)
544
- ? transcript.segments.length
545
- : 0;
546
- screen.transcript = {
544
+ screen.transcript = buildTranscriptPreview({
547
545
  recordingId: transcript.recordingId,
548
546
  language: transcript.language,
549
547
  status: transcript.status,
550
- fullTextSnippet: (transcript.fullText ?? "").slice(0, 2000),
551
- fullTextLength: (transcript.fullText ?? "").length,
552
- segmentCount,
553
- note: "Snippet only. Call get-recording-player-data for the full transcript and segments.",
554
- };
548
+ fullText: transcript.fullText,
549
+ segments: transcript.segments,
550
+ });
555
551
  }
556
552
  screen.comments = comments.slice(0, 50);
557
553
  if (browserDiagnosticsSummary) {
@@ -524,7 +524,7 @@ export function LibraryLayout({ children }: LibraryLayoutProps) {
524
524
  <>
525
525
  <div className="shrink-0 space-y-1.5 px-2 py-1.5">
526
526
  {shouldShowSidebarLink && (
527
- <CaptureInstallInlineLink className="flex items-center gap-2 rounded px-2 py-1.5 text-xs text-foreground hover:bg-accent/60">
527
+ <CaptureInstallInlineLink className="flex w-full items-center gap-2 rounded px-2 py-1.5 text-xs text-foreground hover:bg-accent/60">
528
528
  <IconAppWindow className="h-4 w-4" />
529
529
  {t("navigation.desktopCta")}
530
530
  </CaptureInstallInlineLink>