@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
@@ -1,4 +1,4 @@
1
- import { getDbExec, isPostgres } from "../db/client.js";
1
+ import { getDbExec, isPostgres, type DbExec } from "../db/client.js";
2
2
  import { ensureIndexExists, ensureTableExists } from "../db/ddl-guard.js";
3
3
  import type { Visibility } from "../sharing/schema.js";
4
4
  import type {
@@ -43,9 +43,25 @@ export interface QueryReviewCommentsInput {
43
43
  includeResolved?: boolean;
44
44
  includeDeleted?: boolean;
45
45
  targetId?: string | null;
46
+ rootOnly?: boolean;
47
+ resolutionTargets?: readonly (ReviewResolutionTarget | null)[];
48
+ unconsumedOnly?: boolean;
46
49
  limit?: number;
47
50
  }
48
51
 
52
+ export interface GetReviewThreadSummaryInput {
53
+ resourceType: string;
54
+ resourceId: string;
55
+ scope: ReviewScope;
56
+ bypassScope?: boolean;
57
+ targetId?: string | null;
58
+ }
59
+
60
+ export interface ReviewThreadSummary {
61
+ openCount: number;
62
+ agentQueueCount: number;
63
+ }
64
+
49
65
  export interface UpsertReviewStatusInput {
50
66
  resourceType: string;
51
67
  resourceId: string;
@@ -112,6 +128,15 @@ export async function ensureReviewTables(): Promise<void> {
112
128
  ON agent_review_comments (owner_email, created_at)`,
113
129
  `CREATE INDEX IF NOT EXISTS idx_agent_review_comments_org
114
130
  ON agent_review_comments (org_id, created_at)`,
131
+ `CREATE INDEX IF NOT EXISTS idx_agent_review_comments_queue
132
+ ON agent_review_comments (
133
+ resource_type,
134
+ resource_id,
135
+ parent_comment_id,
136
+ resolution_target,
137
+ consumed_at,
138
+ created_at
139
+ )`,
115
140
  `CREATE INDEX IF NOT EXISTS idx_agent_review_statuses_resource
116
141
  ON agent_review_statuses (resource_type, resource_id)`,
117
142
  ];
@@ -126,9 +151,10 @@ export async function ensureReviewTables(): Promise<void> {
126
151
  await ensureIndexExists("idx_agent_review_comments_thread", indexes[1]);
127
152
  await ensureIndexExists("idx_agent_review_comments_owner", indexes[2]);
128
153
  await ensureIndexExists("idx_agent_review_comments_org", indexes[3]);
154
+ await ensureIndexExists("idx_agent_review_comments_queue", indexes[4]);
129
155
  await ensureIndexExists(
130
156
  "idx_agent_review_statuses_resource",
131
- indexes[4],
157
+ indexes[5],
132
158
  );
133
159
  } else {
134
160
  await client.execute(createCommentsSql);
@@ -145,9 +171,62 @@ export async function ensureReviewTables(): Promise<void> {
145
171
 
146
172
  export async function insertReviewComment(
147
173
  input: InsertReviewCommentInput,
174
+ ): Promise<ReviewComment> {
175
+ await ensureReviewTables();
176
+ return insertReviewCommentWithClient(input, getDbExec());
177
+ }
178
+
179
+ export async function insertReviewReply(
180
+ input: InsertReviewCommentInput & {
181
+ threadId: string;
182
+ parentCommentId: string;
183
+ },
184
+ routeTarget: ReviewResolutionTarget | null,
185
+ resource: { resourceType: string; resourceId: string },
148
186
  ): Promise<ReviewComment> {
149
187
  await ensureReviewTables();
150
188
  const client = getDbExec();
189
+ const insertAndRoute = async (tx: DbExec) => {
190
+ if (routeTarget) {
191
+ const routedCount = await routeReviewThreadWithClient(
192
+ tx,
193
+ input.threadId,
194
+ routeTarget,
195
+ resource,
196
+ );
197
+ if (routedCount < 1) {
198
+ throw new Error("Open review thread not found");
199
+ }
200
+ }
201
+ return insertReviewCommentWithClient(input, tx);
202
+ };
203
+ if (client.transaction) return client.transaction(insertAndRoute);
204
+
205
+ const reply = await insertReviewCommentWithClient(input, client);
206
+ if (!routeTarget) return reply;
207
+ try {
208
+ const routedCount = await routeReviewThreadWithClient(
209
+ client,
210
+ input.threadId,
211
+ routeTarget,
212
+ resource,
213
+ );
214
+ if (routedCount < 1) throw new Error("Open review thread not found");
215
+ return reply;
216
+ } catch (error) {
217
+ await client.execute({
218
+ sql: `DELETE FROM agent_review_comments
219
+ WHERE id = ? AND resource_type = ? AND resource_id = ?`,
220
+ args: [reply.id, resource.resourceType, resource.resourceId],
221
+ });
222
+ throw error;
223
+ }
224
+ }
225
+
226
+ async function insertReviewCommentWithClient(
227
+ input: InsertReviewCommentInput,
228
+ client: DbExec,
229
+ ): Promise<ReviewComment> {
151
230
  const id = createReviewId("comment");
152
231
  const now = new Date().toISOString();
153
232
  const comment: ReviewComment = {
@@ -180,6 +259,10 @@ export async function insertReviewComment(
180
259
  createdAt: now,
181
260
  updatedAt: now,
182
261
  metadata: input.metadata ?? null,
262
+ resolutionNote:
263
+ typeof input.metadata?.resolutionNote === "string"
264
+ ? input.metadata.resolutionNote
265
+ : null,
183
266
  };
184
267
 
185
268
  await client.execute({
@@ -273,18 +356,107 @@ export async function queryReviewComments(
273
356
  filterParams.push(input.targetId);
274
357
  }
275
358
  }
359
+ if (input.rootOnly) {
360
+ filters.push("parent_comment_id IS NULL");
361
+ }
362
+ if (input.unconsumedOnly) {
363
+ filters.push("consumed_at IS NULL");
364
+ }
365
+ if (input.resolutionTargets !== undefined) {
366
+ const targets = Array.from(
367
+ new Set(
368
+ input.resolutionTargets.filter(
369
+ (target): target is ReviewResolutionTarget => target !== null,
370
+ ),
371
+ ),
372
+ );
373
+ const resolutionFilters: string[] = [];
374
+ if (targets.length > 0) {
375
+ resolutionFilters.push(
376
+ `resolution_target IN (${targets.map(() => "?").join(", ")})`,
377
+ );
378
+ filterParams.push(...targets);
379
+ }
380
+ if (input.resolutionTargets.includes(null)) {
381
+ resolutionFilters.push("resolution_target IS NULL");
382
+ }
383
+ filters.push(
384
+ resolutionFilters.length > 0
385
+ ? `(${resolutionFilters.join(" OR ")})`
386
+ : "1 = 0",
387
+ );
388
+ }
276
389
 
390
+ const selectSql = input.rootOnly
391
+ ? `SELECT ${commentColumns()}
392
+ FROM (
393
+ SELECT ${commentColumns()},
394
+ ROW_NUMBER() OVER (
395
+ PARTITION BY thread_id
396
+ ORDER BY created_at ASC, id ASC
397
+ ) AS review_thread_rank
398
+ FROM agent_review_comments
399
+ WHERE ${filters.join(" AND ")}
400
+ ) AS distinct_review_threads
401
+ WHERE review_thread_rank = 1`
402
+ : `SELECT ${commentColumns()}
403
+ FROM agent_review_comments
404
+ WHERE ${filters.join(" AND ")}`;
277
405
  const result = await client.execute({
278
- sql: `SELECT ${commentColumns()}
279
- FROM agent_review_comments
280
- WHERE ${filters.join(" AND ")}
281
- ORDER BY created_at ASC
406
+ sql: `${selectSql}
407
+ ORDER BY created_at ASC${input.rootOnly ? ", id ASC" : ""}
282
408
  LIMIT ?`,
283
409
  args: [...filterParams, clampLimit(input.limit)],
284
410
  });
285
411
  return (result.rows ?? []).map(mapCommentRow);
286
412
  }
287
413
 
414
+ export async function getReviewThreadSummary(
415
+ input: GetReviewThreadSummaryInput,
416
+ ): Promise<ReviewThreadSummary> {
417
+ await ensureReviewTables();
418
+ const { clause, params } = input.bypassScope
419
+ ? { clause: "1 = 1", params: [] as unknown[] }
420
+ : scopedReviewClause(input.scope);
421
+ const filters = [
422
+ "resource_type = ?",
423
+ "resource_id = ?",
424
+ clause,
425
+ "parent_comment_id IS NULL",
426
+ "deleted_at IS NULL",
427
+ "status = 'open'",
428
+ ];
429
+ const filterParams: unknown[] = [
430
+ input.resourceType,
431
+ input.resourceId,
432
+ ...params,
433
+ ];
434
+ if (input.targetId !== undefined) {
435
+ if (input.targetId === null) {
436
+ filters.push("target_id IS NULL");
437
+ } else {
438
+ filters.push("target_id = ?");
439
+ filterParams.push(input.targetId);
440
+ }
441
+ }
442
+ const result = await getDbExec().execute({
443
+ sql: `SELECT COUNT(DISTINCT thread_id) AS open_count,
444
+ COUNT(DISTINCT CASE
445
+ WHEN (resolution_target IS NULL OR resolution_target <> 'human')
446
+ AND consumed_at IS NULL
447
+ THEN thread_id
448
+ END) AS agent_queue_count
449
+ FROM agent_review_comments
450
+ WHERE ${filters.join(" AND ")}`,
451
+ args: filterParams,
452
+ });
453
+ const row = result.rows?.[0];
454
+ return {
455
+ openCount: Number(row?.open_count ?? 0),
456
+ agentQueueCount: Number(row?.agent_queue_count ?? 0),
457
+ };
458
+ }
459
+
288
460
  export async function getReviewCommentById(
289
461
  id: string,
290
462
  scope: ReviewScope,
@@ -306,27 +478,106 @@ export async function getReviewCommentById(
306
478
  return row ? mapCommentRow(row) : null;
307
479
  }
308
480
 
481
+ export async function getReviewThreadRoot(
482
+ threadId: string,
483
+ resource: { resourceType: string; resourceId: string },
484
+ scope: ReviewScope,
485
+ options: { bypassScope?: boolean } = {},
486
+ ): Promise<ReviewComment | null> {
487
+ await ensureReviewTables();
488
+ const { clause, params } = options.bypassScope
489
+ ? { clause: "1 = 1", params: [] as unknown[] }
490
+ : scopedReviewClause(scope);
491
+ const result = await getDbExec().execute({
492
+ sql: `SELECT ${commentColumns()}
493
+ FROM agent_review_comments
494
+ WHERE thread_id = ?
495
+ AND resource_type = ?
496
+ AND resource_id = ?
497
+ AND parent_comment_id IS NULL
498
+ AND ${clause}
499
+ ORDER BY created_at ASC, id ASC
500
+ LIMIT 1`,
501
+ args: [threadId, resource.resourceType, resource.resourceId, ...params],
502
+ });
503
+ const row = result.rows?.[0];
504
+ return row ? mapCommentRow(row) : null;
505
+ }
506
+
309
507
  export async function resolveReviewThread(
310
508
  threadId: string,
311
509
  resolvedBy?: string | null,
312
510
  resource?: { resourceType: string; resourceId: string },
511
+ resolutionNote?: string,
313
512
  ): Promise<number> {
314
513
  await ensureReviewTables();
514
+ const client = getDbExec();
515
+ const resolve = (tx: DbExec) =>
516
+ resolveReviewThreadWithClient(
517
+ tx,
518
+ threadId,
519
+ resolvedBy,
520
+ resource,
521
+ resolutionNote,
522
+ );
523
+ return client.transaction ? client.transaction(resolve) : resolve(client);
524
+ }
525
+
526
+ async function resolveReviewThreadWithClient(
527
+ client: DbExec,
528
+ threadId: string,
529
+ resolvedBy?: string | null,
530
+ resource?: { resourceType: string; resourceId: string },
531
+ resolutionNote?: string,
532
+ ): Promise<number> {
315
533
  const now = new Date().toISOString();
316
534
  const resourceClause = resource
317
535
  ? "AND resource_type = ? AND resource_id = ?"
318
536
  : "";
319
- const result = await getDbExec().execute({
537
+ let rootMetadata: Record<string, unknown> | null = null;
538
+ if (resolutionNote !== undefined) {
539
+ const root = await client.execute({
540
+ sql: `SELECT metadata_json
541
+ FROM agent_review_comments
542
+ WHERE thread_id = ?
543
+ AND parent_comment_id IS NULL
544
+ AND deleted_at IS NULL
545
+ ${resourceClause}
546
+ ORDER BY created_at ASC, id ASC
547
+ LIMIT 1`,
548
+ args: [
549
+ threadId,
550
+ ...(resource ? [resource.resourceType, resource.resourceId] : []),
551
+ ],
552
+ });
553
+ if (!root.rows?.[0]) {
554
+ return 0;
555
+ }
556
+ rootMetadata = {
557
+ ...(parseObject(root.rows[0].metadata_json) ?? {}),
558
+ resolutionNote,
559
+ };
560
+ }
561
+
562
+ const metadataAssignment =
563
+ resolutionNote === undefined
564
+ ? ""
565
+ : ", metadata_json = CASE WHEN parent_comment_id IS NULL THEN ? ELSE metadata_json END";
566
+ const result = await client.execute({
320
567
  sql: `UPDATE agent_review_comments
321
568
  SET status = 'resolved',
322
569
  resolved_by = ?,
323
570
  resolved_at = ?,
324
571
  updated_at = ?
572
+ ${metadataAssignment}
325
573
  WHERE thread_id = ? AND deleted_at IS NULL ${resourceClause}`,
326
574
  args: [
327
575
  resolvedBy ?? null,
328
576
  now,
329
577
  now,
578
+ ...(resolutionNote === undefined
579
+ ? []
580
+ : [stringifyOptionalJson(rootMetadata)]),
330
581
  threadId,
331
582
  ...(resource ? [resource.resourceType, resource.resourceId] : []),
332
583
  ],
@@ -334,6 +585,57 @@ export async function resolveReviewThread(
334
585
  return result.rowsAffected ?? 0;
335
586
  }
336
587
 
588
+ export async function routeReviewThread(
589
+ threadId: string,
590
+ resolutionTarget: ReviewResolutionTarget,
591
+ resource: { resourceType: string; resourceId: string },
592
+ ): Promise<number> {
593
+ await ensureReviewTables();
594
+ return routeReviewThreadWithClient(
595
+ getDbExec(),
596
+ threadId,
597
+ resolutionTarget,
598
+ resource,
599
+ );
600
+ }
601
+
602
+ async function routeReviewThreadWithClient(
603
+ client: DbExec,
604
+ threadId: string,
605
+ resolutionTarget: ReviewResolutionTarget,
606
+ resource: { resourceType: string; resourceId: string },
607
+ ): Promise<number> {
608
+ const now = new Date().toISOString();
609
+ const result = await client.execute({
610
+ sql: `UPDATE agent_review_comments
611
+ SET resolution_target = ?,
612
+ consumed_at = CASE WHEN ? = 'agent' THEN NULL ELSE consumed_at END,
613
+ updated_at = ?
614
+ WHERE thread_id = ?
615
+ AND resource_type = ?
616
+ AND resource_id = ?
617
+ AND parent_comment_id IS NULL
618
+ AND status = 'open'
619
+ AND deleted_at IS NULL`,
620
+ args: [
621
+ resolutionTarget,
622
+ resolutionTarget,
623
+ now,
624
+ threadId,
625
+ resource.resourceType,
626
+ resource.resourceId,
627
+ ],
628
+ });
629
+ return result.rowsAffected ?? 0;
630
+ }
631
+
632
+ export async function sendReviewThreadToAgent(
633
+ threadId: string,
634
+ resource: { resourceType: string; resourceId: string },
635
+ ): Promise<number> {
636
+ return routeReviewThread(threadId, "agent", resource);
637
+ }
638
+
337
639
  export async function deleteReviewComment(
338
640
  id: string,
339
641
  deletedBy?: string | null,
@@ -560,6 +862,7 @@ function scopedReviewClause(scope: ReviewScope): {
560
862
  }
561
863
 
562
864
  function mapCommentRow(row: Record<string, unknown>): ReviewComment {
865
+ const metadata = parseObject(row.metadata_json);
563
866
  return {
564
867
  id: String(row.id),
565
868
  resourceType: String(row.resource_type),
@@ -586,7 +889,11 @@ function mapCommentRow(row: Record<string, unknown>): ReviewComment {
586
889
  deletedAt: nullableString(row.deleted_at),
587
890
  createdAt: String(row.created_at),
588
891
  updatedAt: String(row.updated_at),
589
- metadata: parseObject(row.metadata_json),
892
+ metadata,
893
+ resolutionNote:
894
+ typeof metadata?.resolutionNote === "string"
895
+ ? metadata.resolutionNote
896
+ : null,
590
897
  };
591
898
  }
592
899
 
@@ -75,6 +75,10 @@ export interface ReviewComment {
75
75
  createdAt: string;
76
76
  updatedAt: string;
77
77
  metadata: Record<string, unknown> | null;
78
+ /** Persisted on the root comment's metadata when a thread is resolved. */
79
+ resolutionNote?: string | null;
80
+ /** Caller-specific capability computed by list-review-comments. */
81
+ canDelete?: boolean;
78
82
  }
79
83
 
80
84
  export interface ReviewStatusEntry {
@@ -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 {