@agent-native/core 0.141.7 → 0.144.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 (328) hide show
  1. package/agent-native.eject.json +9 -0
  2. package/corpus/README.md +1 -1
  3. package/corpus/templates/analytics/.agents/skills/provider-api/SKILL.md +19 -0
  4. package/corpus/templates/analytics/.agents/skills/turn-into-app/SKILL.md +296 -0
  5. package/corpus/templates/analytics/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  6. package/corpus/templates/analytics/.agents/skills/turn-into-skill/SKILL.md +112 -0
  7. package/corpus/templates/analytics/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  8. package/corpus/templates/analytics/AGENTS.md +35 -38
  9. package/corpus/templates/analytics/actions/ensure-native-v2-dashboards.ts +1 -1
  10. package/corpus/templates/analytics/actions/list-dashboard-usage-stats.ts +17 -22
  11. package/corpus/templates/analytics/actions/navigate.ts +4 -5
  12. package/corpus/templates/analytics/actions/provider-api-register.ts +50 -0
  13. package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +44 -11
  14. package/corpus/templates/analytics/actions/test-custom-api-connection.ts +106 -0
  15. package/corpus/templates/analytics/app/components/CustomApiCard.tsx +430 -0
  16. package/corpus/templates/analytics/app/i18n-data.ts +680 -0
  17. package/corpus/templates/analytics/app/lib/native-mcp-exclusions.ts +6 -0
  18. package/corpus/templates/analytics/app/lib/sql-query.ts +33 -6
  19. package/corpus/templates/analytics/app/pages/DataSources.tsx +4 -0
  20. package/corpus/templates/analytics/changelog/2026-08-06-analytics-dashboards-load-reliably-during-background-data-sw.md +6 -0
  21. package/corpus/templates/analytics/changelog/2026-08-06-analytics-dashboards-remain-responsive-while-historical-data.md +6 -0
  22. package/corpus/templates/analytics/changelog/2026-08-06-analytics-query-results-now-render-as-a-table-with-csv-downl.md +6 -0
  23. package/corpus/templates/analytics/changelog/2026-08-06-connect-public-https-custom-apis-and-hand-tested-endpoints-t.md +6 -0
  24. package/corpus/templates/analytics/changelog/2026-08-06-durable-agent-worker-memory.md +6 -0
  25. package/corpus/templates/analytics/changelog/2026-08-06-live-dashboard-panels-use-the-shared-query-timeout.md +6 -0
  26. package/corpus/templates/analytics/changelog/2026-08-06-on-demand-billing-is-available-as-a-native-dashboard-with-ta.md +6 -0
  27. package/corpus/templates/analytics/changelog/2026-08-06-visible-dashboard-names-are-unique.md +6 -0
  28. package/corpus/templates/analytics/netlify.toml +7 -0
  29. package/corpus/templates/analytics/scripts/emit-netlify-dashboard-report-cron.ts +4 -0
  30. package/corpus/templates/analytics/server/db/index.ts +27 -0
  31. package/corpus/templates/analytics/server/db/schema.ts +10 -0
  32. package/corpus/templates/analytics/server/lib/dashboards-store.ts +227 -60
  33. package/corpus/templates/analytics/server/lib/first-party-analytics-backend.ts +133 -44
  34. package/corpus/templates/analytics/server/lib/native-v2-dashboards.ts +227 -1
  35. package/corpus/templates/analytics/server/plugins/agent-chat.ts +5 -0
  36. package/corpus/templates/analytics/server/plugins/analytics-rollup-backfill-jobs.ts +1 -0
  37. package/corpus/templates/analytics/server/plugins/db.ts +52 -18
  38. package/corpus/templates/assets/.agents/skills/asset-generation/SKILL.md +28 -2
  39. package/corpus/templates/assets/.agents/skills/image-generation/SKILL.md +16 -1
  40. package/corpus/templates/assets/.agents/skills/turn-into-app/SKILL.md +296 -0
  41. package/corpus/templates/assets/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  42. package/corpus/templates/assets/.agents/skills/turn-into-skill/SKILL.md +112 -0
  43. package/corpus/templates/assets/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  44. package/corpus/templates/brain/.agents/skills/turn-into-app/SKILL.md +296 -0
  45. package/corpus/templates/brain/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  46. package/corpus/templates/brain/.agents/skills/turn-into-skill/SKILL.md +112 -0
  47. package/corpus/templates/brain/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  48. package/corpus/templates/brain/actions/list-connection-providers.ts +24 -3
  49. package/corpus/templates/brain/app/lib/dispatch-links.ts +44 -0
  50. package/corpus/templates/brain/app/routes/sources.tsx +15 -7
  51. package/corpus/templates/brain/changelog/2026-08-06-brain-provider-setup-links-open-dispatch-correctly-in-standa.md +6 -0
  52. package/corpus/templates/brain/server/plugins/agent-chat.ts +1 -0
  53. package/corpus/templates/calendar/.agents/skills/event-management/SKILL.md +26 -0
  54. package/corpus/templates/calendar/.agents/skills/turn-into-app/SKILL.md +296 -0
  55. package/corpus/templates/calendar/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  56. package/corpus/templates/calendar/.agents/skills/turn-into-skill/SKILL.md +112 -0
  57. package/corpus/templates/calendar/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  58. package/corpus/templates/calendar/AGENTS.md +11 -32
  59. package/corpus/templates/calendar/actions/update-event.ts +107 -1
  60. package/corpus/templates/calendar/app/components/calendar/EventCalendarSelect.tsx +83 -0
  61. package/corpus/templates/calendar/app/components/calendar/EventDetailPanel.tsx +57 -0
  62. package/corpus/templates/calendar/app/components/calendar/EventDetailPopover.tsx +59 -73
  63. package/corpus/templates/calendar/app/hooks/use-events.ts +4 -1
  64. package/corpus/templates/calendar/app/i18n-data.ts +20 -0
  65. package/corpus/templates/calendar/changelog/2026-08-06-delegated-requests-continue-in-the-background.md +6 -0
  66. package/corpus/templates/calendar/changelog/2026-08-06-existing-events-can-move-between-connected-google-account-ca.md +6 -0
  67. package/corpus/templates/calendar/server/lib/google-calendar.ts +101 -0
  68. package/corpus/templates/calendar/server/plugins/agent-chat.ts +7 -1
  69. package/corpus/templates/chat/.agents/skills/turn-into-app/SKILL.md +296 -0
  70. package/corpus/templates/chat/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  71. package/corpus/templates/chat/.agents/skills/turn-into-skill/SKILL.md +112 -0
  72. package/corpus/templates/chat/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  73. package/corpus/templates/clips/.agents/skills/turn-into-app/SKILL.md +296 -0
  74. package/corpus/templates/clips/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  75. package/corpus/templates/clips/.agents/skills/turn-into-skill/SKILL.md +112 -0
  76. package/corpus/templates/clips/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  77. package/corpus/templates/clips/app/components/editor/editor-layout.tsx +9 -24
  78. package/corpus/templates/clips/app/components/editor/timeline-geometry.ts +15 -0
  79. package/corpus/templates/clips/app/components/editor/waveform.tsx +4 -17
  80. package/corpus/templates/clips/app/components/player/delete-recording-menu.tsx +14 -3
  81. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +28 -38
  82. package/corpus/templates/clips/app/routes/share.$shareId.tsx +21 -27
  83. package/corpus/templates/clips/changelog/2026-08-06-clips-recovers-from-stalled-recording-setup-without-requirin.md +6 -0
  84. package/corpus/templates/clips/changelog/2026-08-06-clips-starts-faster-after-a-deploy-or-idle-period-startup-no.md +6 -0
  85. package/corpus/templates/clips/changelog/2026-08-06-deleting-a-recording-returns-cleanly-to-the-library-and-fit-.md +6 -0
  86. package/corpus/templates/clips/changelog/2026-08-06-hide-clip-insights-from-viewers-without-analytics-access.md +6 -0
  87. package/corpus/templates/clips/desktop/src/app.tsx +48 -20
  88. package/corpus/templates/clips/desktop/src/lib/recorder.ts +275 -74
  89. package/corpus/templates/clips/desktop/src/lib/recording-start-guard.ts +84 -0
  90. package/corpus/templates/clips/desktop/src/overlays/toolbar.tsx +14 -4
  91. package/corpus/templates/clips/server/plugins/db.ts +214 -26
  92. package/corpus/templates/content/.agents/skills/turn-into-app/SKILL.md +296 -0
  93. package/corpus/templates/content/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  94. package/corpus/templates/content/.agents/skills/turn-into-skill/SKILL.md +112 -0
  95. package/corpus/templates/content/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  96. package/corpus/templates/crm/.agents/skills/turn-into-app/SKILL.md +296 -0
  97. package/corpus/templates/crm/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  98. package/corpus/templates/crm/.agents/skills/turn-into-skill/SKILL.md +112 -0
  99. package/corpus/templates/crm/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  100. package/corpus/templates/crm/changelog/2026-08-06-crm-starts-faster-after-a-deploy-or-idle-period-one-time-dat.md +6 -0
  101. package/corpus/templates/crm/server/plugins/db.ts +11 -8
  102. package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +36 -1
  103. package/corpus/templates/design/.agents/skills/turn-into-app/SKILL.md +296 -0
  104. package/corpus/templates/design/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  105. package/corpus/templates/design/.agents/skills/turn-into-skill/SKILL.md +112 -0
  106. package/corpus/templates/design/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  107. package/corpus/templates/design/actions/import-from-url.ts +1 -1
  108. package/corpus/templates/design/app/components/design/LayersPanel.tsx +27 -18
  109. package/corpus/templates/design/app/pages/Index.tsx +6 -2
  110. package/corpus/templates/design/changelog/2026-08-05-deleting-a-design-from-the-home-page-no-longer-leaves-the-ap.md +6 -0
  111. package/corpus/templates/design/changelog/2026-08-05-renaming-a-layer-now-focuses-its-name-field-automatically.md +6 -0
  112. package/corpus/templates/design/server/plugins/agent-chat.ts +2 -0
  113. package/corpus/templates/dispatch/.agents/skills/turn-into-app/SKILL.md +296 -0
  114. package/corpus/templates/dispatch/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  115. package/corpus/templates/dispatch/.agents/skills/turn-into-skill/SKILL.md +112 -0
  116. package/corpus/templates/dispatch/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  117. package/corpus/templates/dispatch/changelog/2026-08-06-ready-workspace-apps-stay-one-click-away-in-a-compact-dispat.md +6 -0
  118. package/corpus/templates/dispatch/changelog/2026-08-06-shared-vault-values-and-management-are-now-restricted-to-wor.md +6 -0
  119. package/corpus/templates/factory/.agents/skills/turn-into-app/SKILL.md +296 -0
  120. package/corpus/templates/factory/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  121. package/corpus/templates/factory/.agents/skills/turn-into-skill/SKILL.md +112 -0
  122. package/corpus/templates/factory/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  123. package/corpus/templates/forms/.agents/skills/turn-into-app/SKILL.md +296 -0
  124. package/corpus/templates/forms/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  125. package/corpus/templates/forms/.agents/skills/turn-into-skill/SKILL.md +112 -0
  126. package/corpus/templates/forms/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  127. package/corpus/templates/forms/changelog/2026-08-06-delegated-requests-continue-in-the-background.md +6 -0
  128. package/corpus/templates/forms/server/plugins/agent-chat.ts +4 -0
  129. package/corpus/templates/macros/.agents/skills/turn-into-app/SKILL.md +296 -0
  130. package/corpus/templates/macros/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  131. package/corpus/templates/macros/.agents/skills/turn-into-skill/SKILL.md +112 -0
  132. package/corpus/templates/macros/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  133. package/corpus/templates/mail/.agents/skills/turn-into-app/SKILL.md +296 -0
  134. package/corpus/templates/mail/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  135. package/corpus/templates/mail/.agents/skills/turn-into-skill/SKILL.md +112 -0
  136. package/corpus/templates/mail/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  137. package/corpus/templates/mail/changelog/2026-08-06-delegated-requests-continue-in-the-background.md +6 -0
  138. package/corpus/templates/mail/server/plugins/agent-chat.ts +6 -0
  139. package/corpus/templates/plan/.agents/skills/turn-into-app/SKILL.md +296 -0
  140. package/corpus/templates/plan/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  141. package/corpus/templates/plan/.agents/skills/turn-into-skill/SKILL.md +112 -0
  142. package/corpus/templates/plan/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  143. package/corpus/templates/slides/.agents/skills/create-deck/SKILL.md +48 -5
  144. package/corpus/templates/slides/.agents/skills/design-systems/SKILL.md +37 -1
  145. package/corpus/templates/slides/.agents/skills/image-generation-via-a2a/SKILL.md +6 -0
  146. package/corpus/templates/slides/.agents/skills/slide-editing/SKILL.md +15 -2
  147. package/corpus/templates/slides/.agents/skills/slide-images/SKILL.md +29 -24
  148. package/corpus/templates/slides/.agents/skills/turn-into-app/SKILL.md +296 -0
  149. package/corpus/templates/slides/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  150. package/corpus/templates/slides/.agents/skills/turn-into-skill/SKILL.md +112 -0
  151. package/corpus/templates/slides/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  152. package/corpus/templates/slides/AGENTS.md +7 -9
  153. package/corpus/templates/slides/_gitignore +1 -0
  154. package/corpus/templates/slides/actions/export-pptx.ts +402 -36
  155. package/corpus/templates/slides/actions/import-file.ts +46 -85
  156. package/corpus/templates/slides/actions/import-google-slides-reference.ts +271 -12
  157. package/corpus/templates/slides/actions/import-pptx.ts +85 -60
  158. package/corpus/templates/slides/app/components/deck/DeckCard.tsx +10 -13
  159. package/corpus/templates/slides/app/components/editor/AddSlidePopover.tsx +5 -1
  160. package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +25 -12
  161. package/corpus/templates/slides/app/components/editor/ExportMenu.tsx +112 -57
  162. package/corpus/templates/slides/app/components/editor/GoogleDriveConnectionCta.tsx +202 -0
  163. package/corpus/templates/slides/app/components/editor/GoogleSlidesReferenceImport.tsx +26 -14
  164. package/corpus/templates/slides/app/components/editor/PromptDialog.tsx +173 -0
  165. package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +182 -141
  166. package/corpus/templates/slides/app/components/editor/canvas-interactions/index.ts +1 -0
  167. package/corpus/templates/slides/app/components/editor/canvas-interactions/slides-canvas-adapter.ts +18 -0
  168. package/corpus/templates/slides/app/components/editor/slide-text-targets.ts +85 -0
  169. package/corpus/templates/slides/app/components/layout/Layout.tsx +3 -0
  170. package/corpus/templates/slides/app/components/onboarding/FirstDeckOnboardingFlow.tsx +4 -0
  171. package/corpus/templates/slides/app/components/presentation/PresentationView.tsx +27 -1
  172. package/corpus/templates/slides/app/i18n/en-US.ts +1 -0
  173. package/corpus/templates/slides/app/lib/create-deck-generation.ts +1 -1
  174. package/corpus/templates/slides/app/lib/deck-preview-frame.ts +15 -0
  175. package/corpus/templates/slides/app/lib/deck-share-links.ts +9 -0
  176. package/corpus/templates/slides/app/lib/export-pptx-client.ts +89 -0
  177. package/corpus/templates/slides/app/lib/slide-animation-elements.ts +3 -0
  178. package/corpus/templates/slides/app/pages/Index.tsx +91 -1
  179. package/corpus/templates/slides/changelog/2026-08-06-clicking-the-gray-canvas-around-a-slide-clears-its-selection.md +6 -0
  180. package/corpus/templates/slides/changelog/2026-08-06-deck-thumbnails-keep-a-consistent-listing-frame-across-aspec.md +6 -0
  181. package/corpus/templates/slides/changelog/2026-08-06-deep-linked-decks-open-directly-instead-of-being-interrupted.md +6 -0
  182. package/corpus/templates/slides/changelog/2026-08-06-google-slides-exports-now-show-clear-import-steps-when-direc.md +6 -0
  183. package/corpus/templates/slides/changelog/2026-08-06-import-pdf-google-slides-and-powerpoint-decks-directly-from-.md +6 -0
  184. package/corpus/templates/slides/changelog/2026-08-06-imported-powerpoint-exports-keep-text-and-images-editable-an.md +6 -0
  185. package/corpus/templates/slides/changelog/2026-08-06-presentation-prompts-continue-adding-rendered-slides-until-t.md +6 -0
  186. package/corpus/templates/slides/changelog/2026-08-06-public-decks-now-share-read-only-presentation-links-by-defau.md +6 -0
  187. package/corpus/templates/slides/changelog/2026-08-06-slides-offers-a-direct-connect-google-button-when-a-drive-co.md +6 -0
  188. package/corpus/templates/slides/changelog/2026-08-06-slides-preserve-uploaded-pdf-layouts-accept-larger-reference.md +6 -0
  189. package/corpus/templates/slides/changelog/2026-08-06-styled-words-stay-part-of-their-text-box-instead-of-becoming.md +6 -0
  190. package/corpus/templates/slides/server/handlers/google-docs-auth.ts +7 -20
  191. package/corpus/templates/slides/server/handlers/import/html-converter.ts +236 -13
  192. package/corpus/templates/slides/server/handlers/import/pptx-assets.ts +67 -0
  193. package/corpus/templates/slides/server/handlers/import/pptx-parser.ts +2 -0
  194. package/corpus/templates/slides/server/handlers/uploads.ts +7 -3
  195. package/corpus/templates/slides/server/lib/chat-attachments.ts +6 -3
  196. package/corpus/templates/slides/server/lib/emails.ts +7 -2
  197. package/corpus/templates/slides/server/lib/google-docs-error.ts +50 -0
  198. package/corpus/templates/slides/server/lib/google-docs-oauth.ts +1 -0
  199. package/corpus/templates/slides/server/lib/import-asset-storage.ts +127 -0
  200. package/corpus/templates/slides/server/plugins/agent-chat.ts +4 -3
  201. package/corpus/templates/slides/server/routes/api/import-assets/[token].get.ts +70 -0
  202. package/corpus/templates/slides/shared/upload-types.ts +3 -0
  203. package/corpus/templates/tasks/.agents/skills/turn-into-app/SKILL.md +296 -0
  204. package/corpus/templates/tasks/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  205. package/corpus/templates/tasks/.agents/skills/turn-into-skill/SKILL.md +112 -0
  206. package/corpus/templates/tasks/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  207. package/dist/agent/production-agent.d.ts +17 -0
  208. package/dist/agent/production-agent.js +72 -1
  209. package/dist/cli/agent-plugin.d.ts +112 -0
  210. package/dist/cli/agent-plugin.js +1081 -0
  211. package/dist/cli/app-skill.js +39 -1
  212. package/dist/cli/code-agent-executor.d.ts +3 -0
  213. package/dist/cli/code-agent-executor.js +51 -13
  214. package/dist/cli/index.js +13 -0
  215. package/dist/cli/templates-meta.js +1 -1
  216. package/dist/client/AgentPanel.d.ts +3 -1
  217. package/dist/client/AgentPanel.js +9 -2
  218. package/dist/client/AssistantChat.d.ts +8 -0
  219. package/dist/client/AssistantChat.js +23 -8
  220. package/dist/client/NewWorkspaceAppFlow.js +1 -0
  221. package/dist/client/agent-chat-adapter.js +123 -4
  222. package/dist/client/assistant-ui-recovery.d.ts +2 -1
  223. package/dist/client/assistant-ui-recovery.js +7 -3
  224. package/dist/client/onboarding/FirstRunOnboarding.js +11 -4
  225. package/dist/client/org/TeamPage.js +1 -1
  226. package/dist/client/require-session.js +1 -1
  227. package/dist/client/resources/McpConnectionSuggestion.d.ts +1 -0
  228. package/dist/client/resources/McpConnectionSuggestion.js +27 -10
  229. package/dist/client/resources/McpIntegrationDialog.js +77 -45
  230. package/dist/client/resources/mcp-integration-catalog.d.ts +13 -1
  231. package/dist/client/resources/mcp-integration-catalog.js +255 -2
  232. package/dist/client/resources/mcp-integration-logos.js +18 -2
  233. package/dist/client/settings/AccountSettingsCard.js +2 -1
  234. package/dist/collab/routes.d.ts +1 -1
  235. package/dist/collab/struct-routes.d.ts +1 -1
  236. package/dist/db/client.d.ts +9 -0
  237. package/dist/db/client.js +51 -16
  238. package/dist/db/create-get-db.js +2 -2
  239. package/dist/db/ddl-guard.d.ts +11 -10
  240. package/dist/db/ddl-guard.js +40 -12
  241. package/dist/deploy/build.d.ts +2 -0
  242. package/dist/deploy/build.js +97 -4
  243. package/dist/deploy/workspace-deploy.js +0 -2
  244. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  245. package/dist/guards/no-env-credentials.js +9 -0
  246. package/dist/ingestion/index.d.ts +1 -1
  247. package/dist/ingestion/pptx.d.ts +68 -0
  248. package/dist/ingestion/pptx.js +660 -213
  249. package/dist/integrations/plugin.js +9 -6
  250. package/dist/localization/default-messages.d.ts +54 -0
  251. package/dist/localization/default-messages.js +57 -2
  252. package/dist/mcp/screen-memory-stdio.d.ts +7 -7
  253. package/dist/mcp-client/oauth-routes.d.ts +2 -0
  254. package/dist/mcp-client/oauth-routes.js +73 -6
  255. package/dist/notifications/routes.d.ts +1 -1
  256. package/dist/observability/routes.d.ts +3 -3
  257. package/dist/onboarding/app-profile.js +11 -0
  258. package/dist/resources/handlers.d.ts +1 -1
  259. package/dist/resources/store.js +15 -1
  260. package/dist/scripts/call-agent.js +34 -4
  261. package/dist/secrets/routes.d.ts +9 -9
  262. package/dist/server/agent-chat/action-filters-a2a.d.ts +1 -1
  263. package/dist/server/agent-chat/action-filters-a2a.js +36 -1
  264. package/dist/server/agent-chat-plugin.js +29 -8
  265. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  266. package/dist/server/auth.js +47 -11
  267. package/dist/server/better-auth-instance.js +5 -3
  268. package/dist/server/core-routes-plugin.d.ts +8 -1
  269. package/dist/server/core-routes-plugin.js +28 -3
  270. package/dist/server/credential-provider.d.ts +3 -3
  271. package/dist/server/credential-provider.js +90 -4
  272. package/dist/server/onboarding-html.d.ts +2 -0
  273. package/dist/server/onboarding-html.js +115 -29
  274. package/dist/server/self-dispatch.d.ts +5 -4
  275. package/dist/server/self-dispatch.js +25 -14
  276. package/dist/server/ssr-handler.d.ts +1 -1
  277. package/dist/server/ssr-handler.js +1 -1
  278. package/dist/server/transcribe-voice.d.ts +1 -1
  279. package/dist/shared/cache-control.d.ts +26 -2
  280. package/dist/shared/cache-control.js +43 -2
  281. package/dist/shared/password-policy.d.ts +3 -0
  282. package/dist/shared/password-policy.js +3 -0
  283. package/dist/sharing/actions/set-resource-visibility.js +16 -4
  284. package/dist/sharing/registry.d.ts +14 -0
  285. package/dist/styles/agent-native.css +6 -0
  286. package/dist/templates/chat/.agents/skills/turn-into-app/SKILL.md +296 -0
  287. package/dist/templates/chat/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  288. package/dist/templates/chat/.agents/skills/turn-into-skill/SKILL.md +112 -0
  289. package/dist/templates/chat/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  290. package/dist/templates/default/.agents/skills/turn-into-app/SKILL.md +296 -0
  291. package/dist/templates/default/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  292. package/dist/templates/default/.agents/skills/turn-into-skill/SKILL.md +112 -0
  293. package/dist/templates/default/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  294. package/dist/templates/headless/.agents/skills/turn-into-app/SKILL.md +296 -0
  295. package/dist/templates/headless/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  296. package/dist/templates/headless/.agents/skills/turn-into-skill/SKILL.md +112 -0
  297. package/dist/templates/headless/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  298. package/dist/templates/workspace-core/.agents/skills/adding-workspace-apps/SKILL.md +6 -0
  299. package/dist/templates/workspace-core/.agents/skills/performance/SKILL.md +51 -0
  300. package/dist/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +296 -0
  301. package/dist/templates/workspace-core/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  302. package/dist/templates/workspace-core/.agents/skills/turn-into-skill/SKILL.md +112 -0
  303. package/dist/templates/workspace-core/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  304. package/dist/templates/workspace-root/AGENTS.md +7 -0
  305. package/dist/user-profile/actions/change-password.js +8 -3
  306. package/dist/user-profile/actions/set-password.js +5 -1
  307. package/dist/vite/action-types-plugin.js +59 -0
  308. package/docs/content/skills-guide.mdx +13 -0
  309. package/package.json +6 -2
  310. package/src/templates/chat/.agents/skills/turn-into-app/SKILL.md +296 -0
  311. package/src/templates/chat/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  312. package/src/templates/chat/.agents/skills/turn-into-skill/SKILL.md +112 -0
  313. package/src/templates/chat/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  314. package/src/templates/default/.agents/skills/turn-into-app/SKILL.md +296 -0
  315. package/src/templates/default/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  316. package/src/templates/default/.agents/skills/turn-into-skill/SKILL.md +112 -0
  317. package/src/templates/default/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  318. package/src/templates/headless/.agents/skills/turn-into-app/SKILL.md +296 -0
  319. package/src/templates/headless/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  320. package/src/templates/headless/.agents/skills/turn-into-skill/SKILL.md +112 -0
  321. package/src/templates/headless/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  322. package/src/templates/workspace-core/.agents/skills/adding-workspace-apps/SKILL.md +6 -0
  323. package/src/templates/workspace-core/.agents/skills/performance/SKILL.md +51 -0
  324. package/src/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +296 -0
  325. package/src/templates/workspace-core/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  326. package/src/templates/workspace-core/.agents/skills/turn-into-skill/SKILL.md +112 -0
  327. package/src/templates/workspace-core/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  328. package/src/templates/workspace-root/AGENTS.md +7 -0
@@ -90,6 +90,23 @@ function terminalTaskError(value) {
90
90
  : {}),
91
91
  };
92
92
  }
93
+ /**
94
+ * A delegated failure must be an error at the caller's tool boundary. Returning
95
+ * an `Error: ...` string makes the production agent treat the failed call as a
96
+ * successful tool result, so it can spend the rest of its turn retrying or
97
+ * changing arguments while the real failure remains invisible to the loop
98
+ * breaker.
99
+ */
100
+ class A2AInvocationError extends Error {
101
+ taskId;
102
+ errorCode;
103
+ constructor(message, options = {}) {
104
+ super(message);
105
+ this.name = "A2AInvocationError";
106
+ this.taskId = options.taskId;
107
+ this.errorCode = options.errorCode;
108
+ }
109
+ }
93
110
  function buildMessageIdempotencyKey(originatingTurnId, target, exactMessage) {
94
111
  if (!originatingTurnId)
95
112
  return undefined;
@@ -698,6 +715,12 @@ export async function run(args, context, selfAppId) {
698
715
  ? { terminalCode: invocationTerminalCode }
699
716
  : {}),
700
717
  });
718
+ if (terminalStatus === "error") {
719
+ throw new A2AInvocationError(responseText || `Error: The ${agent.name} agent returned no result.`, {
720
+ taskId: invocationTaskId,
721
+ errorCode: invocationTerminalCode,
722
+ });
723
+ }
701
724
  return (responseText || `Error: The ${agent.name} agent returned no result.`);
702
725
  }
703
726
  // No context — use the async + poll call so we don't get cut off at the
@@ -745,6 +768,8 @@ export async function run(args, context, selfAppId) {
745
768
  return expanded;
746
769
  }
747
770
  catch (err) {
771
+ if (err instanceof A2AInvocationError)
772
+ throw err;
748
773
  const msg = err?.message ?? String(err);
749
774
  const credentialMessage = formatDownstreamLlmCredentialFailure(agent.name, err);
750
775
  if (credentialMessage)
@@ -760,10 +785,13 @@ export async function run(args, context, selfAppId) {
760
785
  invocationStatus = "error";
761
786
  invocationTaskId = terminal.taskId;
762
787
  invocationTerminalCode = terminal.errorCode ?? terminal.state;
763
- return (`Error calling ${agent.name}: remote task ${terminal.state}` +
788
+ throw new A2AInvocationError(`Error calling ${agent.name}: remote task ${terminal.state}` +
764
789
  (terminal.errorCode ? ` (${terminal.errorCode})` : "") +
765
790
  (terminal.taskId ? ` [taskId: ${terminal.taskId}]` : "") +
766
- (terminal.responseText ? `: ${terminal.responseText}` : ""));
791
+ (terminal.responseText ? `: ${terminal.responseText}` : ""), {
792
+ taskId: terminal.taskId,
793
+ errorCode: terminal.errorCode ?? terminal.state,
794
+ });
767
795
  }
768
796
  const timeoutTaskId = getA2ATaskTimeoutTaskId(err);
769
797
  if (timeoutTaskId) {
@@ -777,11 +805,13 @@ export async function run(args, context, selfAppId) {
777
805
  if (/timeout|did not complete|Inactivity|504/i.test(msg)) {
778
806
  invocationStatus = "error";
779
807
  invocationTerminalCode = "timeout_without_task";
780
- return `Error calling ${agent.name}: the remote request timed out before a task id could be recovered.`;
808
+ throw new A2AInvocationError(`Error calling ${agent.name}: the remote request timed out before a task id could be recovered.`, { errorCode: "timeout_without_task" });
781
809
  }
782
810
  invocationStatus = "error";
783
811
  invocationTerminalCode = "call_failed";
784
- return `Error calling ${agent.name}: ${msg}`;
812
+ throw new A2AInvocationError(`Error calling ${agent.name}: ${msg}`, {
813
+ errorCode: "call_failed",
814
+ });
785
815
  }
786
816
  finally {
787
817
  trackA2AInvocation({
@@ -34,37 +34,37 @@ export declare function createListSecretsHandler(): import("h3").EventHandlerWit
34
34
  /** POST /_agent-native/secrets/:key — write a secret. */
35
35
  export declare function createWriteSecretHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
36
36
  error: string;
37
- status?: undefined;
38
37
  ok?: undefined;
38
+ status?: undefined;
39
39
  } | {
40
+ error?: undefined;
40
41
  ok: boolean;
41
42
  status: string;
42
- error?: undefined;
43
43
  } | {
44
+ ok?: undefined;
44
45
  error: string;
45
46
  removed?: undefined;
46
- ok?: undefined;
47
47
  } | {
48
+ error?: undefined;
48
49
  ok: boolean;
49
50
  removed: boolean;
50
- error?: undefined;
51
51
  }>>;
52
52
  /**
53
53
  * POST /_agent-native/secrets/:key/test — validate an optional candidate value
54
54
  * or the current stored value without changing anything.
55
55
  */
56
56
  export declare function createTestSecretHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
57
+ ok?: undefined;
57
58
  error: string;
58
59
  note?: undefined;
59
- ok?: undefined;
60
60
  } | {
61
+ error?: undefined;
61
62
  ok: boolean;
62
63
  note?: undefined;
63
- error?: undefined;
64
64
  } | {
65
+ error?: undefined;
65
66
  ok: boolean;
66
67
  note: string;
67
- error?: undefined;
68
68
  } | {
69
69
  note?: undefined;
70
70
  ok: boolean;
@@ -95,11 +95,11 @@ export interface AdHocSecretPayload {
95
95
  export declare function createAdHocSecretHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<AdHocSecretPayload[] | {
96
96
  error: string;
97
97
  } | {
98
+ error?: undefined;
98
99
  ok: boolean;
99
100
  key: string;
100
- error?: undefined;
101
101
  } | {
102
+ error?: undefined;
102
103
  ok: boolean;
103
104
  removed: boolean;
104
- error?: undefined;
105
105
  }>>;
@@ -75,7 +75,7 @@ type A2AAgentLoopRunner = typeof runAgentLoopDirectWithSoftTimeout;
75
75
  export declare const DEFAULT_DELEGATED_MAX_ITERATIONS = 80;
76
76
  export declare const DEFAULT_DELEGATED_MAX_RUN_INPUT_TOKENS = 750000;
77
77
  export declare const DEFAULT_DELEGATED_MAX_TOOL_RESULT_CHARS = 20000;
78
- export declare const DELEGATED_AGENT_EXECUTION_CONTRACT = "\n<delegated-agent-contract>\nThis request was delegated by another app. You are the specialist owner of the work.\n- Interpret the caller's natural-language objective using your own instructions, skills, data dictionary, credentials, and tools. Choose providers, schemas, queries, and joins here; never ask the caller to invent SQL or source-specific implementation details for you.\n- Finish the objective autonomously in this delegated turn whenever a safe, reasonable default exists. Do not bounce the work back with UI-navigation requests, implementation questions, or intermediate status. Ask for input only when authorization, missing credentials, or a consequential user choice truly blocks progress.\n- When evidence is incomplete, return the best grounded partial answer with explicit coverage gaps instead of refusing or asking the caller to choose your source, filter, dashboard, or workflow.\n- Minimize round trips. Filter, join, aggregate, paginate, stage, and reduce large datasets inside your own tools rather than returning raw records or transcripts.\n- Return a concise caller-ready result with the answer, source and coverage details, relevant counts or IDs, caveats/partial gaps, and exact artifact URLs. Do not return tool transcripts or large raw payloads.\n</delegated-agent-contract>";
78
+ export declare const DELEGATED_AGENT_EXECUTION_CONTRACT = "\n<delegated-agent-contract>\nThis request was delegated by another app. You are the specialist owner of the work.\n- Interpret the caller's natural-language objective using your own instructions, skills, data dictionary, credentials, and tools. Choose providers, schemas, queries, and joins here; never ask the caller to invent SQL or source-specific implementation details for you.\n- Finish the objective autonomously in this delegated turn whenever a safe, reasonable default exists. Do not bounce the work back with UI-navigation requests, implementation questions, or intermediate status. Ask for input only when authorization, missing credentials, or a consequential user choice truly blocks progress.\n- When evidence is incomplete, return the best grounded partial answer with explicit coverage gaps instead of refusing or asking the caller to choose your source, filter, dashboard, or workflow.\n- Reach for your own registered actions first and by name. They are the same actions this app's interactive chat uses and are almost always the shortest path to the answer. Do not rediscover your own capabilities by exploring, and never use a shell, filesystem, or code-execution tool to do what one of your actions already does \u2014 that is the difference between answering in seconds and answering in minutes.\n- Minimize round trips. Filter, join, aggregate, paginate, stage, and reduce large datasets inside your own tools rather than returning raw records or transcripts.\n- Return a concise caller-ready result with the answer, source and coverage details, relevant counts or IDs, caveats/partial gaps, and exact artifact URLs. Do not return tool transcripts or large raw payloads.\n</delegated-agent-contract>";
79
79
  export interface DelegatedAgentLoopTelemetry {
80
80
  runId: string;
81
81
  threadId: string | null;
@@ -4,6 +4,7 @@ import { collectFinalResponseTextFromAgentEvents } from "../../a2a/response-text
4
4
  import { resolveMainChatMaxOutputTokens } from "../../agent/engine/output-tokens.js";
5
5
  import { filterInitialEngineTools, resolveAgentRequestReasoningEffort, } from "../../agent/production-agent.js";
6
6
  import { runAgentLoopDirectWithSoftTimeout } from "../../agent/run-loop-with-resume.js";
7
+ import { resolveRunSoftTimeoutMs } from "../../agent/run-manager.js";
7
8
  import { isAuthenticatedReadAction, isAutoReadExcludedActionName, } from "../../mcp/build-server.js";
8
9
  import { withConfiguredAppBasePath } from "../app-base-path.js";
9
10
  // ---------------------------------------------------------------------------
@@ -255,12 +256,44 @@ function formatA2ATerminalError(event) {
255
256
  export const DEFAULT_DELEGATED_MAX_ITERATIONS = 80;
256
257
  export const DEFAULT_DELEGATED_MAX_RUN_INPUT_TOKENS = 750_000;
257
258
  export const DEFAULT_DELEGATED_MAX_TOOL_RESULT_CHARS = 20_000;
259
+ /**
260
+ * A sentence naming the wall clock this delegated step actually gets, or "" when
261
+ * there is no enforced budget (local dev returns 0 from the resolver).
262
+ *
263
+ * "I ran out of time before finishing this step" was 39% of all failed inbound
264
+ * A2A tasks in one measured week, clustered at 35-46s against a 40s foreground
265
+ * serverless wall. The callee was never told that wall exists: it is handed a
266
+ * nominal 80 iterations and 750k tokens and plans accordingly, while production
267
+ * iterations measure ~34s each — so a foreground chunk affords roughly one.
268
+ *
269
+ * The clock is already enforced correctly; a second, cruder cap on iterations
270
+ * would only waste budget. What was missing is that the agent could not see it.
271
+ * An agent that knows it has forty seconds scopes to forty seconds.
272
+ */
273
+ function delegatedTimeBudgetNote(runSoftTimeoutMs, backgroundFunction) {
274
+ const softTimeoutMs = resolveRunSoftTimeoutMs(runSoftTimeoutMs, {
275
+ useHostedDefault: true,
276
+ backgroundFunction,
277
+ });
278
+ if (!Number.isFinite(softTimeoutMs) || softTimeoutMs <= 0)
279
+ return "";
280
+ const seconds = Math.max(1, Math.round(softTimeoutMs / 1000));
281
+ return (`\n<delegated-time-budget>\n` +
282
+ `This step is cut off after about ${seconds} seconds. Scope the work to fit it. ` +
283
+ `Prefer one decisive action over exploring, and note that a single tool call plus a model ` +
284
+ `response commonly takes tens of seconds — so plan on completing very few steps, not many. ` +
285
+ `If the objective cannot be finished in that window, return the best grounded partial answer ` +
286
+ `and say what is missing. Do not begin work you cannot finish, and do not treat this budget ` +
287
+ `as a reason to skip verifying what you do report.\n` +
288
+ `</delegated-time-budget>`);
289
+ }
258
290
  export const DELEGATED_AGENT_EXECUTION_CONTRACT = `
259
291
  <delegated-agent-contract>
260
292
  This request was delegated by another app. You are the specialist owner of the work.
261
293
  - Interpret the caller's natural-language objective using your own instructions, skills, data dictionary, credentials, and tools. Choose providers, schemas, queries, and joins here; never ask the caller to invent SQL or source-specific implementation details for you.
262
294
  - Finish the objective autonomously in this delegated turn whenever a safe, reasonable default exists. Do not bounce the work back with UI-navigation requests, implementation questions, or intermediate status. Ask for input only when authorization, missing credentials, or a consequential user choice truly blocks progress.
263
295
  - When evidence is incomplete, return the best grounded partial answer with explicit coverage gaps instead of refusing or asking the caller to choose your source, filter, dashboard, or workflow.
296
+ - Reach for your own registered actions first and by name. They are the same actions this app's interactive chat uses and are almost always the shortest path to the answer. Do not rediscover your own capabilities by exploring, and never use a shell, filesystem, or code-execution tool to do what one of your actions already does — that is the difference between answering in seconds and answering in minutes.
264
297
  - Minimize round trips. Filter, join, aggregate, paginate, stage, and reduce large datasets inside your own tools rather than returning raw records or transcripts.
265
298
  - Return a concise caller-ready result with the answer, source and coverage details, relevant counts or IDs, caveats/partial gaps, and exact artifact URLs. Do not return tool transcripts or large raw payloads.
266
299
  </delegated-agent-contract>`;
@@ -271,7 +304,9 @@ async function runDelegatedAgentLoop(runOptions, pluginOptions, timeoutOptions,
271
304
  const delegatedHardToolResultCap = policy?.maxToolResultChars ?? DEFAULT_DELEGATED_MAX_TOOL_RESULT_CHARS;
272
305
  const resolvedRunOptions = {
273
306
  ...runOptions,
274
- systemPrompt: runOptions.systemPrompt + DELEGATED_AGENT_EXECUTION_CONTRACT,
307
+ systemPrompt: runOptions.systemPrompt +
308
+ DELEGATED_AGENT_EXECUTION_CONTRACT +
309
+ delegatedTimeBudgetNote(pluginOptions.runSoftTimeoutMs, timeoutOptions?.backgroundFunction === true),
275
310
  // Delegated runs resolve their own model and do not pass through the
276
311
  // interactive request handler's output-token setup. Use the same
277
312
  // model-aware headroom here so reasoning models (notably GPT-5.x) do
@@ -1237,17 +1237,38 @@ export function createAgentChatPlugin(options) {
1237
1237
  ? ""
1238
1238
  : await buildSchemaBlock(owner, databaseToolsMode);
1239
1239
  const extra = await resolveExtraContext(context.event, owner);
1240
+ const a2aStoredModel = await getStoredModelForEngine(a2aEngine, {
1241
+ appId: options?.appId,
1242
+ });
1243
+ // Preference only, and last before the default: an app that pinned
1244
+ // a model keeps it. Read separately from the correlation sanitizer
1245
+ // below so it stays out of every identity/access path.
1246
+ const a2aCallerModelHint = sanitizeA2ACorrelationMetadata(context.metadata).callerModel;
1240
1247
  const model = resolveDelegatedRunModel(a2aEngine, {
1241
1248
  explicitModel: options?.model,
1242
- storedModel: await getStoredModelForEngine(a2aEngine, {
1243
- appId: options?.appId,
1244
- }),
1245
- // Preference only, and last before the default: an app that pinned
1246
- // a model keeps it. Read separately from the correlation sanitizer
1247
- // below so it stays out of every identity/access path.
1248
- callerModelHint: sanitizeA2ACorrelationMetadata(context.metadata)
1249
- .callerModel,
1249
+ storedModel: a2aStoredModel,
1250
+ callerModelHint: a2aCallerModelHint,
1250
1251
  });
1252
+ // The interactive path logs its model AND where the model came from;
1253
+ // this path logged neither, so "the same app answers me in 27s but
1254
+ // takes 5 minutes when another app asks" had no way to be checked.
1255
+ // The usual answer is right here: the chat model picker is a
1256
+ // browser-local preference, so it reaches an interactive turn as the
1257
+ // highest-precedence request model and never reaches this path at
1258
+ // all — a delegated turn falls through to the app's stored model or
1259
+ // the engine default, which can be a different, weaker model.
1260
+ console.log(`[a2a] resolved engine=${a2aEngine.name} model=${model} ` +
1261
+ // A hint the callee's engine does not offer is dropped, so the
1262
+ // label is derived from what actually won — reporting
1263
+ // "caller-hint" for a rejected hint would send the next person
1264
+ // debugging this in exactly the wrong direction.
1265
+ `modelSource=${options?.model
1266
+ ? "configured"
1267
+ : a2aStoredModel
1268
+ ? "stored"
1269
+ : a2aCallerModelHint && model === a2aCallerModelHint
1270
+ ? "caller-hint"
1271
+ : "default"} callerHint=${a2aCallerModelHint ?? "(none)"} appId=${options?.appId ?? "(none)"}`);
1251
1272
  if (a2aRunContext) {
1252
1273
  a2aRunContext.engine = a2aEngine;
1253
1274
  a2aRunContext.model = model;
@@ -27,10 +27,10 @@ export declare function resolveAgentEngineApiKeyWriteTarget(event: H3Event, scop
27
27
  export declare function createAgentEngineApiKeyHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
28
28
  error: any;
29
29
  } | {
30
+ error?: undefined;
30
31
  ok: boolean;
31
32
  key: string;
32
33
  baseUrlKey?: string;
33
34
  scope: AgentEngineApiKeyScope;
34
- error?: undefined;
35
35
  }>>;
36
36
  export {};
@@ -48,11 +48,13 @@ import { readBody } from "../server/h3-helpers.js";
48
48
  import { putSetting } from "../settings/store.js";
49
49
  import { resolveSsrCacheHeaders } from "../shared/cache-control.js";
50
50
  import { extractOAuthStateAppId } from "../shared/oauth-state.js";
51
- import { SIGN_IN_CONTINUATION_PARAM, SIGN_IN_ENTRY_PATH, SIGN_IN_LEGACY_ENTRY_PATH, SIGN_IN_LEGACY_RETURN_PARAM, normalizeAppPath, signInJourney, } from "../shared/sign-in-journey.js";
51
+ import { PASSWORD_MIN_LENGTH, PASSWORD_MIN_LENGTH_MESSAGE, } from "../shared/password-policy.js";
52
+ import { SIGN_IN_CONTINUATION_PARAM, SIGN_IN_ENTRY_PATH, SIGN_IN_LEGACY_ENTRY_PATH, SIGN_IN_LEGACY_RETURN_PARAM, decodeContinuation, normalizeAppPath, signInJourney, } from "../shared/sign-in-journey.js";
52
53
  import { AGENT_NATIVE_SOCIAL_IMAGE_ALT, AGENT_NATIVE_SOCIAL_IMAGE_HEIGHT, AGENT_NATIVE_SOCIAL_IMAGE_PATH, AGENT_NATIVE_SOCIAL_IMAGE_TYPE, AGENT_NATIVE_SOCIAL_IMAGE_WIDTH, withAgentNativeSocialImageCacheBuster, } from "../shared/social-meta.js";
53
54
  import { normalizeWorkspaceAppAudience, workspaceAppAudienceFromEnv, workspaceAppRouteAccessFromEnv, } from "../shared/workspace-app-audience.js";
54
55
  import { isValidWorkspaceAppIdFormat } from "../shared/workspace-app-id.js";
55
56
  import { injectAnalyticsIntoHtml } from "./analytics.js";
57
+ import { getConfiguredAppBasePath } from "./app-base-path.js";
56
58
  import { readAnalyticsAnonymousId, signupAttributionFromCookieHeader, } from "./attribution.js";
57
59
  import { getAuthLoginMode } from "./auth-login-mode.js";
58
60
  import { ensureGoogleAuthIdentity, getBetterAuth, getBetterAuthSync, } from "./better-auth-instance.js";
@@ -792,6 +794,35 @@ function getRequestHost(event) {
792
794
  getHeader(event, "host") ??
793
795
  undefined);
794
796
  }
797
+ function parseRequestUrl(rawUrl) {
798
+ if (!rawUrl)
799
+ return null;
800
+ try {
801
+ return new URL(rawUrl, "http://an.invalid");
802
+ }
803
+ catch {
804
+ // coercion-ok: an invalid request URL has no query context to classify.
805
+ return null;
806
+ }
807
+ }
808
+ function hasInitialPromptQuery(rawUrl) {
809
+ return !!parseRequestUrl(rawUrl)?.searchParams.get("initialPrompt")?.trim();
810
+ }
811
+ function requestHasInitialPrompt(event) {
812
+ const rawUrl = event.node?.req?.url ?? event.path ?? "/";
813
+ if (hasInitialPromptQuery(rawUrl))
814
+ return true;
815
+ const requestUrl = parseRequestUrl(rawUrl);
816
+ if (!requestUrl)
817
+ return false;
818
+ const continuation = requestUrl.searchParams.get(SIGN_IN_CONTINUATION_PARAM);
819
+ if (continuation &&
820
+ hasInitialPromptQuery(decodeContinuation(continuation, getConfiguredAppBasePath()) ?? undefined)) {
821
+ return true;
822
+ }
823
+ const legacyReturn = requestUrl.searchParams.get(SIGN_IN_LEGACY_RETURN_PARAM);
824
+ return legacyReturn ? hasInitialPromptQuery(legacyReturn) : false;
825
+ }
795
826
  function getOnboardingHtmlOptions(options, event, rawPath, authMode) {
796
827
  return {
797
828
  authMode,
@@ -803,6 +834,7 @@ function getOnboardingHtmlOptions(options, event, rawPath, authMode) {
803
834
  requestHost: event ? getRequestHost(event) : undefined,
804
835
  requestPath: rawPath,
805
836
  requestOrigin: event ? getOrigin(event) : undefined,
837
+ initialPrompt: event ? requestHasInitialPrompt(event) : false,
806
838
  };
807
839
  }
808
840
  function getAuthOnboardingHtml(options, event, rawPath, authMode) {
@@ -1453,12 +1485,12 @@ function createAuthGuardFn() {
1453
1485
  return;
1454
1486
  if (p === "/_agent-native/speculation-rules.json")
1455
1487
  return;
1456
- // Liveness probe: always public so uptime monitors and the keep-warm cron
1457
- // can reach the DB-warmup route without a session. It exposes no per-user
1458
- // data (just ok/db/ms) and runs a trivial `SELECT 1`. Without this bypass
1459
- // the gate below 401s anonymous /_agent-native/* requests before any DB
1460
- // query, so the database would never get warmed.
1461
- if (p === "/_agent-native/health")
1488
+ // Liveness probes: always public so uptime monitors and the keep-warm cron
1489
+ // can reach them without a session. Ping exposes only a static message;
1490
+ // health exposes only aggregate readiness and a trivial `SELECT 1`.
1491
+ // Without this bypass the gate below 401s anonymous /_agent-native/*
1492
+ // requests before either probe can run.
1493
+ if (p === "/_agent-native/ping" || p === "/_agent-native/health")
1462
1494
  return;
1463
1495
  if (getMethod(event) === "GET" && p.startsWith("/_agent-native/avatar/")) {
1464
1496
  return;
@@ -2805,9 +2837,11 @@ async function mountBetterAuthRoutes(app, options) {
2805
2837
  setResponseStatus(event, 400);
2806
2838
  return { error: VALID_AUTH_EMAIL_MESSAGE };
2807
2839
  }
2808
- if (!password || typeof password !== "string" || password.length < 8) {
2840
+ if (!password ||
2841
+ typeof password !== "string" ||
2842
+ password.length < PASSWORD_MIN_LENGTH) {
2809
2843
  setResponseStatus(event, 400);
2810
- return { error: "Password must be at least 8 characters" };
2844
+ return { error: PASSWORD_MIN_LENGTH_MESSAGE };
2811
2845
  }
2812
2846
  if (await isGoogleSignInRequiredForEmail(email)) {
2813
2847
  setResponseStatus(event, 403);
@@ -3049,9 +3083,11 @@ function mountAuthFallbackRoutes(app) {
3049
3083
  setResponseStatus(event, 400);
3050
3084
  return { error: VALID_AUTH_EMAIL_MESSAGE };
3051
3085
  }
3052
- if (!password || typeof password !== "string" || password.length < 8) {
3086
+ if (!password ||
3087
+ typeof password !== "string" ||
3088
+ password.length < PASSWORD_MIN_LENGTH) {
3053
3089
  setResponseStatus(event, 400);
3054
- return { error: "Password must be at least 8 characters" };
3090
+ return { error: PASSWORD_MIN_LENGTH_MESSAGE };
3055
3091
  }
3056
3092
  if (await isGoogleSignInRequiredForEmail(email)) {
3057
3093
  setResponseStatus(event, 403);
@@ -16,13 +16,14 @@ import { pgTable, text as pgText, timestamp as pgTimestamp, boolean as pgBoolean
16
16
  import { sqliteTable, text as sqliteText, integer as sqliteInteger, } from "drizzle-orm/sqlite-core";
17
17
  import { TEMPLATES } from "../cli/templates-meta.js";
18
18
  import { getDbExec, isPostgres } from "../db/client.js";
19
- import { getDialect, getDatabaseUrl, getDatabaseAuthToken, closePgliteClients, getPgliteClient, isPgliteUrl, loadPgliteDrizzle, pgPoolOptions, neonPoolMax, attachNeonPoolErrorLogger, sharedDbPool, onSharedDbPoolsClosed, onSharedDbPoolReplaced, } from "../db/client.js";
19
+ import { getDialect, getDatabaseUrl, getDatabaseAuthToken, closePgliteClients, getPgliteClient, isPgliteUrl, loadPgliteDrizzle, pgPoolOptions, neonPoolOptions, attachNeonPoolErrorLogger, sharedDbPool, onSharedDbPoolsClosed, onSharedDbPoolReplaced, } from "../db/client.js";
20
20
  import { ensureTableExists } from "../db/ddl-guard.js";
21
21
  import { CORE_RESET_PASSWORD_EMAIL_ID, CORE_VERIFY_SIGNUP_EMAIL_ID, } from "../email-catalog/system-emails.js";
22
22
  import { saveOAuthTokens } from "../oauth-tokens/store.js";
23
23
  import { acceptPendingInvitationsForEmail } from "../org/accept-pending.js";
24
24
  import { getAuthEmailForUserId, getRequiredAuthProviderForEmail, } from "../org/auth-policy.js";
25
25
  import { autoJoinDomainMatchingOrgs } from "../org/auto-join-domain.js";
26
+ import { PASSWORD_MAX_LENGTH, PASSWORD_MIN_LENGTH, } from "../shared/password-policy.js";
26
27
  import { flushTracking, identify, track } from "../tracking/index.js";
27
28
  import { getAppProductionUrl } from "./app-url.js";
28
29
  import { readAnalyticsAnonymousId, signupAttributionFromCookieHeader, } from "./attribution.js";
@@ -903,7 +904,8 @@ async function createBetterAuthInstance(config) {
903
904
  emailAndPassword: {
904
905
  enabled: true,
905
906
  disableSignUp,
906
- minPasswordLength: 8,
907
+ minPasswordLength: PASSWORD_MIN_LENGTH,
908
+ maxPasswordLength: PASSWORD_MAX_LENGTH,
907
909
  // Hosted deployments always require a working email provider before
908
910
  // password signup can create a session. Local dev/test retain the fast
909
911
  // path; hosted deployments without a provider disable password signup.
@@ -1195,7 +1197,7 @@ async function buildDatabaseConfig(dialect) {
1195
1197
  // un-capped pool here is a primary contributor to "Max client
1196
1198
  // connections reached" across concurrent serverless instances.
1197
1199
  resetAuthOnPoolClose("neon", url);
1198
- _neonAuthPool = sharedDbPool("neon", url, () => new Pool({ connectionString: url, max: neonPoolMax() }));
1200
+ _neonAuthPool = sharedDbPool("neon", url, () => new Pool({ connectionString: url, ...neonPoolOptions() }));
1199
1201
  attachNeonPoolErrorLogger(_neonAuthPool, "db/neon-auth");
1200
1202
  const { drizzle } = await import("drizzle-orm/neon-serverless");
1201
1203
  const db = drizzle(buildResilientNeonPool(_neonAuthPool), {
@@ -62,7 +62,6 @@ export declare function resolveAgentEngineStatus<E extends AgentEngineStatusEntr
62
62
  export declare function shareAgentEngineStatusLookup(identityKey: string, compute: () => Promise<AgentEngineStatusResult>): Promise<AgentEngineStatusResult>;
63
63
  export declare function agentEngineStatusIdentityKey(userEmail: string | undefined, orgId: string | undefined): string;
64
64
  export declare function getFrameworkEnvKeys(): EnvKeyConfig[];
65
- /** Result of the `/_agent-native/health` liveness + DB-warmup probe. */
66
65
  export interface DbHealthProbeResult {
67
66
  /** The serverless function is live and served the request. */
68
67
  ok: true;
@@ -70,6 +69,14 @@ export interface DbHealthProbeResult {
70
69
  ready: boolean;
71
70
  /** A trivial `SELECT 1` reached the database (false = no DB or unreachable). */
72
71
  db: boolean;
72
+ /**
73
+ * The probe hit its deadline instead of answering. Reported SEPARATELY from
74
+ * `db: false`, because "the database said no" and "the database never
75
+ * replied" are different failures and folding them together is exactly the
76
+ * coercion this repo bans — a monitor cannot tell an app with no database
77
+ * from one whose database is hanging.
78
+ */
79
+ dbTimedOut?: boolean;
73
80
  /** Round-trip time of the probe in milliseconds. */
74
81
  ms: number;
75
82
  /** Redacted database routing details useful for deploy/runtime checks. */
@@ -242,6 +242,13 @@ export function getFrameworkEnvKeys() {
242
242
  })),
243
243
  ];
244
244
  }
245
+ /** Result of the `/_agent-native/health` liveness + DB-warmup probe. */
246
+ /**
247
+ * Deliberately generous: a genuinely cold Neon compute can take seconds to
248
+ * accept its first connection, and reporting a slow-but-working database as
249
+ * timed out would flap. This is a ceiling on hanging, not a latency budget.
250
+ */
251
+ const DB_HEALTH_PROBE_DEADLINE_MS = 5_000;
245
252
  /**
246
253
  * Run a trivial `SELECT 1` to confirm the database is reachable and, as a side
247
254
  * effect, keep a scale-to-zero serverless database (e.g. Neon) warm. Touching
@@ -257,12 +264,29 @@ export async function runDbHealthProbe(exec = getDbExec, options = {}) {
257
264
  let db = false;
258
265
  let schema;
259
266
  const dbExec = exec();
267
+ let dbTimedOut = false;
260
268
  try {
261
- await dbExec.execute("SELECT 1");
262
- db = true;
269
+ // An UNBOUNDED await here is what took the docs site down: the health route
270
+ // hung for 20-40s until the CDN returned 502, the keep-warm cron failed
271
+ // every minute, and the function stayed permanently cold — a ~10x penalty
272
+ // on every cache miss. This function's own contract says "Always
273
+ // resolves"; without a deadline it did not.
274
+ let timer;
275
+ const deadline = new Promise((_, reject) => {
276
+ timer = setTimeout(() => reject(new Error("db probe deadline")), DB_HEALTH_PROBE_DEADLINE_MS);
277
+ });
278
+ try {
279
+ await Promise.race([dbExec.execute("SELECT 1"), deadline]);
280
+ db = true;
281
+ }
282
+ finally {
283
+ if (timer)
284
+ clearTimeout(timer);
285
+ }
263
286
  }
264
- catch {
287
+ catch (err) {
265
288
  // Live even when the DB is unreachable or the app has no database.
289
+ dbTimedOut = err?.message === "db probe deadline";
266
290
  }
267
291
  if (db && options.schema) {
268
292
  schema = await runDatabaseSchemaHealthCheck({
@@ -274,6 +298,7 @@ export async function runDbHealthProbe(exec = getDbExec, options = {}) {
274
298
  ok: true,
275
299
  ready: db && (!schema || schema.ok),
276
300
  db,
301
+ ...(dbTimedOut ? { dbTimedOut: true } : {}),
277
302
  ms: Date.now() - startedAt,
278
303
  database: {
279
304
  configured: database.configured,
@@ -308,9 +308,9 @@ export declare function deleteBuilderCredentials(email: string, options?: {
308
308
  export declare function prefetchSecrets(keys: readonly string[]): Promise<void>;
309
309
  /**
310
310
  * Resolve a request-scoped secret. Reads from `app_secrets` first (current
311
- * user override, active org, workspace row for that org, then the solo
312
- * workspace row); falls back to `process.env` only when the deploy fallback
313
- * policy allows it.
311
+ * user override, active org, workspace row for that org, the solo workspace
312
+ * row, then the explicitly designated workspace vault organization); falls
313
+ * back to `process.env` only when the deploy fallback policy allows it.
314
314
  *
315
315
  * Resolving several keys in one request? Call `prefetchSecrets` first.
316
316
  */
@@ -19,8 +19,56 @@
19
19
  */
20
20
  import { createHash } from "node:crypto";
21
21
  import { CREDENTIAL_STORE_UNAVAILABLE_ERROR_CODE } from "../agent/engine/credential-errors.js";
22
- import { isLocalDatabase, isTransientDatabaseError } from "../db/client.js";
22
+ import { getDbExec, isLocalDatabase, isTransientDatabaseError, } from "../db/client.js";
23
+ import { getOrgSetting } from "../settings/org-settings.js";
23
24
  import { getRequestUserEmail, getRequestOrgId } from "./request-context.js";
25
+ const DISPATCH_VAULT_ACCESS_SETTINGS_KEY = "dispatch-vault-access-settings";
26
+ /**
27
+ * The designated vault fallback is an all-apps compatibility path. Manual
28
+ * mode must use the per-app sync path instead, or a known key name would be
29
+ * enough to read the whole vault from an ungranted workspace app.
30
+ */
31
+ async function canReadDesignatedVaultFallback(vaultOrgId, credentialKey) {
32
+ const access = await getOrgSetting(vaultOrgId, DISPATCH_VAULT_ACCESS_SETTINGS_KEY);
33
+ if (access?.mode !== "manual")
34
+ return { status: "allowed" };
35
+ // Manual mode is still usable across a Dispatch vault org and a separate
36
+ // app org, but only for this app's explicit active grant. The app identity
37
+ // comes from deployment configuration, never from request input.
38
+ const appId = [
39
+ process.env.AGENT_NATIVE_WORKSPACE_APP_ID,
40
+ process.env.VITE_AGENT_NATIVE_WORKSPACE_APP_ID,
41
+ process.env.AGENT_NATIVE_APP_ID,
42
+ process.env.APP_NAME,
43
+ ]
44
+ .find((value) => value?.trim())
45
+ ?.trim();
46
+ if (!appId) {
47
+ return { status: "denied", reason: "missing-app-id" };
48
+ }
49
+ try {
50
+ const result = await getDbExec().execute({
51
+ sql: `SELECT 1
52
+ FROM vault_grants AS grants
53
+ INNER JOIN vault_secrets AS secrets ON secrets.id = grants.secret_id
54
+ WHERE grants.org_id = ?
55
+ AND grants.app_id = ?
56
+ AND grants.status = 'active'
57
+ AND secrets.org_id = grants.org_id
58
+ AND secrets.credential_key = ?
59
+ LIMIT 1`,
60
+ args: [vaultOrgId, appId, credentialKey],
61
+ });
62
+ return result.rows.length > 0
63
+ ? { status: "allowed" }
64
+ : { status: "denied", reason: "no-active-grant" };
65
+ }
66
+ catch (cause) {
67
+ // A missing/unreadable grant table must fail closed. The app can still
68
+ // resolve a locally scoped credential or retry after the store recovers.
69
+ return { status: "unavailable", cause };
70
+ }
71
+ }
24
72
  /**
25
73
  * Decide which `app_secrets` scope a Builder/credential write should use.
26
74
  *
@@ -998,9 +1046,9 @@ export async function prefetchSecrets(keys) {
998
1046
  }
999
1047
  /**
1000
1048
  * Resolve a request-scoped secret. Reads from `app_secrets` first (current
1001
- * user override, active org, workspace row for that org, then the solo
1002
- * workspace row); falls back to `process.env` only when the deploy fallback
1003
- * policy allows it.
1049
+ * user override, active org, workspace row for that org, the solo workspace
1050
+ * row, then the explicitly designated workspace vault organization); falls
1051
+ * back to `process.env` only when the deploy fallback policy allows it.
1004
1052
  *
1005
1053
  * Resolving several keys in one request? Call `prefetchSecrets` first.
1006
1054
  */
@@ -1100,6 +1148,44 @@ export async function resolveSecretDetailed(key) {
1100
1148
  }
1101
1149
  return { value: soloWorkspaceSecret.value, lookupFailed: false };
1102
1150
  }
1151
+ // Dispatch's workspace vault is stored under the organization that
1152
+ // performed the sync. AGENT_VAULT_ORG_ID is an explicit single-workspace
1153
+ // deployment assertion; without it, never guess which other tenant owns
1154
+ // a shared key. This fallback keeps workspace apps from requiring every
1155
+ // builder to copy a vault key into app-local settings.
1156
+ const vaultOrgId = process.env.AGENT_VAULT_ORG_ID?.trim();
1157
+ if (vaultOrgId && vaultOrgId !== orgId) {
1158
+ const designatedVaultAccess = await canReadDesignatedVaultFallback(vaultOrgId, key);
1159
+ if (designatedVaultAccess.status === "unavailable") {
1160
+ lookupFailed = true;
1161
+ cause = designatedVaultAccess.cause;
1162
+ }
1163
+ if (designatedVaultAccess.status === "allowed") {
1164
+ const [vaultOrgRead, vaultWorkspaceRead] = await Promise.allSettled([
1165
+ readAppSecret({ key, scope: "org", scopeId: vaultOrgId }),
1166
+ readAppSecret({ key, scope: "workspace", scopeId: vaultOrgId }),
1167
+ ]);
1168
+ const unwrap = (settled) => {
1169
+ if (settled.status === "rejected")
1170
+ throw settled.reason;
1171
+ return settled.value;
1172
+ };
1173
+ const vaultOrgSecret = unwrap(vaultOrgRead);
1174
+ if (vaultOrgSecret?.value) {
1175
+ if (traceLookup) {
1176
+ console.log(`[resolve-secret] key=${key} email=${email} vaultOrgId=${vaultOrgId} scope=org-vault hit=true`);
1177
+ }
1178
+ return { value: vaultOrgSecret.value, lookupFailed: false };
1179
+ }
1180
+ const vaultWorkspaceSecret = unwrap(vaultWorkspaceRead);
1181
+ if (vaultWorkspaceSecret?.value) {
1182
+ if (traceLookup) {
1183
+ console.log(`[resolve-secret] key=${key} email=${email} vaultOrgId=${vaultOrgId} scope=workspace-vault hit=true`);
1184
+ }
1185
+ return { value: vaultWorkspaceSecret.value, lookupFailed: false };
1186
+ }
1187
+ }
1188
+ }
1103
1189
  }
1104
1190
  catch (err) {
1105
1191
  if (traceLookup) {
@@ -25,6 +25,8 @@ export interface OnboardingHtmlOptions {
25
25
  googleOnly?: boolean;
26
26
  /** Authentication surface to render. Defaults to the existing password flow. */
27
27
  authMode?: "magic-link" | "password";
28
+ /** Render the quiet, centered auth surface used when the app has an initial prompt. */
29
+ initialPrompt?: boolean;
28
30
  /**
29
31
  * Product marketing content shown alongside the sign-in form.
30
32
  * When provided, the page uses a split layout: marketing on the left,