@agent-native/core 0.100.1 → 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 (387) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +73 -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/AssistantChat.tsx +4 -0
  37. package/corpus/core/src/client/analytics.ts +8 -1
  38. package/corpus/core/src/client/chat/markdown-renderer.tsx +54 -8
  39. package/corpus/core/src/client/chat/message-components.tsx +8 -2
  40. package/corpus/core/src/client/clipboard.ts +28 -1
  41. package/corpus/core/src/client/composer/PromptComposer.tsx +4 -0
  42. package/corpus/core/src/client/composer/TiptapComposer.tsx +30 -3
  43. package/corpus/core/src/client/guided-questions.tsx +4 -0
  44. package/corpus/core/src/client/i18n.tsx +2 -1
  45. package/corpus/core/src/client/index.ts +4 -0
  46. package/corpus/core/src/client/review/ReviewCommentComposer.tsx +108 -0
  47. package/corpus/core/src/client/review/ReviewThreadPanel.tsx +482 -150
  48. package/corpus/core/src/client/review/index.ts +8 -0
  49. package/corpus/core/src/client/review/use-review.ts +35 -1
  50. package/corpus/core/src/client/use-agent-chat-context.ts +3 -2
  51. package/corpus/core/src/integrations/webhook-handler.ts +4 -2
  52. package/corpus/core/src/review/actions/create-review-comment.ts +2 -1
  53. package/corpus/core/src/review/actions/get-review-feedback.ts +6 -11
  54. package/corpus/core/src/review/actions/list-review-comments.ts +38 -4
  55. package/corpus/core/src/review/actions/reply-review-comment.ts +33 -22
  56. package/corpus/core/src/review/actions/resolve-review-thread.ts +29 -2
  57. package/corpus/core/src/review/actions/send-review-thread-to-agent.ts +62 -0
  58. package/corpus/core/src/review/identity.ts +101 -0
  59. package/corpus/core/src/review/index.ts +14 -0
  60. package/corpus/core/src/review/store.ts +315 -8
  61. package/corpus/core/src/review/types.ts +4 -0
  62. package/corpus/core/src/secrets/crypto.ts +98 -47
  63. package/corpus/core/src/secrets/index.ts +2 -1
  64. package/corpus/core/src/secrets/schema.ts +3 -0
  65. package/corpus/core/src/secrets/storage.ts +164 -31
  66. package/corpus/core/src/server/action-discovery.ts +4 -0
  67. package/corpus/core/src/server/action-routes.ts +125 -4
  68. package/corpus/core/src/server/agent-chat/plugin-options.ts +16 -0
  69. package/corpus/core/src/server/agent-chat-plugin.ts +1 -0
  70. package/corpus/core/src/server/index.ts +8 -0
  71. package/corpus/core/src/vite/action-types-plugin.ts +4 -0
  72. package/corpus/templates/analytics/changelog/2026-07-14-daily-dashboard-email-captures-authenticate-with-a-sessi.md +6 -0
  73. package/corpus/templates/analytics/server/lib/dashboard-report.ts +156 -3
  74. package/corpus/templates/assets/app/components/generation/GenerationResults.tsx +402 -142
  75. package/corpus/templates/assets/app/components/layout/Layout.tsx +4 -0
  76. package/corpus/templates/assets/app/hooks/use-navigation-state.ts +3 -1
  77. package/corpus/templates/assets/app/i18n/zh-TW.ts +1 -0
  78. package/corpus/templates/assets/app/i18n-data.ts +1 -0
  79. package/corpus/templates/assets/app/routes/library.tsx +187 -48
  80. package/corpus/templates/assets/changelog/2026-07-13-assets-keeps-the-right-chat-sidebar-closed-when-the-full-pag.md +6 -0
  81. package/corpus/templates/assets/changelog/2026-07-13-merged-the-candidates-panel-into-the-library-as-a-drafts-tab.md +6 -0
  82. package/corpus/templates/chat/app/lib/agent-page.tsx +40 -0
  83. package/corpus/templates/chat/app/routes/agent.tsx +5 -3
  84. package/corpus/templates/chat/changelog/2026-07-14-fixed-chat-template-startup-with-older-core-versions.md +6 -0
  85. package/corpus/templates/clips/.agents/skills/ai-video-tools/SKILL.md +5 -0
  86. package/corpus/templates/clips/AGENTS.md +4 -0
  87. package/corpus/templates/clips/actions/get-feature-flags.ts +30 -0
  88. package/corpus/templates/clips/actions/lib/transcript-preview.ts +48 -0
  89. package/corpus/templates/clips/actions/request-transcript.ts +41 -1
  90. package/corpus/templates/clips/actions/view-screen.ts +5 -9
  91. package/corpus/templates/clips/app/components/library/library-layout.tsx +1 -1
  92. package/corpus/templates/clips/app/components/player/video-player.tsx +39 -1
  93. package/corpus/templates/clips/app/hooks/use-desktop-promo.ts +6 -12
  94. package/corpus/templates/clips/app/hooks/use-mse-video-source.ts +146 -0
  95. package/corpus/templates/clips/app/lib/capture-install-options.ts +21 -0
  96. package/corpus/templates/clips/app/lib/fmp4.ts +271 -0
  97. package/corpus/templates/clips/app/lib/mse-video-loader.ts +585 -0
  98. package/corpus/templates/clips/app/routes/_app.dictate.tsx +0 -4
  99. package/corpus/templates/clips/app/routes/_app.meetings.$meetingId.tsx +5 -13
  100. package/corpus/templates/clips/app/routes/_app.meetings._index.tsx +2 -37
  101. package/corpus/templates/clips/app/routes/download.tsx +3 -2
  102. package/corpus/templates/clips/changelog/2026-07-10-shared-clips-now-start-playing-instantly-instead-of-showing-.md +6 -0
  103. package/corpus/templates/clips/changelog/2026-07-14-clips-now-distinguishes-transcript-previews-from-incomplete-.md +6 -0
  104. package/corpus/templates/clips/changelog/2026-07-14-desktop-app-prompts-stay-hidden-after-you-download-the-insta.md +6 -0
  105. package/corpus/templates/clips/desktop/src/lib/recorder.ts +5 -0
  106. package/corpus/templates/clips/desktop/src/overlays/recording-pill.tsx +10 -0
  107. package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +4 -0
  108. package/corpus/templates/clips/desktop/src-tauri/src/native_screen/custom_capture.rs +2518 -0
  109. package/corpus/templates/clips/desktop/src-tauri/src/native_screen/live_upload.rs +353 -0
  110. package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +558 -67
  111. package/corpus/templates/clips/desktop/src-tauri/src/recording_indicator.rs +11 -1
  112. package/corpus/templates/clips/desktop/src-tauri/src/remote_flags.rs +188 -0
  113. package/corpus/templates/clips/desktop/src-tauri/src/whisper_speech.rs +1 -1
  114. package/corpus/templates/clips/server/lib/post-finalize-dispatch.ts +1 -0
  115. package/corpus/templates/clips/server/plugins/agent-chat.ts +5 -0
  116. package/corpus/templates/clips/server/routes/api/_agent-native-background/post-finalize-worker.post.ts +5 -1
  117. package/corpus/templates/clips/shared/feature-flags.ts +41 -0
  118. package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +3 -0
  119. package/corpus/templates/design/.agents/skills/design-review-feedback/SKILL.md +42 -0
  120. package/corpus/templates/design/AGENTS.md +6 -0
  121. package/corpus/templates/design/README.md +1 -0
  122. package/corpus/templates/design/actions/navigate.ts +4 -4
  123. package/corpus/templates/design/actions/view-screen.ts +116 -2
  124. package/corpus/templates/design/agent-native.app-skill.json +5 -0
  125. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +52 -59
  126. package/corpus/templates/design/app/components/design/DesignExtensionsPanel.tsx +13 -9
  127. package/corpus/templates/design/app/components/design/EditPanel.tsx +79 -11
  128. package/corpus/templates/design/app/components/design/LayersPanel.tsx +78 -65
  129. package/corpus/templates/design/app/components/design/ReviewCommentsPanel.tsx +161 -0
  130. package/corpus/templates/design/app/components/design/ReviewStatusControl.tsx +96 -0
  131. package/corpus/templates/design/app/components/design/bridge/hit-test.bridge.ts +166 -0
  132. package/corpus/templates/design/app/components/layout/Layout.tsx +1 -0
  133. package/corpus/templates/design/app/components/visual-editor/ReviewCanvasPins.tsx +1077 -0
  134. package/corpus/templates/design/app/components/visual-editor/index.ts +1 -0
  135. package/corpus/templates/design/app/components/visual-editor/review-canvas-state.ts +42 -0
  136. package/corpus/templates/design/app/hooks/use-design-systems.ts +2 -2
  137. package/corpus/templates/design/app/hooks/use-navigation-state.ts +9 -6
  138. package/corpus/templates/design/app/hooks/use-question-flow.ts +7 -1
  139. package/corpus/templates/design/app/i18n/ar-SA.ts +56 -1
  140. package/corpus/templates/design/app/i18n/de-DE.ts +57 -1
  141. package/corpus/templates/design/app/i18n/en-US.ts +56 -1
  142. package/corpus/templates/design/app/i18n/es-ES.ts +56 -1
  143. package/corpus/templates/design/app/i18n/fr-FR.ts +57 -1
  144. package/corpus/templates/design/app/i18n/hi-IN.ts +56 -1
  145. package/corpus/templates/design/app/i18n/ja-JP.ts +56 -1
  146. package/corpus/templates/design/app/i18n/ko-KR.ts +56 -1
  147. package/corpus/templates/design/app/i18n/pt-BR.ts +57 -1
  148. package/corpus/templates/design/app/i18n/zh-CN.ts +56 -1
  149. package/corpus/templates/design/app/i18n/zh-TW.ts +51 -0
  150. package/corpus/templates/design/app/pages/Present.tsx +172 -14
  151. package/corpus/templates/design/app/pages/design-editor/overview-camera.ts +23 -0
  152. package/corpus/templates/design/app/pages/design-editor/tool-state.ts +10 -0
  153. package/corpus/templates/design/app/pages/present-review-state.ts +18 -0
  154. package/corpus/templates/design/app/public-routes.ts +8 -0
  155. package/corpus/templates/design/app/root.tsx +7 -6
  156. package/corpus/templates/design/changelog/2026-07-13-dragged-design-assets-now-appear-at-the-visible-drop-locatio.md +6 -0
  157. package/corpus/templates/design/changelog/2026-07-13-reviewers-can-pin-comments-on-shared-designs-and-apply-verif.md +6 -0
  158. package/corpus/templates/design/server/plugins/agent-chat.ts +10 -0
  159. package/corpus/templates/design/server/plugins/auth.ts +7 -5
  160. package/corpus/templates/design/server/plugins/review.ts +9 -0
  161. package/corpus/templates/design/shared/review-anchor.ts +83 -0
  162. package/corpus/templates/design/shared/review-summary.ts +25 -0
  163. package/corpus/templates/forms/.agents/skills/form-publishing/SKILL.md +2 -0
  164. package/corpus/templates/forms/AGENTS.md +4 -0
  165. package/corpus/templates/forms/actions/create-form.ts +2 -1
  166. package/corpus/templates/forms/actions/update-form.ts +5 -2
  167. package/corpus/templates/forms/app/i18n/ar-SA.ts +3 -0
  168. package/corpus/templates/forms/app/i18n/de-DE.ts +3 -0
  169. package/corpus/templates/forms/app/i18n/en-US.ts +3 -0
  170. package/corpus/templates/forms/app/i18n/es-ES.ts +3 -0
  171. package/corpus/templates/forms/app/i18n/fr-FR.ts +3 -0
  172. package/corpus/templates/forms/app/i18n/hi-IN.ts +3 -0
  173. package/corpus/templates/forms/app/i18n/ja-JP.ts +3 -0
  174. package/corpus/templates/forms/app/i18n/ko-KR.ts +3 -0
  175. package/corpus/templates/forms/app/i18n/pt-BR.ts +3 -0
  176. package/corpus/templates/forms/app/i18n/zh-CN.ts +3 -0
  177. package/corpus/templates/forms/app/i18n/zh-TW.ts +3 -0
  178. package/corpus/templates/forms/app/pages/FormBuilderPage.tsx +19 -0
  179. package/corpus/templates/forms/changelog/2026-07-14-fixed-the-ask-forms-loading-input-appearing-above-the-welcom.md +6 -0
  180. package/corpus/templates/forms/changelog/2026-07-14-form-social-previews-now-show-the-form-title-description-and.md +6 -0
  181. package/corpus/templates/forms/changelog/2026-07-14-forms-can-email-the-form-owner-when-new-responses-arrive.md +6 -0
  182. package/corpus/templates/forms/server/handlers/submissions.ts +17 -0
  183. package/corpus/templates/forms/server/lib/form-og-image.ts +64 -6
  184. package/corpus/templates/forms/server/lib/public-form-ssr.ts +6 -2
  185. package/corpus/templates/forms/server/lib/response-email.ts +65 -0
  186. package/corpus/templates/forms/server/plugins/agent-chat.ts +1 -0
  187. package/corpus/templates/forms/server/routes/api/forms/og/[...slug]/og.png.get.ts +184 -0
  188. package/corpus/templates/forms/shared/types.ts +2 -0
  189. package/corpus/templates/plan/.agents/skills/visual-plan/SKILL.md +6 -4
  190. package/corpus/templates/plan/.agents/skills/visual-recap/SKILL.md +7 -1
  191. package/dist/a2a/index.d.ts +2 -1
  192. package/dist/a2a/index.d.ts.map +1 -1
  193. package/dist/a2a/index.js +1 -1
  194. package/dist/a2a/index.js.map +1 -1
  195. package/dist/a2a/server.d.ts +25 -0
  196. package/dist/a2a/server.d.ts.map +1 -1
  197. package/dist/a2a/server.js +30 -6
  198. package/dist/a2a/server.js.map +1 -1
  199. package/dist/agent/production-agent.d.ts +2 -0
  200. package/dist/agent/production-agent.d.ts.map +1 -1
  201. package/dist/agent/production-agent.js +37 -12
  202. package/dist/agent/production-agent.js.map +1 -1
  203. package/dist/cli/create.d.ts +5 -3
  204. package/dist/cli/create.d.ts.map +1 -1
  205. package/dist/cli/create.js +44 -19
  206. package/dist/cli/create.js.map +1 -1
  207. package/dist/cli/pr-visual-recap-workflow.d.ts +2 -2
  208. package/dist/cli/pr-visual-recap-workflow.d.ts.map +1 -1
  209. package/dist/cli/pr-visual-recap-workflow.js +2 -2
  210. package/dist/cli/pr-visual-recap-workflow.js.map +1 -1
  211. package/dist/cli/recap.d.ts +3 -562
  212. package/dist/cli/recap.d.ts.map +1 -1
  213. package/dist/cli/recap.js +3 -3875
  214. package/dist/cli/recap.js.map +1 -1
  215. package/dist/cli/skills-content/visual-plan-skill.d.ts +1 -1
  216. package/dist/cli/skills-content/visual-plan-skill.d.ts.map +1 -1
  217. package/dist/cli/skills-content/visual-plan-skill.js +6 -4
  218. package/dist/cli/skills-content/visual-plan-skill.js.map +1 -1
  219. package/dist/cli/skills-content/visual-recap-skill.d.ts +1 -1
  220. package/dist/cli/skills-content/visual-recap-skill.d.ts.map +1 -1
  221. package/dist/cli/skills-content/visual-recap-skill.js +7 -1
  222. package/dist/cli/skills-content/visual-recap-skill.js.map +1 -1
  223. package/dist/client/AgentPanel.d.ts.map +1 -1
  224. package/dist/client/AgentPanel.js +3 -3
  225. package/dist/client/AgentPanel.js.map +1 -1
  226. package/dist/client/AssistantChat.d.ts +2 -0
  227. package/dist/client/AssistantChat.d.ts.map +1 -1
  228. package/dist/client/AssistantChat.js +2 -2
  229. package/dist/client/AssistantChat.js.map +1 -1
  230. package/dist/client/analytics.d.ts +5 -0
  231. package/dist/client/analytics.d.ts.map +1 -1
  232. package/dist/client/analytics.js +3 -1
  233. package/dist/client/analytics.js.map +1 -1
  234. package/dist/client/chat/markdown-renderer.d.ts +1 -0
  235. package/dist/client/chat/markdown-renderer.d.ts.map +1 -1
  236. package/dist/client/chat/markdown-renderer.js +36 -1
  237. package/dist/client/chat/markdown-renderer.js.map +1 -1
  238. package/dist/client/chat/message-components.d.ts.map +1 -1
  239. package/dist/client/chat/message-components.js +5 -2
  240. package/dist/client/chat/message-components.js.map +1 -1
  241. package/dist/client/clipboard.d.ts +3 -1
  242. package/dist/client/clipboard.d.ts.map +1 -1
  243. package/dist/client/clipboard.js +24 -1
  244. package/dist/client/clipboard.js.map +1 -1
  245. package/dist/client/composer/PromptComposer.d.ts +2 -0
  246. package/dist/client/composer/PromptComposer.d.ts.map +1 -1
  247. package/dist/client/composer/PromptComposer.js +2 -2
  248. package/dist/client/composer/PromptComposer.js.map +1 -1
  249. package/dist/client/composer/TiptapComposer.d.ts +3 -1
  250. package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
  251. package/dist/client/composer/TiptapComposer.js +20 -5
  252. package/dist/client/composer/TiptapComposer.js.map +1 -1
  253. package/dist/client/guided-questions.d.ts +3 -1
  254. package/dist/client/guided-questions.d.ts.map +1 -1
  255. package/dist/client/guided-questions.js +2 -1
  256. package/dist/client/guided-questions.js.map +1 -1
  257. package/dist/client/i18n.d.ts.map +1 -1
  258. package/dist/client/i18n.js +3 -1
  259. package/dist/client/i18n.js.map +1 -1
  260. package/dist/client/index.d.ts +1 -1
  261. package/dist/client/index.d.ts.map +1 -1
  262. package/dist/client/index.js +1 -1
  263. package/dist/client/index.js.map +1 -1
  264. package/dist/client/review/ReviewCommentComposer.d.ts +18 -0
  265. package/dist/client/review/ReviewCommentComposer.d.ts.map +1 -0
  266. package/dist/client/review/ReviewCommentComposer.js +30 -0
  267. package/dist/client/review/ReviewCommentComposer.js.map +1 -0
  268. package/dist/client/review/ReviewThreadPanel.d.ts +28 -1
  269. package/dist/client/review/ReviewThreadPanel.d.ts.map +1 -1
  270. package/dist/client/review/ReviewThreadPanel.js +151 -39
  271. package/dist/client/review/ReviewThreadPanel.js.map +1 -1
  272. package/dist/client/review/index.d.ts +3 -2
  273. package/dist/client/review/index.d.ts.map +1 -1
  274. package/dist/client/review/index.js +2 -1
  275. package/dist/client/review/index.js.map +1 -1
  276. package/dist/client/review/use-review.d.ts +23 -0
  277. package/dist/client/review/use-review.d.ts.map +1 -1
  278. package/dist/client/review/use-review.js +3 -0
  279. package/dist/client/review/use-review.js.map +1 -1
  280. package/dist/client/use-agent-chat-context.d.ts +1 -1
  281. package/dist/client/use-agent-chat-context.d.ts.map +1 -1
  282. package/dist/client/use-agent-chat-context.js +4 -2
  283. package/dist/client/use-agent-chat-context.js.map +1 -1
  284. package/dist/collab/awareness.d.ts +2 -2
  285. package/dist/collab/awareness.d.ts.map +1 -1
  286. package/dist/collab/struct-routes.d.ts +1 -1
  287. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  288. package/dist/integrations/webhook-handler.d.ts.map +1 -1
  289. package/dist/integrations/webhook-handler.js +3 -2
  290. package/dist/integrations/webhook-handler.js.map +1 -1
  291. package/dist/notifications/routes.d.ts +3 -3
  292. package/dist/observability/routes.d.ts +5 -5
  293. package/dist/progress/routes.d.ts +1 -1
  294. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  295. package/dist/resources/handlers.d.ts +2 -2
  296. package/dist/review/actions/create-review-comment.js +2 -1
  297. package/dist/review/actions/create-review-comment.js.map +1 -1
  298. package/dist/review/actions/get-review-feedback.js +6 -11
  299. package/dist/review/actions/get-review-feedback.js.map +1 -1
  300. package/dist/review/actions/list-review-comments.d.ts +1 -0
  301. package/dist/review/actions/list-review-comments.js +25 -4
  302. package/dist/review/actions/list-review-comments.js.map +1 -1
  303. package/dist/review/actions/reply-review-comment.js +12 -5
  304. package/dist/review/actions/reply-review-comment.js.map +1 -1
  305. package/dist/review/actions/resolve-review-thread.d.ts +3 -0
  306. package/dist/review/actions/resolve-review-thread.js +20 -3
  307. package/dist/review/actions/resolve-review-thread.js.map +1 -1
  308. package/dist/review/actions/send-review-thread-to-agent.d.ts +17 -0
  309. package/dist/review/actions/send-review-thread-to-agent.d.ts.map +1 -0
  310. package/dist/review/actions/send-review-thread-to-agent.js +49 -0
  311. package/dist/review/actions/send-review-thread-to-agent.js.map +1 -0
  312. package/dist/review/identity.d.ts +6 -0
  313. package/dist/review/identity.d.ts.map +1 -0
  314. package/dist/review/identity.js +68 -0
  315. package/dist/review/identity.js.map +1 -0
  316. package/dist/review/index.d.ts +3 -1
  317. package/dist/review/index.d.ts.map +1 -1
  318. package/dist/review/index.js +2 -1
  319. package/dist/review/index.js.map +1 -1
  320. package/dist/review/store.d.ts +36 -0
  321. package/dist/review/store.d.ts.map +1 -1
  322. package/dist/review/store.js +223 -8
  323. package/dist/review/store.js.map +1 -1
  324. package/dist/review/types.d.ts +4 -0
  325. package/dist/review/types.d.ts.map +1 -1
  326. package/dist/review/types.js.map +1 -1
  327. package/dist/secrets/crypto.d.ts +35 -13
  328. package/dist/secrets/crypto.d.ts.map +1 -1
  329. package/dist/secrets/crypto.js +78 -41
  330. package/dist/secrets/crypto.js.map +1 -1
  331. package/dist/secrets/index.d.ts.map +1 -1
  332. package/dist/secrets/index.js +2 -1
  333. package/dist/secrets/index.js.map +1 -1
  334. package/dist/secrets/routes.d.ts +9 -9
  335. package/dist/secrets/schema.d.ts +20 -1
  336. package/dist/secrets/schema.d.ts.map +1 -1
  337. package/dist/secrets/schema.js +3 -0
  338. package/dist/secrets/schema.js.map +1 -1
  339. package/dist/secrets/storage.d.ts +7 -7
  340. package/dist/secrets/storage.d.ts.map +1 -1
  341. package/dist/secrets/storage.js +121 -30
  342. package/dist/secrets/storage.js.map +1 -1
  343. package/dist/server/action-discovery.d.ts.map +1 -1
  344. package/dist/server/action-discovery.js +4 -0
  345. package/dist/server/action-discovery.js.map +1 -1
  346. package/dist/server/action-routes.d.ts +45 -0
  347. package/dist/server/action-routes.d.ts.map +1 -1
  348. package/dist/server/action-routes.js +71 -5
  349. package/dist/server/action-routes.js.map +1 -1
  350. package/dist/server/agent-chat/plugin-options.d.ts +16 -0
  351. package/dist/server/agent-chat/plugin-options.d.ts.map +1 -1
  352. package/dist/server/agent-chat/plugin-options.js.map +1 -1
  353. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  354. package/dist/server/agent-chat-plugin.js +1 -0
  355. package/dist/server/agent-chat-plugin.js.map +1 -1
  356. package/dist/server/index.d.ts +3 -1
  357. package/dist/server/index.d.ts.map +1 -1
  358. package/dist/server/index.js +2 -0
  359. package/dist/server/index.js.map +1 -1
  360. package/dist/vite/action-types-plugin.d.ts.map +1 -1
  361. package/dist/vite/action-types-plugin.js +4 -0
  362. package/dist/vite/action-types-plugin.js.map +1 -1
  363. package/docs/content/locales/ar-SA/pr-visual-recap.mdx +48 -30
  364. package/docs/content/locales/ar-SA/template-plan.mdx +7 -0
  365. package/docs/content/locales/de-DE/pr-visual-recap.mdx +48 -30
  366. package/docs/content/locales/de-DE/template-plan.mdx +7 -0
  367. package/docs/content/locales/es-ES/pr-visual-recap.mdx +48 -30
  368. package/docs/content/locales/es-ES/template-plan.mdx +14 -0
  369. package/docs/content/locales/fr-FR/pr-visual-recap.mdx +48 -30
  370. package/docs/content/locales/fr-FR/template-plan.mdx +7 -0
  371. package/docs/content/locales/hi-IN/pr-visual-recap.mdx +48 -30
  372. package/docs/content/locales/hi-IN/template-plan.mdx +7 -0
  373. package/docs/content/locales/ja-JP/pr-visual-recap.mdx +48 -30
  374. package/docs/content/locales/ja-JP/template-plan.mdx +7 -0
  375. package/docs/content/locales/ko-KR/pr-visual-recap.mdx +48 -30
  376. package/docs/content/locales/ko-KR/template-plan.mdx +7 -0
  377. package/docs/content/locales/pt-BR/pr-visual-recap.mdx +48 -30
  378. package/docs/content/locales/pt-BR/template-plan.mdx +14 -0
  379. package/docs/content/locales/zh-CN/pr-visual-recap.mdx +48 -30
  380. package/docs/content/locales/zh-CN/template-plan.mdx +7 -0
  381. package/docs/content/locales/zh-TW/pr-visual-recap.mdx +48 -30
  382. package/docs/content/locales/zh-TW/template-plan.mdx +7 -0
  383. package/docs/content/pr-visual-recap.mdx +50 -32
  384. package/docs/content/template-plan.mdx +14 -0
  385. package/docs/content/toolkit-comments-review.mdx +16 -2
  386. package/package.json +4 -1
  387. package/corpus/templates/forms/server/routes/api/forms/og/[slug]/og.png.get.ts +0 -45
@@ -1,13 +1,13 @@
1
1
  /**
2
2
  * Storage layer for the framework secrets registry.
3
3
  *
4
- * Values are encrypted at rest with AES-256-GCM. The encryption key is
5
- * derived from `SECRETS_ENCRYPTION_KEY` (preferred) or the existing
6
- * `BETTER_AUTH_SECRET` env var (fallback so templates don't need a second
7
- * secret during development). If neither is set in production we fall back
8
- * to a machine-local key derived from the cwd the secret is still only
9
- * readable on this machine, but consider setting `SECRETS_ENCRYPTION_KEY`
10
- * for a stable, rotatable key.
4
+ * Values are encrypted at rest with AES-256-GCM. The workspace-shared
5
+ * encryption key is derived from `SECRETS_ENCRYPTION_KEY` (preferred) or the
6
+ * existing `BETTER_AUTH_SECRET` env var (fallback so templates don't need a
7
+ * second secret during development). Deployments that only have the legacy
8
+ * app-scoped key continue to work until shared key material is configured;
9
+ * once configured, new rows use the shared key and reads retain a legacy-key
10
+ * fallback for existing rows.
11
11
  *
12
12
  * Secret values are NEVER logged and NEVER returned from any route handler.
13
13
  */
@@ -17,8 +17,11 @@ import { randomUUID } from "node:crypto";
17
17
  import { getDbExec, isPostgres } from "../db/client.js";
18
18
  import { ensureColumnExists, ensureTableExists } from "../db/ddl-guard.js";
19
19
  import {
20
- encryptSecretValue as encryptValue,
21
- decryptSecretValue as decryptValue,
20
+ encryptSecretValue as encryptLegacyValue,
21
+ encryptSharedSecretValue as encryptValue,
22
+ decryptSharedSecretValue as decryptValue,
23
+ decryptSecretValue as decryptLegacyValue,
24
+ hasSharedSecretEncryptionKeyMaterial,
22
25
  } from "./crypto.js";
23
26
  import type { SecretScope } from "./register.js";
24
27
  import { APP_SECRETS_CREATE_SQL } from "./schema.js";
@@ -61,6 +64,11 @@ async function ensureTable(): Promise<void> {
61
64
  "url_allowlist",
62
65
  `ALTER TABLE app_secrets ADD COLUMN IF NOT EXISTS url_allowlist TEXT`,
63
66
  );
67
+ await ensureColumnExists(
68
+ "app_secrets",
69
+ "shared_encrypted_value",
70
+ `ALTER TABLE app_secrets ADD COLUMN IF NOT EXISTS shared_encrypted_value TEXT`,
71
+ );
64
72
  return;
65
73
  }
66
74
 
@@ -86,6 +94,16 @@ async function ensureTable(): Promise<void> {
86
94
  } catch {
87
95
  // Column already exists — expected
88
96
  }
97
+
98
+ // Additive migration: workspace-shared ciphertext. Keep the legacy
99
+ // encrypted_value column so older app versions remain readable.
100
+ try {
101
+ await client.execute(
102
+ `ALTER TABLE app_secrets ADD COLUMN shared_encrypted_value TEXT`,
103
+ );
104
+ } catch {
105
+ // Column already exists — expected
106
+ }
89
107
  })().catch((err) => {
90
108
  _initPromise = undefined;
91
109
  throw err;
@@ -95,7 +113,9 @@ async function ensureTable(): Promise<void> {
95
113
  }
96
114
 
97
115
  // ---------------------------------------------------------------------------
98
- // Encryption — see ./crypto.ts (shared with per-user credentials)
116
+ // Encryption — see ./crypto.ts. Keep encrypted_value on the legacy app-key
117
+ // format for mixed-version deployments, and add shared_encrypted_value when a
118
+ // stable workspace key is configured so sibling apps can read the same row.
99
119
  // ---------------------------------------------------------------------------
100
120
 
101
121
  /**
@@ -141,7 +161,14 @@ export async function writeAppSecret(args: WriteSecretArgs): Promise<string> {
141
161
  }
142
162
  const client = getDbExec();
143
163
  const now = Date.now();
144
- const encrypted = encryptValue(value);
164
+ // Dual-write during rollout: old readers continue using encrypted_value,
165
+ // while new readers prefer the nullable shared ciphertext. An app-only
166
+ // deployment leaves the shared column null; on an update, an existing
167
+ // shared ciphertext is preserved by the upsert below.
168
+ const encrypted = encryptLegacyValue(value);
169
+ const sharedEncrypted = hasSharedSecretEncryptionKeyMaterial()
170
+ ? encryptValue(value)
171
+ : null;
145
172
  const id = randomUUID();
146
173
 
147
174
  // Atomic upsert by (scope, scope_id, key). Previously this was a
@@ -155,10 +182,11 @@ export async function writeAppSecret(args: WriteSecretArgs): Promise<string> {
155
182
  // keeps its original id (any stored references stay stable); only a
156
183
  // genuinely new row gets the freshly generated `id`. This syntax is
157
184
  // portable across SQLite (UPSERT since 3.24) and Postgres.
158
- const upsertSql = `INSERT INTO app_secrets (id, scope, scope_id, key, encrypted_value, description, url_allowlist, created_at, updated_at)
159
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
185
+ const upsertSql = `INSERT INTO app_secrets (id, scope, scope_id, key, encrypted_value, shared_encrypted_value, description, url_allowlist, created_at, updated_at)
186
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
160
187
  ON CONFLICT (scope, scope_id, key) DO UPDATE SET
161
188
  encrypted_value = excluded.encrypted_value,
189
+ shared_encrypted_value = COALESCE(excluded.shared_encrypted_value, app_secrets.shared_encrypted_value),
162
190
  description = excluded.description,
163
191
  url_allowlist = excluded.url_allowlist,
164
192
  updated_at = excluded.updated_at`;
@@ -168,6 +196,7 @@ export async function writeAppSecret(args: WriteSecretArgs): Promise<string> {
168
196
  scopeId,
169
197
  key,
170
198
  encrypted,
199
+ sharedEncrypted,
171
200
  description ?? null,
172
201
  urlAllowlist ?? null,
173
202
  now,
@@ -201,6 +230,80 @@ export interface ReadSecretResult {
201
230
  updatedAt: number;
202
231
  }
203
232
 
233
+ /**
234
+ * Read the shared-key format and retain compatibility with rows written before
235
+ * app_secrets moved to its workspace-shared encryption boundary. The legacy
236
+ * fallback is only useful when the current app owns the old row; sibling apps
237
+ * will receive shared-key ciphertext after the next vault sync or update.
238
+ */
239
+ interface DecryptedAppSecretValue {
240
+ value: string;
241
+ /** True when the app-scoped fallback decrypted encrypted_value. */
242
+ usedLegacyKey: boolean;
243
+ /** True when shared_encrypted_value was not the source of the plaintext. */
244
+ needsSharedCiphertext: boolean;
245
+ }
246
+
247
+ function decryptAppSecretValue(
248
+ encrypted: string,
249
+ sharedEncrypted?: string | null,
250
+ ): DecryptedAppSecretValue {
251
+ if (sharedEncrypted) {
252
+ try {
253
+ return {
254
+ value: decryptValue(sharedEncrypted),
255
+ usedLegacyKey: false,
256
+ needsSharedCiphertext: false,
257
+ };
258
+ } catch {
259
+ // Fall through to the legacy column. A partially migrated row may have
260
+ // a stale shared ciphertext while the old app-key value is valid.
261
+ }
262
+ }
263
+ try {
264
+ return {
265
+ value: decryptValue(encrypted),
266
+ usedLegacyKey: false,
267
+ needsSharedCiphertext: true,
268
+ };
269
+ } catch {
270
+ return {
271
+ value: decryptLegacyValue(encrypted),
272
+ usedLegacyKey: true,
273
+ needsSharedCiphertext: true,
274
+ };
275
+ }
276
+ }
277
+
278
+ /**
279
+ * Populate the shared column without touching encrypted_value. This is
280
+ * intentionally best-effort: a read must still succeed if a deployment's DB
281
+ * role cannot update the row. The NULL predicate prevents a concurrent writer
282
+ * from overwriting newly-populated shared ciphertext, and leaving updated_at
283
+ * untouched preserves the row's user-visible ordering/metadata.
284
+ */
285
+ async function populateSharedAppSecret(
286
+ id: unknown,
287
+ value: string,
288
+ ): Promise<void> {
289
+ if (
290
+ id === undefined ||
291
+ id === null ||
292
+ !hasSharedSecretEncryptionKeyMaterial()
293
+ ) {
294
+ return;
295
+ }
296
+ try {
297
+ await getDbExec().execute({
298
+ sql: `UPDATE app_secrets SET shared_encrypted_value = ? WHERE id = ? AND shared_encrypted_value IS NULL`,
299
+ args: [encryptValue(value), id],
300
+ });
301
+ } catch {
302
+ // Migration is opportunistic. Preserve the successful read if the update
303
+ // is unavailable due to a read-only role, transient DB failure, or race.
304
+ }
305
+ }
306
+
204
307
  type AppSecretsReadQuery = { sql: string; args: unknown[] };
205
308
 
206
309
  /**
@@ -244,15 +347,22 @@ export async function readAppSecret(
244
347
  ): Promise<ReadSecretResult | null> {
245
348
  const { key, scope, scopeId } = ref;
246
349
  const { rows } = await executeAppSecretsRead({
247
- sql: `SELECT encrypted_value, updated_at FROM app_secrets WHERE scope = ? AND scope_id = ? AND key = ? LIMIT 1`,
350
+ sql: `SELECT encrypted_value, shared_encrypted_value, updated_at, id FROM app_secrets WHERE scope = ? AND scope_id = ? AND key = ? LIMIT 1`,
248
351
  args: [scope, scopeId, key],
249
352
  });
250
353
  if (rows.length === 0) return null;
251
354
  try {
252
- const value = decryptValue(rows[0].encrypted_value as string);
355
+ const encrypted = rows[0].encrypted_value as string;
356
+ const decrypted = decryptAppSecretValue(
357
+ encrypted,
358
+ rows[0].shared_encrypted_value as string | null,
359
+ );
360
+ if (decrypted.needsSharedCiphertext) {
361
+ await populateSharedAppSecret(rows[0].id, decrypted.value);
362
+ }
253
363
  return {
254
- value,
255
- last4: last4(value),
364
+ value: decrypted.value,
365
+ last4: last4(decrypted.value),
256
366
  updatedAt: Number(rows[0].updated_at ?? 0),
257
367
  };
258
368
  } catch {
@@ -273,7 +383,7 @@ export async function readAppSecrets(args: {
273
383
 
274
384
  const placeholders = keys.map(() => "?").join(", ");
275
385
  const { rows } = await executeAppSecretsRead({
276
- sql: `SELECT key, encrypted_value, updated_at FROM app_secrets WHERE scope = ? AND scope_id = ? AND key IN (${placeholders})`,
386
+ sql: `SELECT key, encrypted_value, shared_encrypted_value, updated_at, id FROM app_secrets WHERE scope = ? AND scope_id = ? AND key IN (${placeholders})`,
277
387
  args: [args.scope, args.scopeId, ...keys],
278
388
  });
279
389
  const results = new Map<string, ReadSecretResult>();
@@ -281,10 +391,17 @@ export async function readAppSecrets(args: {
281
391
  const key = String(row.key ?? "");
282
392
  if (!key) continue;
283
393
  try {
284
- const value = decryptValue(row.encrypted_value as string);
394
+ const encrypted = row.encrypted_value as string;
395
+ const decrypted = decryptAppSecretValue(
396
+ encrypted,
397
+ row.shared_encrypted_value as string | null,
398
+ );
399
+ if (decrypted.needsSharedCiphertext) {
400
+ await populateSharedAppSecret(row.id, decrypted.value);
401
+ }
285
402
  results.set(key, {
286
- value,
287
- last4: last4(value),
403
+ value: decrypted.value,
404
+ last4: last4(decrypted.value),
288
405
  updatedAt: Number(row.updated_at ?? 0),
289
406
  });
290
407
  } catch {
@@ -330,15 +447,22 @@ export async function readAppSecretMeta(
330
447
  const { key, scope, scopeId } = ref;
331
448
  const client = getDbExec();
332
449
  const { rows } = await client.execute({
333
- sql: `SELECT encrypted_value, description, url_allowlist, created_at, updated_at FROM app_secrets WHERE scope = ? AND scope_id = ? AND key = ? LIMIT 1`,
450
+ sql: `SELECT id, encrypted_value, shared_encrypted_value, description, url_allowlist, created_at, updated_at FROM app_secrets WHERE scope = ? AND scope_id = ? AND key = ? LIMIT 1`,
334
451
  args: [scope, scopeId, key],
335
452
  });
336
453
  if (rows.length === 0) return null;
337
454
  const row = rows[0];
338
455
  let last4Value = "";
339
456
  try {
340
- const value = decryptValue(row.encrypted_value as string);
341
- last4Value = last4(value);
457
+ const encrypted = row.encrypted_value as string;
458
+ const decrypted = decryptAppSecretValue(
459
+ encrypted,
460
+ row.shared_encrypted_value as string | null,
461
+ );
462
+ if (decrypted.needsSharedCiphertext) {
463
+ await populateSharedAppSecret(row.id, decrypted.value);
464
+ }
465
+ last4Value = last4(decrypted.value);
342
466
  } catch {
343
467
  last4Value = "";
344
468
  }
@@ -366,18 +490,26 @@ export async function listAppSecretsForScope(
366
490
  await ensureTable();
367
491
  const client = getDbExec();
368
492
  const { rows } = await client.execute({
369
- sql: `SELECT key, encrypted_value, description, url_allowlist, created_at, updated_at FROM app_secrets WHERE scope = ? AND scope_id = ? ORDER BY updated_at DESC`,
493
+ sql: `SELECT id, key, encrypted_value, shared_encrypted_value, description, url_allowlist, created_at, updated_at FROM app_secrets WHERE scope = ? AND scope_id = ? ORDER BY updated_at DESC`,
370
494
  args: [scope, scopeId],
371
495
  });
372
- return rows.map((row) => {
496
+ const results: SecretMeta[] = [];
497
+ for (const row of rows) {
373
498
  let last4Value = "";
374
499
  try {
375
- const value = decryptValue(row.encrypted_value as string);
376
- last4Value = last4(value);
500
+ const encrypted = row.encrypted_value as string;
501
+ const decrypted = decryptAppSecretValue(
502
+ encrypted,
503
+ row.shared_encrypted_value as string | null,
504
+ );
505
+ if (decrypted.needsSharedCiphertext) {
506
+ await populateSharedAppSecret(row.id, decrypted.value);
507
+ }
508
+ last4Value = last4(decrypted.value);
377
509
  } catch {
378
510
  last4Value = "";
379
511
  }
380
- return {
512
+ results.push({
381
513
  key: row.key as string,
382
514
  scope,
383
515
  scopeId,
@@ -386,8 +518,9 @@ export async function listAppSecretsForScope(
386
518
  urlAllowlist: parseAllowlist(row.url_allowlist as string | null),
387
519
  createdAt: Number(row.created_at ?? 0),
388
520
  updatedAt: Number(row.updated_at ?? 0),
389
- };
390
- });
521
+ });
522
+ }
523
+ return results;
391
524
  }
392
525
 
393
526
  function parseAllowlist(raw: string | null): string[] | null {
@@ -686,6 +686,10 @@ export async function mergeCoreSharingActions(
686
686
  "set-review-status",
687
687
  () => import("../review/actions/set-review-status.js"),
688
688
  ],
689
+ [
690
+ "send-review-thread-to-agent",
691
+ () => import("../review/actions/send-review-thread-to-agent.js"),
692
+ ],
689
693
  // Org service tokens (CI credentials, e.g. PLAN_RECAP_TOKEN). Mint/revoke
690
694
  // are toolCallable:false — preserved via preserveActionFlags below.
691
695
  [
@@ -1,4 +1,5 @@
1
1
  import {
2
+ createError,
2
3
  defineEventHandler,
3
4
  setResponseStatus,
4
5
  setResponseHeader,
@@ -10,6 +11,7 @@ import {
10
11
 
11
12
  import { isAgentActionStopError } from "../action.js";
12
13
  import type { ActionEntry } from "../agent/production-agent.js";
14
+ import { resolveOrgIdForEmail } from "../org/context.js";
13
15
  import { readBody } from "../server/h3-helpers.js";
14
16
  import { EMBED_TARGET_HEADER } from "../shared/embed-auth.js";
15
17
  import {
@@ -18,6 +20,10 @@ import {
18
20
  shouldAllowMcpEmbedCredentials,
19
21
  } from "../shared/mcp-embed-headers.js";
20
22
  import { notifyActionChange } from "./action-change.js";
23
+ import {
24
+ seedAgentRunOwnerContext,
25
+ type AgentRunOwnerContext,
26
+ } from "./agent-run-context.js";
21
27
  import {
22
28
  getAllowedCorsOrigin as resolveAllowedCorsOrigin,
23
29
  readCorsAllowedOrigins,
@@ -164,6 +170,51 @@ function handleOptionsRequest(event: any): string {
164
170
  return "";
165
171
  }
166
172
 
173
+ /**
174
+ * Declarative auth adapter for the HTTP action route. Its `resolveCaller` runs
175
+ * BEFORE the framework's `getOwnerFromEvent` / `getSession` chain, letting an
176
+ * app accept caller identities `getSession` doesn't understand (e.g. an A2A
177
+ * JWT) without reaching into request context from a Nitro `request` hook.
178
+ *
179
+ * Scoped to `/_agent-native/actions/*` only — it does not affect other routes.
180
+ */
181
+ export type ActionRouteResolvedCaller = AgentRunOwnerContext & {
182
+ /**
183
+ * Org to scope the request to, verified from the same credential as the
184
+ * caller identity (e.g. the A2A token's org claim). When omitted, the org
185
+ * is derived from the verified owner email via the framework's owner→org
186
+ * membership lookup. The ambient session/org state on the request is never
187
+ * consulted for adapter-resolved callers: a request can carry both a valid
188
+ * A2A bearer and an unrelated browser cookie, and the cookie user's org
189
+ * must not leak into the token caller's request context.
190
+ */
191
+ orgId?: string;
192
+ };
193
+
194
+ export interface ActionRouteAuthAdapter {
195
+ /**
196
+ * Resolve a caller from the raw event before the cookie/bearer chain.
197
+ *
198
+ * - Return the resolved caller to run the action scoped to that identity.
199
+ * Org scoping comes exclusively from the caller: the returned `orgId` if
200
+ * set, otherwise the owner-email membership lookup — never from the
201
+ * request's session cookie or org context.
202
+ * - Return `null` when the credential isn't yours to judge — the request
203
+ * defers to `getOwnerFromEvent` / `getSession`.
204
+ * - THROW to hard-reject: the credential is present but invalid (e.g. an
205
+ * expired or forged A2A bearer). The action route responds 401 and does
206
+ * NOT fall through to the cookie/session chain, so a valid same-origin
207
+ * session cookie can't be used to execute the request as the logged-in
208
+ * user. Do not throw merely to signal "not mine" — return `null` for that.
209
+ */
210
+ resolveCaller?: (
211
+ event: any,
212
+ ) =>
213
+ | ActionRouteResolvedCaller
214
+ | null
215
+ | Promise<ActionRouteResolvedCaller | null>;
216
+ }
217
+
167
218
  export interface MountActionRoutesOptions {
168
219
  /** Resolve owner email from the H3 event (for data scoping). */
169
220
  getOwnerFromEvent?: (event: any) => string | Promise<string>;
@@ -173,6 +224,18 @@ export interface MountActionRoutesOptions {
173
224
  ) => string | undefined | Promise<string | undefined>;
174
225
  /** Resolve org ID from the H3 event (for org scoping). */
175
226
  resolveOrgId?: (event: any) => string | null | Promise<string | null>;
227
+ /**
228
+ * Optional caller resolver that runs before the `getOwnerFromEvent` /
229
+ * `getSession` chain. Lets apps accept A2A JWTs (or other bearer schemes) on
230
+ * the action route declaratively. See {@link ActionRouteAuthAdapter}.
231
+ */
232
+ actionRouteAuth?: ActionRouteAuthAdapter;
233
+ }
234
+
235
+ function normalizeOrgId(value: string | null | undefined): string | undefined {
236
+ return typeof value === "string" && value.trim().length > 0
237
+ ? value.trim()
238
+ : undefined;
176
239
  }
177
240
 
178
241
  function isAuthResolutionFailure(error: unknown): boolean {
@@ -259,7 +322,42 @@ export function mountActionRoutes(
259
322
  // Resolve auth context for per-request scoping
260
323
  let userEmail: string | undefined;
261
324
  let userName: string | undefined;
262
- if (options?.getOwnerFromEvent) {
325
+ // An app-supplied auth adapter runs first: it can accept caller
326
+ // identities the framework's getSession chain doesn't understand (e.g.
327
+ // an A2A JWT). A resolved caller is seeded onto the event context so any
328
+ // downstream resolveAgentRunOwnerContext (nested agent runs) sees the
329
+ // same identity. The adapter is only consulted for the action route, so
330
+ // it can't affect other surfaces.
331
+ //
332
+ // Contract: `resolveCaller` returning `null` means "this credential
333
+ // isn't mine — defer to the cookie/session chain below". THROWING means
334
+ // "the credential is mine but invalid" (e.g. an expired/forged A2A
335
+ // bearer) and is a hard rejection: we surface a 401 instead of falling
336
+ // through, so a live same-origin session cookie can't silently execute
337
+ // the request as the logged-in user.
338
+ let resolvedCaller: ActionRouteResolvedCaller | null = null;
339
+ if (options?.actionRouteAuth?.resolveCaller) {
340
+ let caller: ActionRouteResolvedCaller | null;
341
+ try {
342
+ caller = await options.actionRouteAuth.resolveCaller(event);
343
+ } catch {
344
+ throw createError({
345
+ statusCode: 401,
346
+ statusMessage: "Unauthorized",
347
+ });
348
+ }
349
+ if (caller) {
350
+ seedAgentRunOwnerContext(event, {
351
+ owner: caller.owner,
352
+ anonymous: caller.anonymous,
353
+ name: caller.name,
354
+ });
355
+ userEmail = caller.owner;
356
+ userName = caller.name;
357
+ resolvedCaller = caller;
358
+ }
359
+ }
360
+ if (!resolvedCaller && options?.getOwnerFromEvent) {
263
361
  try {
264
362
  userEmail = await options.getOwnerFromEvent(event);
265
363
  userName = options?.getUserNameFromEvent
@@ -277,9 +375,32 @@ export function mountActionRoutes(
277
375
  }
278
376
  }
279
377
  }
280
- const orgId = options?.resolveOrgId
281
- ? ((await options.resolveOrgId(event)) ?? undefined)
282
- : undefined;
378
+ // Org scoping. For adapter-resolved callers the org must come
379
+ // exclusively from the verified credential: the adapter-asserted
380
+ // orgId when present, otherwise the owner-email membership lookup.
381
+ // The request's ambient session/org state (`resolveOrgId`, usually
382
+ // getSession-backed) is deliberately NOT consulted — a request can
383
+ // carry both a valid A2A bearer and an unrelated same-origin browser
384
+ // cookie, and the cookie user's org must not become the org the
385
+ // token caller's actions execute under. Non-adapter callers keep the
386
+ // original resolveOrgId-only behavior.
387
+ let orgId: string | undefined;
388
+ if (resolvedCaller) {
389
+ orgId = normalizeOrgId(resolvedCaller.orgId);
390
+ if (!orgId && resolvedCaller.owner && !resolvedCaller.anonymous) {
391
+ try {
392
+ orgId = normalizeOrgId(
393
+ await resolveOrgIdForEmail(resolvedCaller.owner),
394
+ );
395
+ } catch {
396
+ // Org tables may not exist yet on first boot.
397
+ }
398
+ }
399
+ } else {
400
+ orgId = options?.resolveOrgId
401
+ ? ((await options.resolveOrgId(event)) ?? undefined)
402
+ : undefined;
403
+ }
283
404
  const timezone = readTimezoneHeader(event);
284
405
 
285
406
  return runWithRequestContext(
@@ -109,6 +109,22 @@ export interface AgentChatPluginOptions {
109
109
  * agent mutations.
110
110
  */
111
111
  anonymousReadOnly?: boolean;
112
+ /**
113
+ * Optional auth adapter for the HTTP action route
114
+ * (`/_agent-native/actions/*`). Its `resolveCaller` runs before the
115
+ * cookie/bearer `getSession` chain, letting an app accept caller identities
116
+ * `getSession` doesn't understand (e.g. an A2A JWT verified with
117
+ * `verifyA2AToken`) declaratively, instead of pre-seeding request context
118
+ * from a Nitro `request` hook.
119
+ *
120
+ * Returning `null` defers to the normal chain; THROWING hard-rejects with a
121
+ * 401 (an invalid/forged credential must not fall through to a same-origin
122
+ * session cookie). A resolved caller's org comes exclusively from the
123
+ * verified credential — the returned `orgId` or the owner-email membership
124
+ * lookup — never from the request's session cookie.
125
+ * See {@link import("../action-routes.js").ActionRouteAuthAdapter}.
126
+ */
127
+ actionRouteAuth?: import("../action-routes.js").ActionRouteAuthAdapter;
112
128
  /**
113
129
  * Optional callback to append template-specific context to the system
114
130
  * prompt on each request. Runs after AGENTS.md / skills / memory are
@@ -1804,6 +1804,7 @@ export function createAgentChatPlugin(
1804
1804
  getOwnerFromEvent,
1805
1805
  getUserNameFromEvent,
1806
1806
  resolveOrgId: options?.resolveOrgId,
1807
+ actionRouteAuth: options?.actionRouteAuth,
1807
1808
  });
1808
1809
  }
1809
1810
 
@@ -241,6 +241,7 @@ export {
241
241
  renderAgentNativeOgImageSvg,
242
242
  type AgentNativeOgImageInput,
243
243
  } from "./social-og-image.js";
244
+ export { resolveOgFontFiles } from "./og-fonts.js";
244
245
  export {
245
246
  createBrowserSessionActionEntries,
246
247
  type CreateBrowserSessionActionEntriesOptions,
@@ -320,7 +321,14 @@ export {
320
321
  export {
321
322
  mountActionRoutes,
322
323
  type MountActionRoutesOptions,
324
+ type ActionRouteAuthAdapter,
325
+ type ActionRouteResolvedCaller,
323
326
  } from "./action-routes.js";
327
+ export {
328
+ AGENT_RUN_OWNER_CONTEXT_KEY,
329
+ seedAgentRunOwnerContext,
330
+ type AgentRunOwnerContext,
331
+ } from "./agent-run-context.js";
324
332
  export {
325
333
  runWithRequestContext,
326
334
  hasRequestContext,
@@ -141,6 +141,10 @@ const CORE_SHARING_ACTIONS: Array<{ name: string; specifier: string }> = [
141
141
  name: "set-review-status",
142
142
  specifier: "@agent-native/core/review/actions/set-review-status",
143
143
  },
144
+ {
145
+ name: "send-review-thread-to-agent",
146
+ specifier: "@agent-native/core/review/actions/send-review-thread-to-agent",
147
+ },
144
148
  ];
145
149
 
146
150
  function isRuntimeSourceFile(filename: string): boolean {
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-07-14
4
+ ---
5
+
6
+ Daily dashboard email captures authenticate with a session cookie, fall back to a lighter panel set, and record page diagnostics when a capture fails.