@agent-native/core 0.96.0 → 0.97.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (450) hide show
  1. package/README.md +6 -0
  2. package/corpus/README.md +2 -2
  3. package/corpus/core/CHANGELOG.md +39 -0
  4. package/corpus/core/docs/content/audit-log.mdx +2 -1
  5. package/corpus/core/docs/content/automations.mdx +7 -7
  6. package/corpus/core/docs/content/creating-templates.mdx +1 -1
  7. package/corpus/core/docs/content/internationalization.mdx +2 -1
  8. package/corpus/core/docs/content/locales/ar-SA/audit-log.mdx +2 -1
  9. package/corpus/core/docs/content/locales/ar-SA/automations.mdx +7 -7
  10. package/corpus/core/docs/content/locales/ar-SA/getting-started.mdx +7 -1
  11. package/corpus/core/docs/content/locales/ar-SA/internationalization.mdx +1 -1
  12. package/corpus/core/docs/content/locales/ar-SA/package-lifecycle.mdx +19 -0
  13. package/corpus/core/docs/content/locales/ar-SA/sandbox-adapters.mdx +18 -7
  14. package/corpus/core/docs/content/locales/ar-SA/security.mdx +8 -0
  15. package/corpus/core/docs/content/locales/de-DE/audit-log.mdx +2 -1
  16. package/corpus/core/docs/content/locales/de-DE/automations.mdx +7 -7
  17. package/corpus/core/docs/content/locales/de-DE/getting-started.mdx +7 -1
  18. package/corpus/core/docs/content/locales/de-DE/internationalization.mdx +1 -1
  19. package/corpus/core/docs/content/locales/de-DE/package-lifecycle.mdx +22 -0
  20. package/corpus/core/docs/content/locales/de-DE/sandbox-adapters.mdx +18 -7
  21. package/corpus/core/docs/content/locales/de-DE/security.mdx +8 -0
  22. package/corpus/core/docs/content/locales/es-ES/audit-log.mdx +2 -1
  23. package/corpus/core/docs/content/locales/es-ES/automations.mdx +7 -7
  24. package/corpus/core/docs/content/locales/es-ES/getting-started.mdx +7 -1
  25. package/corpus/core/docs/content/locales/es-ES/internationalization.mdx +1 -1
  26. package/corpus/core/docs/content/locales/es-ES/package-lifecycle.mdx +22 -0
  27. package/corpus/core/docs/content/locales/es-ES/sandbox-adapters.mdx +18 -7
  28. package/corpus/core/docs/content/locales/es-ES/security.mdx +8 -0
  29. package/corpus/core/docs/content/locales/fr-FR/audit-log.mdx +2 -1
  30. package/corpus/core/docs/content/locales/fr-FR/automations.mdx +7 -7
  31. package/corpus/core/docs/content/locales/fr-FR/getting-started.mdx +7 -1
  32. package/corpus/core/docs/content/locales/fr-FR/internationalization.mdx +1 -1
  33. package/corpus/core/docs/content/locales/fr-FR/package-lifecycle.mdx +21 -0
  34. package/corpus/core/docs/content/locales/fr-FR/sandbox-adapters.mdx +19 -8
  35. package/corpus/core/docs/content/locales/fr-FR/security.mdx +8 -0
  36. package/corpus/core/docs/content/locales/hi-IN/audit-log.mdx +2 -1
  37. package/corpus/core/docs/content/locales/hi-IN/automations.mdx +7 -7
  38. package/corpus/core/docs/content/locales/hi-IN/getting-started.mdx +7 -1
  39. package/corpus/core/docs/content/locales/hi-IN/internationalization.mdx +1 -1
  40. package/corpus/core/docs/content/locales/hi-IN/package-lifecycle.mdx +20 -0
  41. package/corpus/core/docs/content/locales/hi-IN/sandbox-adapters.mdx +18 -7
  42. package/corpus/core/docs/content/locales/hi-IN/security.mdx +8 -0
  43. package/corpus/core/docs/content/locales/ja-JP/audit-log.mdx +2 -1
  44. package/corpus/core/docs/content/locales/ja-JP/automations.mdx +7 -7
  45. package/corpus/core/docs/content/locales/ja-JP/getting-started.mdx +7 -1
  46. package/corpus/core/docs/content/locales/ja-JP/internationalization.mdx +1 -1
  47. package/corpus/core/docs/content/locales/ja-JP/package-lifecycle.mdx +21 -0
  48. package/corpus/core/docs/content/locales/ja-JP/sandbox-adapters.mdx +17 -6
  49. package/corpus/core/docs/content/locales/ja-JP/security.mdx +8 -0
  50. package/corpus/core/docs/content/locales/ko-KR/audit-log.mdx +2 -1
  51. package/corpus/core/docs/content/locales/ko-KR/automations.mdx +7 -7
  52. package/corpus/core/docs/content/locales/ko-KR/getting-started.mdx +7 -1
  53. package/corpus/core/docs/content/locales/ko-KR/internationalization.mdx +1 -1
  54. package/corpus/core/docs/content/locales/ko-KR/package-lifecycle.mdx +20 -0
  55. package/corpus/core/docs/content/locales/ko-KR/sandbox-adapters.mdx +17 -6
  56. package/corpus/core/docs/content/locales/ko-KR/security.mdx +8 -0
  57. package/corpus/core/docs/content/locales/pt-BR/audit-log.mdx +2 -1
  58. package/corpus/core/docs/content/locales/pt-BR/automations.mdx +7 -7
  59. package/corpus/core/docs/content/locales/pt-BR/getting-started.mdx +7 -1
  60. package/corpus/core/docs/content/locales/pt-BR/internationalization.mdx +1 -1
  61. package/corpus/core/docs/content/locales/pt-BR/package-lifecycle.mdx +21 -0
  62. package/corpus/core/docs/content/locales/pt-BR/sandbox-adapters.mdx +18 -7
  63. package/corpus/core/docs/content/locales/pt-BR/security.mdx +8 -0
  64. package/corpus/core/docs/content/locales/zh-CN/audit-log.mdx +2 -1
  65. package/corpus/core/docs/content/locales/zh-CN/automations.mdx +7 -7
  66. package/corpus/core/docs/content/locales/zh-CN/getting-started.mdx +6 -4
  67. package/corpus/core/docs/content/locales/zh-CN/internationalization.mdx +1 -1
  68. package/corpus/core/docs/content/locales/zh-CN/package-lifecycle.mdx +19 -0
  69. package/corpus/core/docs/content/locales/zh-CN/sandbox-adapters.mdx +17 -6
  70. package/corpus/core/docs/content/locales/zh-CN/security.mdx +8 -0
  71. package/corpus/core/docs/content/locales/zh-TW/audit-log.mdx +2 -1
  72. package/corpus/core/docs/content/locales/zh-TW/automations.mdx +7 -7
  73. package/corpus/core/docs/content/locales/zh-TW/getting-started.mdx +6 -4
  74. package/corpus/core/docs/content/locales/zh-TW/internationalization.mdx +1 -1
  75. package/corpus/core/docs/content/locales/zh-TW/package-lifecycle.mdx +19 -0
  76. package/corpus/core/docs/content/locales/zh-TW/sandbox-adapters.mdx +18 -7
  77. package/corpus/core/docs/content/locales/zh-TW/security.mdx +8 -0
  78. package/corpus/core/docs/content/package-lifecycle.mdx +51 -0
  79. package/corpus/core/docs/content/sandbox-adapters.mdx +16 -5
  80. package/corpus/core/package.json +9 -2
  81. package/corpus/core/src/a2a/auth-policy.ts +33 -0
  82. package/corpus/core/src/agent/durable-background.ts +15 -7
  83. package/corpus/core/src/agent/run-store.ts +13 -4
  84. package/corpus/core/src/audit/actions/export-audit-events.ts +162 -0
  85. package/corpus/core/src/audit/store.ts +8 -3
  86. package/corpus/core/src/audit/types.ts +3 -0
  87. package/corpus/core/src/cli/doctor.ts +396 -0
  88. package/corpus/core/src/cli/index.ts +56 -0
  89. package/corpus/core/src/cli/info.ts +3 -3
  90. package/corpus/core/src/cli/package-lifecycle.ts +821 -0
  91. package/corpus/core/src/client/agent-chat-adapter.ts +9 -9
  92. package/corpus/core/src/guards/db-tool-scoping.ts +129 -0
  93. package/corpus/core/src/guards/index.ts +23 -0
  94. package/corpus/core/src/guards/no-drizzle-push.ts +116 -0
  95. package/corpus/core/src/guards/no-env-credentials.ts +229 -0
  96. package/corpus/core/src/guards/no-env-mutation.ts +114 -0
  97. package/corpus/core/src/guards/no-localhost-fallback.ts +124 -0
  98. package/corpus/core/src/guards/no-unscoped-credentials.ts +227 -0
  99. package/corpus/core/src/guards/no-unscoped-queries.ts +834 -0
  100. package/corpus/core/src/guards/scan-utils.ts +105 -0
  101. package/corpus/core/src/guards/types.ts +30 -0
  102. package/corpus/core/src/org/accept-pending.ts +9 -1
  103. package/corpus/core/src/org/migrations.ts +41 -0
  104. package/corpus/core/src/package-lifecycle/index.ts +1 -0
  105. package/corpus/core/src/package-lifecycle/manifest.ts +120 -0
  106. package/corpus/core/src/provider-api/custom-registry.ts +56 -0
  107. package/corpus/core/src/provider-api/index.ts +2 -0
  108. package/corpus/core/src/secrets/storage.ts +47 -27
  109. package/corpus/core/src/server/action-discovery.ts +4 -0
  110. package/corpus/core/src/server/agent-chat-plugin.ts +54 -12
  111. package/corpus/core/src/server/core-routes-plugin.ts +30 -14
  112. package/corpus/core/src/server/csrf.ts +24 -5
  113. package/corpus/core/src/server/framework-request-handler.ts +34 -0
  114. package/corpus/core/src/server/google-realtime-session.ts +1 -36
  115. package/corpus/core/src/server/poll.ts +24 -2
  116. package/corpus/core/src/server/realtime-voice.ts +9 -0
  117. package/corpus/core/src/server/request-origin.ts +63 -0
  118. package/corpus/core/src/server/transcribe-voice.ts +1 -50
  119. package/corpus/core/src/templates/default/package.json +2 -2
  120. package/corpus/core/src/templates/headless/package.json +0 -1
  121. package/corpus/core/src/templates/workspace-core/.agents/skills/audit-log/SKILL.md +3 -0
  122. package/corpus/core/src/templates/workspace-core/.agents/skills/automations/SKILL.md +1 -1
  123. package/corpus/core/src/templates/workspace-core/package.json +0 -1
  124. package/corpus/core/src/templates/workspace-root/package.json +0 -1
  125. package/corpus/core/src/triggers/actions.ts +11 -3
  126. package/corpus/core/src/triggers/types.ts +7 -1
  127. package/corpus/templates/analytics/actions/compose-dashboard.ts +65 -37
  128. package/corpus/templates/analytics/actions/mutate-dashboard.ts +73 -24
  129. package/corpus/templates/analytics/actions/reorder-dashboard-panels.ts +16 -13
  130. package/corpus/templates/analytics/actions/update-dashboard.ts +53 -42
  131. package/corpus/templates/analytics/changelog/2026-07-10-dashboard-edits-from-the-agent-and-the-ui-at-the-same-time-n.md +6 -0
  132. package/corpus/templates/analytics/changelog/2026-07-10-timed-out-bigquery-jobs-are-now-cancelled-so-they-stop-consu.md +6 -0
  133. package/corpus/templates/analytics/package.json +1 -2
  134. package/corpus/templates/analytics/server/lib/bigquery.ts +3 -2
  135. package/corpus/templates/analytics/server/lib/dashboards-store.ts +154 -11
  136. package/corpus/templates/assets/package.json +1 -2
  137. package/corpus/templates/brain/package.json +1 -2
  138. package/corpus/templates/calendar/package.json +1 -2
  139. package/corpus/templates/chat/package.json +1 -2
  140. package/corpus/templates/clips/changelog/2026-07-10-atomic-view-tracking.md +6 -0
  141. package/corpus/templates/clips/chrome-extension/package.json +3 -2
  142. package/corpus/templates/clips/desktop/package.json +6 -4
  143. package/corpus/templates/clips/desktop/src/lib/recorder.ts +26 -13
  144. package/corpus/templates/clips/desktop/src/lib/voice-dictation.ts +4 -1
  145. package/corpus/templates/clips/package.json +1 -2
  146. package/corpus/templates/clips/server/db/schema.ts +29 -17
  147. package/corpus/templates/clips/server/plugins/db.ts +8 -0
  148. package/corpus/templates/clips/server/routes/api/view-event.post.ts +260 -105
  149. package/corpus/templates/content/.agents/skills/notion-integration/SKILL.md +16 -0
  150. package/corpus/templates/content/AGENTS.md +72 -62
  151. package/corpus/templates/content/actions/_content-database-source-adapters.ts +84 -0
  152. package/corpus/templates/content/actions/_database-source-utils.ts +206 -96
  153. package/corpus/templates/content/actions/_notion-database-source-adapter.ts +216 -0
  154. package/corpus/templates/content/actions/_position-utils.ts +76 -0
  155. package/corpus/templates/content/actions/_property-utils.ts +31 -20
  156. package/corpus/templates/content/actions/add-database-item.ts +52 -39
  157. package/corpus/templates/content/actions/attach-content-database-source.ts +95 -11
  158. package/corpus/templates/content/actions/change-content-database-source-role.ts +24 -1
  159. package/corpus/templates/content/actions/configure-document-property.ts +36 -27
  160. package/corpus/templates/content/actions/create-content-database.ts +40 -30
  161. package/corpus/templates/content/actions/create-document.ts +39 -32
  162. package/corpus/templates/content/actions/duplicate-document-property.ts +37 -28
  163. package/corpus/templates/content/actions/list-notion-database-sources.ts +80 -0
  164. package/corpus/templates/content/actions/move-document.ts +64 -48
  165. package/corpus/templates/content/actions/refresh-content-database-source.ts +42 -3
  166. package/corpus/templates/content/actions/share-local-file-document.ts +36 -27
  167. package/corpus/templates/content/actions/suggest-source-join-key.ts +39 -16
  168. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +89 -23
  169. package/corpus/templates/content/app/components/editor/database/settings.tsx +1 -1
  170. package/corpus/templates/content/app/hooks/use-content-database.ts +18 -1
  171. package/corpus/templates/content/app/i18n/zh-TW.ts +4 -0
  172. package/corpus/templates/content/app/i18n-data.ts +40 -0
  173. package/corpus/templates/content/changelog/2026-07-10-failed-row-creation-and-source-attach-now-show-an-error-inst.md +6 -0
  174. package/corpus/templates/content/changelog/2026-07-10-items-added-at-the-same-time-no-longer-end-up-with-identical.md +6 -0
  175. package/corpus/templates/content/changelog/2026-07-10-notion-databases-can-add-read-only-details-to-content-tables.md +6 -0
  176. package/corpus/templates/content/package.json +1 -2
  177. package/corpus/templates/content/parity/matrix.md +25 -25
  178. package/corpus/templates/content/parity/matrix.ts +1 -0
  179. package/corpus/templates/content/server/routes/api/documents/[id]/move.patch.ts +43 -26
  180. package/corpus/templates/content/shared/api.ts +16 -1
  181. package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +8 -4
  182. package/corpus/templates/design/AGENTS.md +12 -2
  183. package/corpus/templates/design/DEVELOPING.md +10 -6
  184. package/corpus/templates/design/actions/apply-visual-edit.ts +191 -6
  185. package/corpus/templates/design/actions/duplicate-design.ts +31 -25
  186. package/corpus/templates/design/app/pages/design-editor/pending-edits.ts +5 -1
  187. package/corpus/templates/design/changelog/2026-07-10-duplicating-a-design-can-no-longer-produce-a-copy-with-missi.md +6 -0
  188. package/corpus/templates/design/changelog/2026-07-10-local-visual-edits-can-now-save-safe-leaf-text-class-and.md +6 -0
  189. package/corpus/templates/design/package.json +1 -1
  190. package/corpus/templates/design/shared/local-jsx-visual-edit.ts +388 -0
  191. package/corpus/templates/dispatch/package.json +1 -2
  192. package/corpus/templates/forms/actions/patch-form-fields.ts +82 -44
  193. package/corpus/templates/forms/changelog/2026-07-10-simultaneous-edits-to-different-form-fields-no-longer-overwr.md +6 -0
  194. package/corpus/templates/forms/package.json +1 -2
  195. package/corpus/templates/macros/package.json +1 -2
  196. package/corpus/templates/mail/app/components/email/EmailThread.tsx +3 -1
  197. package/corpus/templates/mail/changelog/2026-07-10-fixed-calendar-rsvp-buttons-in-emails-firing-duplicate-respo.md +6 -0
  198. package/corpus/templates/mail/package.json +1 -2
  199. package/corpus/templates/plan/actions/restore-plan-version.ts +126 -96
  200. package/corpus/templates/plan/changelog/2026-07-10-restoring-a-plan-version-can-no-longer-leave-a-plan-half-res.md +6 -0
  201. package/corpus/templates/plan/package.json +1 -2
  202. package/corpus/templates/plan/server/plans.ts +9 -2
  203. package/corpus/templates/slides/actions/list-decks.ts +28 -0
  204. package/corpus/templates/slides/app/components/deck/MermaidRenderer.tsx +41 -26
  205. package/corpus/templates/slides/app/components/design-system/DesignSystemSetup.tsx +4 -8
  206. package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +2 -4
  207. package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +4 -8
  208. package/corpus/templates/slides/app/components/editor/ExportMenu.tsx +5 -12
  209. package/corpus/templates/slides/app/components/editor/HistoryPanel.tsx +3 -6
  210. package/corpus/templates/slides/app/components/editor/ImageDropPromptPopover.tsx +3 -6
  211. package/corpus/templates/slides/app/components/editor/PromptDialog.tsx +2 -5
  212. package/corpus/templates/slides/app/context/DeckContext.tsx +47 -4
  213. package/corpus/templates/slides/app/pages/DeckEditor.tsx +11 -30
  214. package/corpus/templates/slides/app/pages/Index.tsx +2 -3
  215. package/corpus/templates/slides/app/root.tsx +0 -5
  216. package/corpus/templates/slides/changelog/2026-07-10-deck-lists-load-much-faster-and-no-longer-re-download-slide-.md +6 -0
  217. package/corpus/templates/slides/package.json +1 -2
  218. package/dist/a2a/auth-policy.d.ts +19 -0
  219. package/dist/a2a/auth-policy.d.ts.map +1 -1
  220. package/dist/a2a/auth-policy.js +32 -0
  221. package/dist/a2a/auth-policy.js.map +1 -1
  222. package/dist/agent/durable-background.d.ts +8 -5
  223. package/dist/agent/durable-background.d.ts.map +1 -1
  224. package/dist/agent/durable-background.js +15 -8
  225. package/dist/agent/durable-background.js.map +1 -1
  226. package/dist/agent/run-store.d.ts.map +1 -1
  227. package/dist/agent/run-store.js +9 -4
  228. package/dist/agent/run-store.js.map +1 -1
  229. package/dist/audit/actions/export-audit-events.d.ts +27 -0
  230. package/dist/audit/actions/export-audit-events.d.ts.map +1 -0
  231. package/dist/audit/actions/export-audit-events.js +144 -0
  232. package/dist/audit/actions/export-audit-events.js.map +1 -0
  233. package/dist/audit/store.d.ts +1 -0
  234. package/dist/audit/store.d.ts.map +1 -1
  235. package/dist/audit/store.js +8 -3
  236. package/dist/audit/store.js.map +1 -1
  237. package/dist/audit/types.d.ts +3 -0
  238. package/dist/audit/types.d.ts.map +1 -1
  239. package/dist/audit/types.js.map +1 -1
  240. package/dist/cli/doctor.d.ts +83 -0
  241. package/dist/cli/doctor.d.ts.map +1 -0
  242. package/dist/cli/doctor.js +277 -0
  243. package/dist/cli/doctor.js.map +1 -0
  244. package/dist/cli/index.js +50 -0
  245. package/dist/cli/index.js.map +1 -1
  246. package/dist/cli/info.js +3 -3
  247. package/dist/cli/info.js.map +1 -1
  248. package/dist/cli/package-lifecycle.d.ts +50 -0
  249. package/dist/cli/package-lifecycle.d.ts.map +1 -0
  250. package/dist/cli/package-lifecycle.js +560 -0
  251. package/dist/cli/package-lifecycle.js.map +1 -0
  252. package/dist/client/agent-chat-adapter.js +7 -3
  253. package/dist/client/agent-chat-adapter.js.map +1 -1
  254. package/dist/collab/struct-routes.d.ts +1 -1
  255. package/dist/guards/db-tool-scoping.d.ts +38 -0
  256. package/dist/guards/db-tool-scoping.d.ts.map +1 -0
  257. package/dist/guards/db-tool-scoping.js +114 -0
  258. package/dist/guards/db-tool-scoping.js.map +1 -0
  259. package/dist/guards/index.d.ts +23 -0
  260. package/dist/guards/index.d.ts.map +1 -0
  261. package/dist/guards/index.js +19 -0
  262. package/dist/guards/index.js.map +1 -0
  263. package/dist/guards/no-drizzle-push.d.ts +14 -0
  264. package/dist/guards/no-drizzle-push.d.ts.map +1 -0
  265. package/dist/guards/no-drizzle-push.js +97 -0
  266. package/dist/guards/no-drizzle-push.js.map +1 -0
  267. package/dist/guards/no-env-credentials.d.ts +36 -0
  268. package/dist/guards/no-env-credentials.d.ts.map +1 -0
  269. package/dist/guards/no-env-credentials.js +204 -0
  270. package/dist/guards/no-env-credentials.js.map +1 -0
  271. package/dist/guards/no-env-mutation.d.ts +23 -0
  272. package/dist/guards/no-env-mutation.d.ts.map +1 -0
  273. package/dist/guards/no-env-mutation.js +90 -0
  274. package/dist/guards/no-env-mutation.js.map +1 -0
  275. package/dist/guards/no-localhost-fallback.d.ts +30 -0
  276. package/dist/guards/no-localhost-fallback.d.ts.map +1 -0
  277. package/dist/guards/no-localhost-fallback.js +105 -0
  278. package/dist/guards/no-localhost-fallback.js.map +1 -0
  279. package/dist/guards/no-unscoped-credentials.d.ts +28 -0
  280. package/dist/guards/no-unscoped-credentials.d.ts.map +1 -0
  281. package/dist/guards/no-unscoped-credentials.js +199 -0
  282. package/dist/guards/no-unscoped-credentials.js.map +1 -0
  283. package/dist/guards/no-unscoped-queries.d.ts +32 -0
  284. package/dist/guards/no-unscoped-queries.d.ts.map +1 -0
  285. package/dist/guards/no-unscoped-queries.js +720 -0
  286. package/dist/guards/no-unscoped-queries.js.map +1 -0
  287. package/dist/guards/scan-utils.d.ts +28 -0
  288. package/dist/guards/scan-utils.d.ts.map +1 -0
  289. package/dist/guards/scan-utils.js +92 -0
  290. package/dist/guards/scan-utils.js.map +1 -0
  291. package/dist/guards/types.d.ts +28 -0
  292. package/dist/guards/types.d.ts.map +1 -0
  293. package/dist/guards/types.js +11 -0
  294. package/dist/guards/types.js.map +1 -0
  295. package/dist/org/accept-pending.d.ts.map +1 -1
  296. package/dist/org/accept-pending.js +9 -1
  297. package/dist/org/accept-pending.js.map +1 -1
  298. package/dist/org/migrations.d.ts +7 -2
  299. package/dist/org/migrations.d.ts.map +1 -1
  300. package/dist/org/migrations.js +41 -0
  301. package/dist/org/migrations.js.map +1 -1
  302. package/dist/package-lifecycle/index.d.ts +2 -0
  303. package/dist/package-lifecycle/index.d.ts.map +1 -0
  304. package/dist/package-lifecycle/index.js +2 -0
  305. package/dist/package-lifecycle/index.js.map +1 -0
  306. package/dist/package-lifecycle/manifest.d.ts +24 -0
  307. package/dist/package-lifecycle/manifest.d.ts.map +1 -0
  308. package/dist/package-lifecycle/manifest.js +81 -0
  309. package/dist/package-lifecycle/manifest.js.map +1 -0
  310. package/dist/progress/routes.d.ts +1 -1
  311. package/dist/provider-api/custom-registry.d.ts +32 -1
  312. package/dist/provider-api/custom-registry.d.ts.map +1 -1
  313. package/dist/provider-api/custom-registry.js +41 -1
  314. package/dist/provider-api/custom-registry.js.map +1 -1
  315. package/dist/provider-api/index.d.ts +1 -1
  316. package/dist/provider-api/index.d.ts.map +1 -1
  317. package/dist/provider-api/index.js +1 -1
  318. package/dist/provider-api/index.js.map +1 -1
  319. package/dist/secrets/storage.d.ts.map +1 -1
  320. package/dist/secrets/storage.js +45 -27
  321. package/dist/secrets/storage.js.map +1 -1
  322. package/dist/server/action-discovery.d.ts.map +1 -1
  323. package/dist/server/action-discovery.js +4 -0
  324. package/dist/server/action-discovery.js.map +1 -1
  325. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  326. package/dist/server/agent-chat-plugin.js +47 -13
  327. package/dist/server/agent-chat-plugin.js.map +1 -1
  328. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  329. package/dist/server/core-routes-plugin.js +23 -12
  330. package/dist/server/core-routes-plugin.js.map +1 -1
  331. package/dist/server/csrf.d.ts.map +1 -1
  332. package/dist/server/csrf.js +18 -5
  333. package/dist/server/csrf.js.map +1 -1
  334. package/dist/server/framework-request-handler.d.ts.map +1 -1
  335. package/dist/server/framework-request-handler.js +34 -0
  336. package/dist/server/framework-request-handler.js.map +1 -1
  337. package/dist/server/google-realtime-session.d.ts.map +1 -1
  338. package/dist/server/google-realtime-session.js +2 -34
  339. package/dist/server/google-realtime-session.js.map +1 -1
  340. package/dist/server/poll.d.ts.map +1 -1
  341. package/dist/server/poll.js +24 -2
  342. package/dist/server/poll.js.map +1 -1
  343. package/dist/server/realtime-voice.d.ts.map +1 -1
  344. package/dist/server/realtime-voice.js +9 -0
  345. package/dist/server/realtime-voice.js.map +1 -1
  346. package/dist/server/request-origin.d.ts +10 -0
  347. package/dist/server/request-origin.d.ts.map +1 -0
  348. package/dist/server/request-origin.js +60 -0
  349. package/dist/server/request-origin.js.map +1 -0
  350. package/dist/server/transcribe-voice.d.ts.map +1 -1
  351. package/dist/server/transcribe-voice.js +2 -48
  352. package/dist/server/transcribe-voice.js.map +1 -1
  353. package/dist/templates/default/package.json +2 -2
  354. package/dist/templates/headless/package.json +0 -1
  355. package/dist/templates/workspace-core/.agents/skills/audit-log/SKILL.md +3 -0
  356. package/dist/templates/workspace-core/.agents/skills/automations/SKILL.md +1 -1
  357. package/dist/templates/workspace-core/package.json +0 -1
  358. package/dist/templates/workspace-root/package.json +0 -1
  359. package/dist/triggers/actions.d.ts.map +1 -1
  360. package/dist/triggers/actions.js +8 -3
  361. package/dist/triggers/actions.js.map +1 -1
  362. package/dist/triggers/types.d.ts +7 -1
  363. package/dist/triggers/types.d.ts.map +1 -1
  364. package/dist/triggers/types.js.map +1 -1
  365. package/docs/content/audit-log.mdx +2 -1
  366. package/docs/content/automations.mdx +7 -7
  367. package/docs/content/creating-templates.mdx +1 -1
  368. package/docs/content/internationalization.mdx +2 -1
  369. package/docs/content/locales/ar-SA/audit-log.mdx +2 -1
  370. package/docs/content/locales/ar-SA/automations.mdx +7 -7
  371. package/docs/content/locales/ar-SA/getting-started.mdx +7 -1
  372. package/docs/content/locales/ar-SA/internationalization.mdx +1 -1
  373. package/docs/content/locales/ar-SA/package-lifecycle.mdx +19 -0
  374. package/docs/content/locales/ar-SA/sandbox-adapters.mdx +18 -7
  375. package/docs/content/locales/ar-SA/security.mdx +8 -0
  376. package/docs/content/locales/de-DE/audit-log.mdx +2 -1
  377. package/docs/content/locales/de-DE/automations.mdx +7 -7
  378. package/docs/content/locales/de-DE/getting-started.mdx +7 -1
  379. package/docs/content/locales/de-DE/internationalization.mdx +1 -1
  380. package/docs/content/locales/de-DE/package-lifecycle.mdx +22 -0
  381. package/docs/content/locales/de-DE/sandbox-adapters.mdx +18 -7
  382. package/docs/content/locales/de-DE/security.mdx +8 -0
  383. package/docs/content/locales/es-ES/audit-log.mdx +2 -1
  384. package/docs/content/locales/es-ES/automations.mdx +7 -7
  385. package/docs/content/locales/es-ES/getting-started.mdx +7 -1
  386. package/docs/content/locales/es-ES/internationalization.mdx +1 -1
  387. package/docs/content/locales/es-ES/package-lifecycle.mdx +22 -0
  388. package/docs/content/locales/es-ES/sandbox-adapters.mdx +18 -7
  389. package/docs/content/locales/es-ES/security.mdx +8 -0
  390. package/docs/content/locales/fr-FR/audit-log.mdx +2 -1
  391. package/docs/content/locales/fr-FR/automations.mdx +7 -7
  392. package/docs/content/locales/fr-FR/getting-started.mdx +7 -1
  393. package/docs/content/locales/fr-FR/internationalization.mdx +1 -1
  394. package/docs/content/locales/fr-FR/package-lifecycle.mdx +21 -0
  395. package/docs/content/locales/fr-FR/sandbox-adapters.mdx +19 -8
  396. package/docs/content/locales/fr-FR/security.mdx +8 -0
  397. package/docs/content/locales/hi-IN/audit-log.mdx +2 -1
  398. package/docs/content/locales/hi-IN/automations.mdx +7 -7
  399. package/docs/content/locales/hi-IN/getting-started.mdx +7 -1
  400. package/docs/content/locales/hi-IN/internationalization.mdx +1 -1
  401. package/docs/content/locales/hi-IN/package-lifecycle.mdx +20 -0
  402. package/docs/content/locales/hi-IN/sandbox-adapters.mdx +18 -7
  403. package/docs/content/locales/hi-IN/security.mdx +8 -0
  404. package/docs/content/locales/ja-JP/audit-log.mdx +2 -1
  405. package/docs/content/locales/ja-JP/automations.mdx +7 -7
  406. package/docs/content/locales/ja-JP/getting-started.mdx +7 -1
  407. package/docs/content/locales/ja-JP/internationalization.mdx +1 -1
  408. package/docs/content/locales/ja-JP/package-lifecycle.mdx +21 -0
  409. package/docs/content/locales/ja-JP/sandbox-adapters.mdx +17 -6
  410. package/docs/content/locales/ja-JP/security.mdx +8 -0
  411. package/docs/content/locales/ko-KR/audit-log.mdx +2 -1
  412. package/docs/content/locales/ko-KR/automations.mdx +7 -7
  413. package/docs/content/locales/ko-KR/getting-started.mdx +7 -1
  414. package/docs/content/locales/ko-KR/internationalization.mdx +1 -1
  415. package/docs/content/locales/ko-KR/package-lifecycle.mdx +20 -0
  416. package/docs/content/locales/ko-KR/sandbox-adapters.mdx +17 -6
  417. package/docs/content/locales/ko-KR/security.mdx +8 -0
  418. package/docs/content/locales/pt-BR/audit-log.mdx +2 -1
  419. package/docs/content/locales/pt-BR/automations.mdx +7 -7
  420. package/docs/content/locales/pt-BR/getting-started.mdx +7 -1
  421. package/docs/content/locales/pt-BR/internationalization.mdx +1 -1
  422. package/docs/content/locales/pt-BR/package-lifecycle.mdx +21 -0
  423. package/docs/content/locales/pt-BR/sandbox-adapters.mdx +18 -7
  424. package/docs/content/locales/pt-BR/security.mdx +8 -0
  425. package/docs/content/locales/zh-CN/audit-log.mdx +2 -1
  426. package/docs/content/locales/zh-CN/automations.mdx +7 -7
  427. package/docs/content/locales/zh-CN/getting-started.mdx +6 -4
  428. package/docs/content/locales/zh-CN/internationalization.mdx +1 -1
  429. package/docs/content/locales/zh-CN/package-lifecycle.mdx +19 -0
  430. package/docs/content/locales/zh-CN/sandbox-adapters.mdx +17 -6
  431. package/docs/content/locales/zh-CN/security.mdx +8 -0
  432. package/docs/content/locales/zh-TW/audit-log.mdx +2 -1
  433. package/docs/content/locales/zh-TW/automations.mdx +7 -7
  434. package/docs/content/locales/zh-TW/getting-started.mdx +6 -4
  435. package/docs/content/locales/zh-TW/internationalization.mdx +1 -1
  436. package/docs/content/locales/zh-TW/package-lifecycle.mdx +19 -0
  437. package/docs/content/locales/zh-TW/sandbox-adapters.mdx +18 -7
  438. package/docs/content/locales/zh-TW/security.mdx +8 -0
  439. package/docs/content/package-lifecycle.mdx +51 -0
  440. package/docs/content/sandbox-adapters.mdx +16 -5
  441. package/package.json +10 -3
  442. package/src/templates/default/package.json +2 -2
  443. package/src/templates/headless/package.json +0 -1
  444. package/src/templates/workspace-core/.agents/skills/audit-log/SKILL.md +3 -0
  445. package/src/templates/workspace-core/.agents/skills/automations/SKILL.md +1 -1
  446. package/src/templates/workspace-core/package.json +0 -1
  447. package/src/templates/workspace-root/package.json +0 -1
  448. package/corpus/templates/slides/app/components/ui/toast.tsx +0 -1
  449. package/corpus/templates/slides/app/components/ui/toaster.tsx +0 -1
  450. package/corpus/templates/slides/app/hooks/use-toast.ts +0 -1
@@ -1169,12 +1169,20 @@ export function createCoreRoutesPlugin(
1169
1169
  }),
1170
1170
  );
1171
1171
 
1172
- // Defense-in-depth CSRF check for state-changing /_agent-native/* routes.
1173
- // Mounted AFTER the CORS layer so disallowed-origin OPTIONS preflights
1174
- // 403 first (rather than being rejected on a stale cookie heuristic).
1175
- // See `csrf.ts` for the threat model and allowlist.
1176
- const { createCsrfMiddleware } = await import("./csrf.js");
1177
- getH3App(nitroApp).use(createCsrfMiddleware(P));
1172
+ // Defense-in-depth CSRF check for state-changing /_agent-native/* routes
1173
+ // (see `csrf.ts` for the threat model and allowlist) is registered by
1174
+ // `getH3App()` itself (framework-request-handler.ts), synchronously, on
1175
+ // the very first call to `getH3App(nitroApp)` for this process NOT
1176
+ // here. Registering it inside this plugin's own async init chain would
1177
+ // race against agent-chat-plugin's action-route registration (a
1178
+ // SEPARATE, independently-async-initialized Nitro plugin file in real
1179
+ // deployments): whichever plugin's `getH3App(nitroApp).use(...)` call
1180
+ // happened to resolve first would win the position in the middleware
1181
+ // array, and CSRF losing that race would let an action route match and
1182
+ // run before the CSRF check ever saw the request. Centralizing the
1183
+ // registration in `getH3App()`'s one-time bootstrap makes it the first
1184
+ // middleware any plugin's route can possibly land behind, regardless of
1185
+ // plugin init ordering.
1178
1186
 
1179
1187
  // Agent discovery primitive — shared by headless CLI/A2A surfaces and
1180
1188
  // UI shells that need to show connected peer apps without depending on
@@ -1275,8 +1283,11 @@ export function createCoreRoutesPlugin(
1275
1283
  return { error: "executionId required" };
1276
1284
  }
1277
1285
 
1278
- const { hasConfiguredA2ASecret, isA2AProductionRuntime } =
1279
- await import("../a2a/auth-policy.js");
1286
+ const {
1287
+ hasConfiguredA2ASecret,
1288
+ isLoopbackAddress,
1289
+ isTrustedLocalRuntime,
1290
+ } = await import("../a2a/auth-policy.js");
1280
1291
  if (hasConfiguredA2ASecret()) {
1281
1292
  const { verifyInternalToken, extractBearerToken } =
1282
1293
  await import("../integrations/internal-token.js");
@@ -1285,12 +1296,17 @@ export function createCoreRoutesPlugin(
1285
1296
  setResponseStatus(event, 401);
1286
1297
  return { error: "Invalid or expired processor token" };
1287
1298
  }
1288
- } else if (isA2AProductionRuntime()) {
1289
- setResponseStatus(event, 503);
1290
- return {
1291
- error:
1292
- "Sandbox execution processor not configured — set A2A_SECRET on this deployment.",
1293
- };
1299
+ } else {
1300
+ const loopback = isLoopbackAddress(
1301
+ getRequestIP(event, { xForwardedFor: false }),
1302
+ );
1303
+ if (!isTrustedLocalRuntime({ loopback })) {
1304
+ setResponseStatus(event, 503);
1305
+ return {
1306
+ error:
1307
+ "Sandbox execution processor not configured — set A2A_SECRET on this deployment (or A2A_ALLOW_UNSIGNED_INTERNAL=1 for trusted local dev).",
1308
+ };
1309
+ }
1294
1310
  }
1295
1311
 
1296
1312
  try {
@@ -50,6 +50,8 @@ import {
50
50
  setResponseStatus,
51
51
  } from "h3";
52
52
 
53
+ import { getConfiguredAppBasePath } from "./app-base-path.js";
54
+
53
55
  /**
54
56
  * Path prefixes (relative to the framework prefix `/_agent-native`) that are
55
57
  * allowed to receive cross-origin state-changing POSTs without first-party
@@ -144,9 +146,10 @@ function requestHasCookies(event: any): boolean {
144
146
  }
145
147
 
146
148
  /**
147
- * Path passed in is the full request URL pathname (e.g. `/_agent-native/actions/foo`).
148
- * `frameworkPrefix` should be the framework route prefix without trailing slash,
149
- * e.g. `/_agent-native`.
149
+ * The path is the full request URL pathname (e.g.
150
+ * `/_agent-native/actions/foo` or `/app/_agent-native/actions/foo`).
151
+ * `frameworkPrefix` is the root framework route prefix without a trailing
152
+ * slash, e.g. `/_agent-native`.
150
153
  */
151
154
  function isOnAllowlist(pathname: string, frameworkPrefix: string): boolean {
152
155
  if (!pathname.startsWith(frameworkPrefix)) return false;
@@ -157,6 +160,21 @@ function isOnAllowlist(pathname: string, frameworkPrefix: string): boolean {
157
160
  return false;
158
161
  }
159
162
 
163
+ function matchingFrameworkPrefix(
164
+ pathname: string,
165
+ frameworkPrefix: string,
166
+ ): string | undefined {
167
+ if (pathname.startsWith(frameworkPrefix)) return frameworkPrefix;
168
+
169
+ const basePath = getConfiguredAppBasePath();
170
+ const basePathFrameworkPrefix = `${basePath}${frameworkPrefix}`;
171
+ if (basePath && pathname.startsWith(basePathFrameworkPrefix)) {
172
+ return basePathFrameworkPrefix;
173
+ }
174
+
175
+ return undefined;
176
+ }
177
+
160
178
  /**
161
179
  * Create the framework CSRF middleware.
162
180
  *
@@ -176,8 +194,9 @@ export function createCsrfMiddleware(
176
194
  if (!STATE_CHANGING_METHODS.has(method)) return undefined;
177
195
 
178
196
  const pathname = event.url?.pathname ?? "";
179
- if (!pathname.startsWith(frameworkPrefix)) return undefined;
180
- if (isOnAllowlist(pathname, frameworkPrefix)) return undefined;
197
+ const matchingPrefix = matchingFrameworkPrefix(pathname, frameworkPrefix);
198
+ if (!matchingPrefix) return undefined;
199
+ if (isOnAllowlist(pathname, matchingPrefix)) return undefined;
181
200
 
182
201
  // No cookie = no risk of confused-deputy CSRF on the session cookie.
183
202
  if (!requestHasCookies(event)) return undefined;
@@ -17,6 +17,7 @@ import { setResponseHeader, setResponseStatus } from "h3";
17
17
  import { getMissingDefaultPlugins } from "../deploy/route-discovery.js";
18
18
  import { getConfiguredAppBasePath } from "./app-base-path.js";
19
19
  import { captureError } from "./capture-error.js";
20
+ import { createCsrfMiddleware } from "./csrf.js";
20
21
 
21
22
  const BOOTSTRAPPED = new WeakSet<object>();
22
23
  const IN_BOOTSTRAP = new WeakSet<object>();
@@ -164,6 +165,27 @@ export function getH3App(nitroApp: any): H3AppShim {
164
165
  prepend: true,
165
166
  });
166
167
 
168
+ // CSRF (see csrf.ts): registered here — synchronously, on the very
169
+ // first `getH3App()` call for this nitroApp — rather than inside
170
+ // createCoreRoutesPlugin's own async init chain. Real deployments mount
171
+ // core-routes and agent-chat as SEPARATE, independently-async-initialized
172
+ // Nitro plugin files with no explicit ordering between them; both
173
+ // eventually call `getH3App(nitroApp).use(...)` to register their own
174
+ // routes (CSRF, action routes) after their own async setup (DB reads,
175
+ // dynamic imports) resolves in unpredictable relative order. The
176
+ // readiness gate above only guarantees every tracked plugin has FINISHED
177
+ // registering by the time a gated request is released — it does NOT
178
+ // guarantee CSRF's registration call happens to `.push()` onto
179
+ // `~middleware` before an action route's does. If agent-chat's action
180
+ // route push happened to land first, that route would match and run
181
+ // before CSRF ever saw the request. Registering CSRF here instead makes
182
+ // it the first non-prepended middleware pushed onto the array for this
183
+ // nitroApp, full stop — every plugin's own route registrations reach
184
+ // `getH3App()` (and therefore run after this point) before they can
185
+ // register anything, regardless of which plugin's async chain resolves
186
+ // first.
187
+ registerMiddleware(nitroApp, "", createCsrfMiddleware());
188
+
167
189
  // Primary gate: Nitro bridges this `request` hook to h3's `config.onRequest`,
168
190
  // which h3 awaits BEFORE `handler()` snapshots middleware and resolves the
169
191
  // route. The middleware gate above runs too late on production dispatchers —
@@ -466,7 +488,18 @@ function registerMiddleware(
466
488
  let originalPathname: string | undefined;
467
489
  let originalEventPath: string | undefined;
468
490
  let hadEventPath = false;
491
+ // Only true once this specific middleware invocation has actually
492
+ // stripped a mount prefix (i.e. `path` was non-empty and matched).
493
+ // Global (`path === ""`) middleware never mutates event.path/pathname,
494
+ // so `restoreOriginalPath` must be a no-op for it — otherwise it would
495
+ // unconditionally `delete event.path` on every pass-through (hadEventPath
496
+ // defaults to false), corrupting the event for any middleware that runs
497
+ // later in the chain (a real bug: two or more global middlewares in
498
+ // sequence, e.g. security-headers + CORS + CSRF, would wipe event.path
499
+ // for everything downstream, including the final route handler).
500
+ let didStripPath = false;
469
501
  const restoreOriginalPath = () => {
502
+ if (!didStripPath) return;
470
503
  if (originalPathname !== undefined) {
471
504
  try {
472
505
  event.url.pathname = originalPathname;
@@ -502,6 +535,7 @@ function registerMiddleware(
502
535
  const eventAny = event as any;
503
536
  hadEventPath = "path" in eventAny;
504
537
  originalEventPath = eventAny.path;
538
+ didStripPath = true;
505
539
  try {
506
540
  originalPathname = event.url.pathname;
507
541
  // Save the full path in context so handlers that need the original URL
@@ -3,7 +3,6 @@ import { readFile } from "node:fs/promises";
3
3
  import {
4
4
  defineEventHandler,
5
5
  getMethod,
6
- getRequestHeader,
7
6
  readBody,
8
7
  setResponseStatus,
9
8
  type H3Event,
@@ -15,6 +14,7 @@ import { readAppSecret } from "../secrets/storage.js";
15
14
  import { getSession } from "./auth.js";
16
15
  import { resolveBuilderCredentials } from "./credential-provider.js";
17
16
  import { runWithRequestContext } from "./request-context.js";
17
+ import { isSameOriginRequest } from "./request-origin.js";
18
18
 
19
19
  interface GoogleRealtimeSessionResponse {
20
20
  websocketUrl: string;
@@ -22,41 +22,6 @@ interface GoogleRealtimeSessionResponse {
22
22
  websocketProtocol?: string;
23
23
  }
24
24
 
25
- function isSameOriginRequest(event: H3Event): boolean {
26
- const host = getRequestHeader(event, "host");
27
- const origin = getRequestHeader(event, "origin");
28
- if (origin && host) {
29
- try {
30
- const parsed = new URL(origin);
31
- if (parsed.host === host) return true;
32
- if (parsed.protocol === "tauri:" && parsed.hostname === "localhost") {
33
- return true;
34
- }
35
- if (
36
- (parsed.protocol === "http:" || parsed.protocol === "https:") &&
37
- parsed.hostname === "tauri.localhost" &&
38
- (host.startsWith("localhost:") || host.startsWith("127.0.0.1:"))
39
- ) {
40
- return true;
41
- }
42
- if (
43
- parsed.protocol === "http:" &&
44
- (parsed.hostname === "localhost" || parsed.hostname === "127.0.0.1") &&
45
- parsed.port === "1420" &&
46
- (host.startsWith("localhost:") || host.startsWith("127.0.0.1:"))
47
- ) {
48
- return true;
49
- }
50
- return false;
51
- } catch {
52
- return false;
53
- }
54
- }
55
- const fetchSite = getRequestHeader(event, "sec-fetch-site");
56
- if (fetchSite) return fetchSite === "same-origin" || fetchSite === "none";
57
- return true;
58
- }
59
-
60
25
  export async function resolveGoogleRealtimeCredentials(opts: {
61
26
  userEmail?: string | null;
62
27
  orgId?: string | null;
@@ -738,9 +738,31 @@ async function getDurableChangesSinceForUser(
738
738
  }
739
739
 
740
740
  try {
741
+ // Scope the fetch to rows that could ever be visible to this caller
742
+ // before paying to JSON.parse and visibility-check every deployment-wide
743
+ // event: deployment-global rows (no owner, no org), the caller's own
744
+ // rows, the caller's org's rows, and resource-scoped rows (owner/org
745
+ // don't gate those — access is decided below by
746
+ // `getChangeVisibilityForUser`'s access-aware branch, which can grant a
747
+ // non-owner sharee, so resource-scoped rows must still flow through that
748
+ // check regardless of who owns them). This lets Postgres/SQLite use the
749
+ // `sync_events_owner_version_idx` / `sync_events_org_version_idx` indexes
750
+ // instead of scanning every tenant's activity on every poll. The OR group
751
+ // is parenthesized so `version > ?` ANDs against the whole group, not
752
+ // just the first term. A caller with no org passes a null `orgId` bind
753
+ // param, which makes `org_id = ?` evaluate to no match for every row
754
+ // (including null-org rows) in both dialects — mirroring the
755
+ // `event.orgId && orgId` truthy check in `getChangeVisibilityForUser`.
741
756
  const result = await getDbExec().execute({
742
- sql: `SELECT version, event_json FROM sync_events WHERE version > ? ORDER BY version ASC LIMIT ?`,
743
- args: [since, DURABLE_READ_LIMIT + 1],
757
+ sql: `SELECT version, event_json FROM sync_events WHERE version > ?
758
+ AND (
759
+ (owner IS NULL AND org_id IS NULL)
760
+ OR owner = ?
761
+ OR org_id = ?
762
+ OR resource_type IS NOT NULL
763
+ )
764
+ ORDER BY version ASC LIMIT ?`,
765
+ args: [since, userEmail, orgId ?? null, DURABLE_READ_LIMIT + 1],
744
766
  });
745
767
  const events: ChangeEvent[] = [];
746
768
  let version = Math.max(_version, since);
@@ -26,6 +26,7 @@ import {
26
26
  } from "./credential-provider.js";
27
27
  import { getH3App } from "./framework-request-handler.js";
28
28
  import { runWithRequestContext } from "./request-context.js";
29
+ import { isSameOriginRequest } from "./request-origin.js";
29
30
 
30
31
  export const REALTIME_VOICE_SESSION_PATH =
31
32
  "/_agent-native/realtime-voice/session";
@@ -301,6 +302,10 @@ function createSessionHandler(
301
302
  ) {
302
303
  return defineEventHandler(async (event: H3Event) => {
303
304
  if (getMethod(event) !== "POST") return invalidMethod(event);
305
+ if (!isSameOriginRequest(event)) {
306
+ setResponseStatus(event, 403);
307
+ return { error: "Cross-origin request rejected" };
308
+ }
304
309
  setResponseHeader(event, "Cache-Control", "no-store");
305
310
 
306
311
  const auth = await authenticateVoiceRequest(event, options);
@@ -529,6 +534,10 @@ function createToolHandler(
529
534
  ) {
530
535
  return defineEventHandler(async (event: H3Event) => {
531
536
  if (getMethod(event) !== "POST") return invalidMethod(event);
537
+ if (!isSameOriginRequest(event)) {
538
+ setResponseStatus(event, 403);
539
+ return { error: "Cross-origin request rejected" };
540
+ }
532
541
  setResponseHeader(event, "Cache-Control", "no-store");
533
542
 
534
543
  const auth = await authenticateVoiceRequest(event, options);
@@ -0,0 +1,63 @@
1
+ import { getRequestHeader, type H3Event } from "h3";
2
+
3
+ function isLoopbackHost(host: string): boolean {
4
+ return host.startsWith("localhost:") || host.startsWith("127.0.0.1:");
5
+ }
6
+
7
+ /**
8
+ * Reject cross-site POSTs. Cookies are `SameSite=None; Secure` over HTTPS so
9
+ * the browser would otherwise attach the session to a forged form submission
10
+ * from evil.com, causing us to spend provider credits on the user's behalf.
11
+ * Same-origin browsers always send `Origin` on POST; if it's missing we fall
12
+ * back to `Sec-Fetch-Site` so Safari's fetch-spec behavior still works.
13
+ */
14
+ export function isSameOriginRequest(event: H3Event): boolean {
15
+ const host = getRequestHeader(event, "host");
16
+ const origin = getRequestHeader(event, "origin");
17
+ if (origin && host) {
18
+ try {
19
+ const parsed = new URL(origin);
20
+ const forwardedProto = getRequestHeader(event, "x-forwarded-proto");
21
+ const forwardedProtocol =
22
+ forwardedProto === "https" || forwardedProto === "http"
23
+ ? `${forwardedProto}:`
24
+ : null;
25
+ const matchesScheme = forwardedProtocol
26
+ ? parsed.protocol === forwardedProtocol
27
+ : parsed.protocol === "https:" ||
28
+ (parsed.protocol === "http:" && isLoopbackHost(host));
29
+ if (parsed.host === host && matchesScheme) return true;
30
+ // Tauri desktop dev serves the tray WebView from localhost:1420 while
31
+ // the app server lives on the template dev port. Production Tauri
32
+ // WebViews can also send a tauri://localhost origin. Trust that custom
33
+ // scheme, while limiting the web-scheme desktop origins below to a
34
+ // loopback app server so arbitrary websites still fail the CSRF check.
35
+ if (parsed.protocol === "tauri:" && parsed.hostname === "localhost") {
36
+ return true;
37
+ }
38
+ if (
39
+ (parsed.protocol === "http:" || parsed.protocol === "https:") &&
40
+ parsed.hostname === "tauri.localhost" &&
41
+ isLoopbackHost(host)
42
+ ) {
43
+ return true;
44
+ }
45
+ if (
46
+ parsed.protocol === "http:" &&
47
+ (parsed.hostname === "localhost" || parsed.hostname === "127.0.0.1") &&
48
+ parsed.port === "1420" &&
49
+ isLoopbackHost(host)
50
+ ) {
51
+ return true;
52
+ }
53
+ return false;
54
+ } catch {
55
+ return false;
56
+ }
57
+ }
58
+ const fetchSite = getRequestHeader(event, "sec-fetch-site");
59
+ if (fetchSite) return fetchSite === "same-origin" || fetchSite === "none";
60
+ // No Origin and no Sec-Fetch-Site: likely a non-browser client (curl,
61
+ // server-side) — safe to allow, CSRF requires a browser with ambient cookies.
62
+ return true;
63
+ }
@@ -20,7 +20,6 @@
20
20
  import {
21
21
  defineEventHandler,
22
22
  getMethod,
23
- getRequestHeader,
24
23
  readMultipartFormData,
25
24
  setResponseStatus,
26
25
  type H3Event,
@@ -43,6 +42,7 @@ import {
43
42
  resolveSecret,
44
43
  } from "./credential-provider.js";
45
44
  import { runWithRequestContext } from "./request-context.js";
45
+ import { isSameOriginRequest } from "./request-origin.js";
46
46
 
47
47
  const WHISPER_URL = "https://api.openai.com/v1/audio/transcriptions";
48
48
  const GROQ_URL = "https://api.groq.com/openai/v1/audio/transcriptions";
@@ -75,55 +75,6 @@ const BUILDER_GEMINI_TRANSCRIPTION_MODEL = "gemini-3-1-flash-lite";
75
75
  const GEMINI_MODEL = "gemini-2.0-flash-lite";
76
76
  const GEMINI_URL = `https://generativelanguage.googleapis.com/v1beta/models/${GEMINI_MODEL}:generateContent`;
77
77
 
78
- /**
79
- * Reject cross-site POSTs. Cookies are `SameSite=None; Secure` over HTTPS so
80
- * the browser would otherwise attach the session to a forged form submission
81
- * from evil.com, causing us to spend OpenAI credits on the user's behalf.
82
- * Same-origin browsers always send `Origin` on POST; if it's missing we fall
83
- * back to `Sec-Fetch-Site` so Safari's fetch-spec behavior still works.
84
- */
85
- function isSameOriginRequest(event: H3Event): boolean {
86
- const host = getRequestHeader(event, "host");
87
- const origin = getRequestHeader(event, "origin");
88
- if (origin && host) {
89
- try {
90
- const parsed = new URL(origin);
91
- if (parsed.host === host) return true;
92
- // Tauri desktop dev serves the tray WebView from localhost:1420 while
93
- // the app server lives on the template dev port. Production Tauri
94
- // WebViews can also send a tauri://localhost origin. Treat only those
95
- // desktop origins as trusted cross-origin callers; arbitrary websites
96
- // still fail the CSRF check.
97
- if (parsed.protocol === "tauri:" && parsed.hostname === "localhost") {
98
- return true;
99
- }
100
- if (
101
- (parsed.protocol === "http:" || parsed.protocol === "https:") &&
102
- parsed.hostname === "tauri.localhost" &&
103
- (host.startsWith("localhost:") || host.startsWith("127.0.0.1:"))
104
- ) {
105
- return true;
106
- }
107
- if (
108
- parsed.protocol === "http:" &&
109
- (parsed.hostname === "localhost" || parsed.hostname === "127.0.0.1") &&
110
- parsed.port === "1420" &&
111
- (host.startsWith("localhost:") || host.startsWith("127.0.0.1:"))
112
- ) {
113
- return true;
114
- }
115
- return false;
116
- } catch {
117
- return false;
118
- }
119
- }
120
- const fetchSite = getRequestHeader(event, "sec-fetch-site");
121
- if (fetchSite) return fetchSite === "same-origin" || fetchSite === "none";
122
- // No Origin and no Sec-Fetch-Site: likely a non-browser client (curl,
123
- // server-side) — safe to allow, CSRF requires a browser with ambient cookies.
124
- return true;
125
- }
126
-
127
78
  /**
128
79
  * Derive an AbortSignal that fires when the client disconnects mid-request
129
80
  * (e.g. the desktop client's own 8s ceiling firing before a provider call's
@@ -7,6 +7,7 @@
7
7
  "build": "agent-native build",
8
8
  "start": "agent-native start",
9
9
  "typecheck": "agent-native typecheck",
10
+ "doctor": "agent-native doctor",
10
11
  "action": "agent-native action",
11
12
  "script": "agent-native script",
12
13
  "skills:update": "agent-native skills update scaffold --project",
@@ -43,8 +44,7 @@
43
44
  "tailwind-merge": "^3.5.0",
44
45
  "tailwindcss": "^4.1.18",
45
46
  "tsx": "^4.20.3",
46
- "typescript": "catalog:",
47
47
  "typescript-7": "catalog:",
48
- "vite": "^8.0.0"
48
+ "vite": "8.1.0"
49
49
  }
50
50
  }
@@ -19,7 +19,6 @@
19
19
  "@types/node": "^24.2.1",
20
20
  "oxfmt": "catalog:",
21
21
  "tsx": "^4.20.3",
22
- "typescript": "catalog:",
23
22
  "typescript-7": "catalog:"
24
23
  }
25
24
  }
@@ -77,6 +77,9 @@ SQL to the caller — they never leak another tenant's rows:
77
77
  (`agent` | `human` | `system`), `status`, `threadId`/`turnId`, `action`,
78
78
  `sinceMs`, `limit`.
79
79
  - `get-audit-event` — one event by id, with its redacted input payload.
80
+ - `export-audit-events` — bulk CSV/NDJSON export (same filters minus `limit`,
81
+ plus `format` and `maxRows`) for offline/compliance pulls; itself audited
82
+ via `onRead`.
80
83
 
81
84
  Call them from the UI with `useActionQuery` to build an activity feed or a
82
85
  "who changed this" line — never hand-write a fetch to the audit table.
@@ -61,7 +61,7 @@ Use the web-request tool with ${keys.SLACK_WEBHOOK}.
61
61
  | `triggerType` | `"schedule" \| "event"` | How the automation fires |
62
62
  | `event` | `string?` | Event name to subscribe to (event triggers) |
63
63
  | `condition` | `string?` | Natural-language condition evaluated before dispatch |
64
- | `mode` | `"agentic" \| "deterministic"` | Full agent loop vs. fixed action set |
64
+ | `mode` | `"agentic"` | Full agent loop (only supported mode; `"deterministic"` was removed never implemented, rejected at define time) |
65
65
  | `model` | `string?` | Override the model for this trigger's agent loop |
66
66
  | `domain` | `string?` | Grouping tag (mail, calendar, clips, etc.) |
67
67
  | `createdBy` | `string?` | Owner email |
@@ -32,7 +32,6 @@
32
32
  "prepare": "tsc"
33
33
  },
34
34
  "devDependencies": {
35
- "typescript": "catalog:",
36
35
  "typescript-7": "catalog:"
37
36
  }
38
37
  }
@@ -20,7 +20,6 @@
20
20
  "@types/node": "^24.2.1",
21
21
  "oxfmt": "catalog:",
22
22
  "tsx": "catalog:",
23
- "typescript": "catalog:",
24
23
  "typescript-7": "catalog:"
25
24
  },
26
25
  "packageManager": "pnpm@10.14.0",
@@ -107,6 +107,14 @@ async function handleDefine(
107
107
  return `Error: An automation named "${name}" already exists. Use a different name or delete the existing one first.`;
108
108
  }
109
109
 
110
+ if (args.mode === "deterministic") {
111
+ return (
112
+ "Error: Deterministic mode was removed — it was never implemented and " +
113
+ "automations that set it never fired. Create the automation without " +
114
+ "mode (agentic), and describe the exact fixed steps in the automation body."
115
+ );
116
+ }
117
+
110
118
  const triggerType = args.trigger_type === "schedule" ? "schedule" : "event";
111
119
  const meta: TriggerFrontmatter = {
112
120
  schedule: args.schedule || "",
@@ -114,7 +122,7 @@ async function handleDefine(
114
122
  triggerType,
115
123
  event: args.event || undefined,
116
124
  condition: args.condition || undefined,
117
- mode: args.mode === "deterministic" ? "deterministic" : "agentic",
125
+ mode: "agentic",
118
126
  domain: args.domain || undefined,
119
127
  createdBy: owner,
120
128
  runAs: "creator",
@@ -268,8 +276,8 @@ export function createAutomationToolEntries(
268
276
  mode: {
269
277
  type: "string",
270
278
  description:
271
- '"agentic" (full agent loop, can use tools) or "deterministic" (fixed actions only). Used by define.',
272
- enum: ["agentic", "deterministic"],
279
+ '"agentic" (full agent loop, can use tools) the only supported mode. Used by define.',
280
+ enum: ["agentic"],
273
281
  },
274
282
  domain: {
275
283
  type: "string",
@@ -15,7 +15,13 @@ export interface TriggerFrontmatter {
15
15
  event?: string;
16
16
  /** Natural-language condition evaluated by Haiku before dispatch. */
17
17
  condition?: string;
18
- /** "agentic" = full runAgentLoop. "deterministic" = fixed action set. */
18
+ /**
19
+ * "agentic" = full runAgentLoop; the only mode `manage-automations` will
20
+ * define/update going forward. "deterministic" was removed from the
21
+ * advertised surface (never implemented) and is legacy-only: rows created
22
+ * before the removal may still carry it, and the dispatcher's
23
+ * warn-and-skip branch keeps them inert by design — do not make them fire.
24
+ */
19
25
  mode: "agentic" | "deterministic";
20
26
  /** Domain tag for filtering in per-template UIs. */
21
27
  domain?: string;