@agent-native/core 0.129.2 → 0.130.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 (589) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +72 -0
  3. package/corpus/core/docs/content/cloneable-saas.mdx +114 -0
  4. package/corpus/core/docs/content/creating-templates.mdx +28 -2
  5. package/corpus/core/docs/content/syncing-template-changes.mdx +7 -0
  6. package/corpus/core/docs/content/template-clips-developers.mdx +12 -5
  7. package/corpus/core/docs/content/template-dispatch-developers.mdx +1 -1
  8. package/corpus/core/docs/content/template-dispatch.mdx +1 -1
  9. package/corpus/core/package.json +1 -1
  10. package/corpus/core/src/action-ui.ts +1 -0
  11. package/corpus/core/src/action.ts +5 -1
  12. package/corpus/core/src/agent/engine/ai-sdk-engine.ts +15 -5
  13. package/corpus/core/src/agent/harness/runner.ts +5 -0
  14. package/corpus/core/src/agent/production-agent.ts +33 -0
  15. package/corpus/core/src/agent/run-loop-with-resume.ts +5 -0
  16. package/corpus/core/src/agent/run-manager.ts +126 -1
  17. package/corpus/core/src/agent/thread-data-builder.ts +47 -2
  18. package/corpus/core/src/agent/types.ts +2 -0
  19. package/corpus/core/src/chat-threads/store.ts +4 -5
  20. package/corpus/core/src/cli/create.ts +1139 -65
  21. package/corpus/core/src/cli/design-connect.ts +3 -7
  22. package/corpus/core/src/cli/index.ts +5 -3
  23. package/corpus/core/src/cli/skills-content/design-visual-edit-skill.ts +83 -47
  24. package/corpus/core/src/client/AssistantChat.tsx +27 -16
  25. package/corpus/core/src/client/agent-chat-adapter.ts +24 -0
  26. package/corpus/core/src/client/blocks/library/wireframe-kit.tsx +17 -2
  27. package/corpus/core/src/client/chat/index.ts +1 -0
  28. package/corpus/core/src/client/chat/message-components.tsx +104 -1
  29. package/corpus/core/src/client/chat/run-recovery.tsx +15 -3
  30. package/corpus/core/src/client/chat/widgets/DataTableWidget.tsx +10 -29
  31. package/corpus/core/src/client/chat/widgets/WorkspaceFileWidget.tsx +71 -0
  32. package/corpus/core/src/client/chat/widgets/builtin-tool-renderers.tsx +22 -0
  33. package/corpus/core/src/client/chat/widgets/workspace-file-result.ts +49 -0
  34. package/corpus/core/src/client/embed-auth.ts +2 -0
  35. package/corpus/core/src/client/org/InvitationBanner.tsx +14 -1
  36. package/corpus/core/src/client/org/OrgSwitcher.tsx +23 -0
  37. package/corpus/core/src/client/org/TeamPage.tsx +130 -0
  38. package/corpus/core/src/client/org/WorkspaceNotice.tsx +85 -0
  39. package/corpus/core/src/client/org/hooks.ts +14 -0
  40. package/corpus/core/src/client/org/index.ts +2 -0
  41. package/corpus/core/src/client/resources/McpIntegrationDialog.tsx +27 -40
  42. package/corpus/core/src/client/resources/ResourcesPanel.tsx +134 -51
  43. package/corpus/core/src/client/resources/mcp-integration-catalog.ts +7 -0
  44. package/corpus/core/src/client/resources/use-resources.ts +6 -0
  45. package/corpus/core/src/client/use-action.ts +3 -1
  46. package/corpus/core/src/client/widgets/index.ts +1 -0
  47. package/corpus/core/src/coding-tools/run-code.ts +2 -1
  48. package/corpus/core/src/db/client.ts +28 -4
  49. package/corpus/core/src/deploy/build.ts +31 -3
  50. package/corpus/core/src/eject/remote-mcp-presets.ts +1 -1
  51. package/corpus/core/src/index.browser.ts +1 -0
  52. package/corpus/core/src/index.ts +1 -0
  53. package/corpus/core/src/integrations/google-docs-poller.ts +3 -0
  54. package/corpus/core/src/integrations/webhook-handler.ts +28 -11
  55. package/corpus/core/src/jobs/scheduler.ts +4 -0
  56. package/corpus/core/src/localization/default-messages.ts +3 -2
  57. package/corpus/core/src/observability/traces.ts +48 -12
  58. package/corpus/core/src/org/handlers.ts +52 -1
  59. package/corpus/core/src/org/migrations.ts +4 -0
  60. package/corpus/core/src/org/plugin.ts +14 -0
  61. package/corpus/core/src/org/schema.ts +1 -0
  62. package/corpus/core/src/org/types.ts +8 -0
  63. package/corpus/core/src/org/workspace-url.ts +74 -0
  64. package/corpus/core/src/resources/handlers.ts +35 -5
  65. package/corpus/core/src/scripts/runner.ts +183 -5
  66. package/corpus/core/src/server/action-routes.ts +32 -2
  67. package/corpus/core/src/server/agent-chat-plugin.ts +29 -0
  68. package/corpus/core/src/server/agent-teams.ts +10 -1
  69. package/corpus/core/src/server/auth.ts +33 -7
  70. package/corpus/core/src/server/embed-route.ts +9 -0
  71. package/corpus/core/src/server/embed-session.ts +62 -3
  72. package/corpus/core/src/server/open-route.ts +20 -6
  73. package/corpus/core/src/server/prompts/framework-core-compact.ts +1 -1
  74. package/corpus/core/src/server/prompts/framework-core.ts +1 -0
  75. package/corpus/core/src/server/request-context.ts +36 -1
  76. package/corpus/core/src/shared/embed-auth.ts +1 -0
  77. package/corpus/core/src/shared/html-document.ts +115 -0
  78. package/corpus/core/src/shared/index.ts +1 -0
  79. package/corpus/core/src/sharing/access.ts +8 -1
  80. package/corpus/core/src/sharing/registry.ts +11 -2
  81. package/corpus/core/src/workspace-files/actions.ts +100 -0
  82. package/corpus/core/src/workspace-files/tool.ts +4 -0
  83. package/corpus/templates/analytics/.agents/skills/analysis-workspace/SKILL.md +4 -0
  84. package/corpus/templates/analytics/.agents/skills/hubspot/SKILL.md +9 -1
  85. package/corpus/templates/analytics/AGENTS.md +17 -24
  86. package/corpus/templates/analytics/actions/data-source-status.ts +11 -1
  87. package/corpus/templates/analytics/app/i18n-data.ts +34 -0
  88. package/corpus/templates/analytics/app/lib/data-source-status.ts +86 -0
  89. package/corpus/templates/analytics/app/lib/native-mcp-exclusions.ts +9 -0
  90. package/corpus/templates/analytics/app/pages/DataSources.tsx +184 -20
  91. package/corpus/templates/analytics/changelog/2026-07-28-native-analytics-data-sources-no-longer-show-duplicate-mc.md +6 -0
  92. package/corpus/templates/analytics/changelog/2026-07-29-exports-now-appear-in-chat-with-a-direct-download-instead-of.md +6 -0
  93. package/corpus/templates/analytics/changelog/2026-07-29-queued-chat-prompts-no-longer-resend-after-analytics-navigat.md +6 -0
  94. package/corpus/templates/analytics/changelog/2026-07-29-scheduled-dashboard-emails-load-every-panel-reliably-without.md +6 -0
  95. package/corpus/templates/analytics/scripts/emit-netlify-dashboard-report-cron.ts +6 -3
  96. package/corpus/templates/analytics/server/lib/credential-keys.ts +1 -1
  97. package/corpus/templates/analytics/server/lib/hubspot.ts +1 -1
  98. package/corpus/templates/analytics/server/lib/provider-credentials.ts +55 -1
  99. package/corpus/templates/analytics/server/plugins/agent-chat.ts +123 -27
  100. package/corpus/templates/analytics/server/routes/[...page].get.ts +2 -7
  101. package/corpus/templates/analytics/vite.config.ts +7 -0
  102. package/corpus/templates/brain/actions/list-connection-providers.ts +100 -2
  103. package/corpus/templates/brain/app/lib/brain.ts +10 -0
  104. package/corpus/templates/brain/app/routes/sources.tsx +15 -4
  105. package/corpus/templates/brain/changelog/2026-07-29-brain-automatically-retries-failed-source-syncs-and-guides-y.md +6 -0
  106. package/corpus/templates/brain/jobs/process-ingest-queue.ts +13 -0
  107. package/corpus/templates/brain/server/jobs/sync-sources.ts +27 -22
  108. package/corpus/templates/brain/server/plugins/agent-chat.ts +2 -1
  109. package/corpus/templates/brain/server/routes/api/brain/queue/run.post.ts +7 -1
  110. package/corpus/templates/clips/AGENTS.md +1 -1
  111. package/corpus/templates/clips/actions/create-recording-agent-link.ts +11 -1
  112. package/corpus/templates/clips/actions/update-comment.ts +68 -0
  113. package/corpus/templates/clips/app/components/editor/editor-layout.tsx +0 -1
  114. package/corpus/templates/clips/app/components/player/comments-panel.tsx +221 -65
  115. package/corpus/templates/clips/app/components/player/video-player.tsx +101 -27
  116. package/corpus/templates/clips/app/i18n/en-US.ts +2 -1
  117. package/corpus/templates/clips/app/routes/bug-report.done.tsx +48 -27
  118. package/corpus/templates/clips/app/routes/bug-report.tsx +43 -4
  119. package/corpus/templates/clips/app/routes/record.tsx +2 -0
  120. package/corpus/templates/clips/changelog/2026-07-29-clip-playback-now-recovers-instead-of-getting-stuck-when-a-b.md +6 -0
  121. package/corpus/templates/clips/changelog/2026-07-29-comments-can-now-be-edited-after-posting.md +6 -0
  122. package/corpus/templates/clips/changelog/2026-07-29-download-actions-now-use-a-shorter-clearer-label.md +6 -0
  123. package/corpus/templates/clips/changelog/2026-07-29-embedded-bug-reports-now-return-a-temporary-agent-readable.md +6 -0
  124. package/corpus/templates/clips/shared/bug-report.ts +99 -0
  125. package/corpus/templates/content/actions/_content-database-personal-view.ts +7 -1
  126. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +5 -2
  127. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +20 -8
  128. package/corpus/templates/content/changelog/2026-07-29-missing-databases-no-longer-trigger-repeated-personal-view-e.md +6 -0
  129. package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +83 -47
  130. package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +474 -55
  131. package/corpus/templates/design/.generated/bridge/embedded-wheel.generated.ts +3 -0
  132. package/corpus/templates/design/.generated/bridge/hit-test.generated.ts +18 -1
  133. package/corpus/templates/design/.generated/bridge/source-location.generated.ts +348 -0
  134. package/corpus/templates/design/actions/add-localhost-screens.ts +2 -7
  135. package/corpus/templates/design/actions/apply-visual-edit.ts +7 -1
  136. package/corpus/templates/design/actions/connect-localhost.ts +5 -9
  137. package/corpus/templates/design/actions/create-component.ts +16 -13
  138. package/corpus/templates/design/actions/grant-localhost-write-consent.ts +2 -7
  139. package/corpus/templates/design/actions/list-design-source-capabilities.ts +4 -7
  140. package/corpus/templates/design/actions/list-local-files.ts +26 -50
  141. package/corpus/templates/design/actions/list-localhost-connections.ts +2 -7
  142. package/corpus/templates/design/actions/migrate-board-objects-to-file.ts +2 -2
  143. package/corpus/templates/design/actions/open-visual-edit.ts +234 -135
  144. package/corpus/templates/design/actions/read-local-file.ts +26 -50
  145. package/corpus/templates/design/actions/request-localhost-write-consent.ts +2 -7
  146. package/corpus/templates/design/actions/write-local-file.ts +31 -73
  147. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +307 -133
  148. package/corpus/templates/design/app/components/design/EditPanel.tsx +94 -22
  149. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +137 -60
  150. package/corpus/templates/design/app/components/design/ResponsiveInteractBar.tsx +75 -14
  151. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +755 -97
  152. package/corpus/templates/design/app/components/design/bridge/embedded-wheel.bridge.ts +8 -0
  153. package/corpus/templates/design/app/components/design/bridge/hit-test.bridge.ts +24 -1
  154. package/corpus/templates/design/app/components/design/bridge/source-location.bridge.ts +530 -0
  155. package/corpus/templates/design/app/components/design/code-workbench/CodeWorkbenchLoader.tsx +278 -0
  156. package/corpus/templates/design/app/components/design/code-workbench/editor/MonacoHost.tsx +32 -12
  157. package/corpus/templates/design/app/components/design/code-workbench/editor/monaco-setup.ts +14 -3
  158. package/corpus/templates/design/app/components/design/code-workbench/explorer/ExplorerView.tsx +87 -24
  159. package/corpus/templates/design/app/components/design/code-workbench/explorer/FileTree.tsx +36 -0
  160. package/corpus/templates/design/app/components/design/code-workbench/store.tsx +2 -1
  161. package/corpus/templates/design/app/components/design/code-workbench/workspace/localhost-provider.ts +48 -8
  162. package/corpus/templates/design/app/components/design/design-canvas/content-size-report.ts +3 -13
  163. package/corpus/templates/design/app/components/design/design-canvas/embedded-frame.ts +4 -2
  164. package/corpus/templates/design/app/components/design/design-canvas/hit-test.ts +3 -13
  165. package/corpus/templates/design/app/components/design/edit-panel/element-classification.ts +3 -1
  166. package/corpus/templates/design/app/components/design/edit-panel/inspect-code-source.ts +93 -0
  167. package/corpus/templates/design/app/components/design/multi-screen/board-surface-html.ts +4 -2
  168. package/corpus/templates/design/app/components/design/multi-screen/cross-screen-drop.ts +35 -0
  169. package/corpus/templates/design/app/components/design/multi-screen/iframe-targeting.ts +24 -0
  170. package/corpus/templates/design/app/components/design/multi-screen/types.ts +9 -0
  171. package/corpus/templates/design/app/components/design/types.ts +29 -0
  172. package/corpus/templates/design/app/components/layout/Layout.tsx +7 -4
  173. package/corpus/templates/design/app/hooks/use-navigation-state.ts +3 -0
  174. package/corpus/templates/design/app/i18n-data.ts +153 -46
  175. package/corpus/templates/design/app/i18n-responsive-interact.ts +12 -12
  176. package/corpus/templates/design/app/lib/design-editor-route.ts +23 -0
  177. package/corpus/templates/design/app/pages/VisualEdit.tsx +19 -6
  178. package/corpus/templates/design/app/pages/design-editor/action-error.ts +19 -0
  179. package/corpus/templates/design/app/pages/design-editor/canvas-primitive-insert.ts +29 -0
  180. package/corpus/templates/design/app/pages/design-editor/clone-and-pen-edit.ts +6 -0
  181. package/corpus/templates/design/app/pages/design-editor/code-layer-state.ts +277 -15
  182. package/corpus/templates/design/app/pages/design-editor/editor-state.ts +75 -9
  183. package/corpus/templates/design/app/pages/design-editor/layer-state-scope.ts +28 -0
  184. package/corpus/templates/design/app/pages/design-editor/live-screen-layer-drop.ts +41 -0
  185. package/corpus/templates/design/app/pages/design-editor/pending-edits.ts +496 -41
  186. package/corpus/templates/design/app/pages/design-editor/pending-live-edit-unload-guard.ts +27 -0
  187. package/corpus/templates/design/app/pages/design-editor/pending-structure-verification.ts +10 -0
  188. package/corpus/templates/design/app/pages/design-editor/react-semantic-handoff.ts +168 -9
  189. package/corpus/templates/design/app/pages/design-editor/responsive-interact.ts +41 -3
  190. package/corpus/templates/design/app/pages/design-editor/screen-command-utils.ts +5 -0
  191. package/corpus/templates/design/app/pages/design-editor/selection-state.ts +42 -13
  192. package/corpus/templates/design/app/pages/design-editor/source-location.ts +180 -0
  193. package/corpus/templates/design/app/pages/design-editor/tool-state.ts +17 -0
  194. package/corpus/templates/design/app/public-routes.ts +1 -0
  195. package/corpus/templates/design/app/routes/visual-edit.$id.tsx +15 -0
  196. package/corpus/templates/design/changelog/2026-06-29-screen-overview-is-easier-to-find-and-named-screens-open-dir.md +1 -1
  197. package/corpus/templates/design/changelog/2026-07-28-deleting-a-selected-element-now-removes-it-from-the-live-pre.md +6 -0
  198. package/corpus/templates/design/changelog/2026-07-28-deleting-an-element-on-a-connected-localhost-screen-now-queu.md +6 -0
  199. package/corpus/templates/design/changelog/2026-07-28-interact-mode-now-shows-a-responsive-device-preview-with-pre.md +6 -0
  200. package/corpus/templates/design/changelog/2026-07-28-layer-hide-and-lock-now-apply-to-the-live-preview-instead-of.md +6 -0
  201. package/corpus/templates/design/changelog/2026-07-28-layers-panel-selections-on-a-connected-localhost-screen-can-.md +6 -0
  202. package/corpus/templates/design/changelog/2026-07-28-locked-layers-now-show-a-subtle-dashed-outline-in-the-live-p.md +6 -0
  203. package/corpus/templates/design/changelog/2026-07-28-the-apply-design-updates-button-now-counts-pending-live-text.md +6 -0
  204. package/corpus/templates/design/changelog/2026-07-28-the-design-canvas-no-longer-stalls-on-a-render-loop-while-a-.md +6 -0
  205. package/corpus/templates/design/changelog/2026-07-28-visual-edit-on-a-local-dev-server-no-longer-requires-signing.md +6 -0
  206. package/corpus/templates/design/changelog/2026-07-28-visual-edits-on-a-react-19-app-no-longer-report-a-source-lin.md +6 -0
  207. package/corpus/templates/design/changelog/2026-07-29-an-edit-that-cannot-be-written-to-source-now-names-the-reaso.md +6 -0
  208. package/corpus/templates/design/changelog/2026-07-29-applying-a-primitive-dropped-onto-a-connected-localhost-scre.md +6 -0
  209. package/corpus/templates/design/changelog/2026-07-29-changing-a-style-in-the-inspector-now-updates-a-connected-lo.md +6 -0
  210. package/corpus/templates/design/changelog/2026-07-29-choosing-edit-or-annotate-from-a-focused-screen-now-returns-.md +6 -0
  211. package/corpus/templates/design/changelog/2026-07-29-concurrent-source-edits-now-return-a-clear-conflict-response.md +6 -0
  212. package/corpus/templates/design/changelog/2026-07-29-creating-a-component-from-an-element-that-repeats-in-the-sou.md +6 -0
  213. package/corpus/templates/design/changelog/2026-07-29-deleting-an-element-you-just-dropped-onto-a-live-screen-no-l.md +6 -0
  214. package/corpus/templates/design/changelog/2026-07-29-dragging-a-layer-across-screens-no-longer-dies-when-the-poin.md +6 -0
  215. package/corpus/templates/design/changelog/2026-07-29-dragging-an-element-from-a-stored-screen-into-a-live-localho.md +6 -0
  216. package/corpus/templates/design/changelog/2026-07-29-drawing-a-box-on-the-canvas-and-dragging-it-into-a-connected.md +6 -0
  217. package/corpus/templates/design/changelog/2026-07-29-fixed-a-loading-screen-flicker-when-reopening-designs-with-a.md +6 -0
  218. package/corpus/templates/design/changelog/2026-07-29-interact-mode-has-edit-and-annotate-buttons-again-so-you-can.md +6 -0
  219. package/corpus/templates/design/changelog/2026-07-29-layer-groups-can-be-dropped-onto-live-localhost-screens.md +6 -0
  220. package/corpus/templates/design/changelog/2026-07-29-localhost-source-errors-now-say-what-actually-went-wrong-whi.md +6 -0
  221. package/corpus/templates/design/changelog/2026-07-29-opening-or-refreshing-a-live-localhost-screen-in-single-scre.md +6 -0
  222. package/corpus/templates/design/changelog/2026-07-29-redo-after-undoing-a-drop-onto-a-live-screen-puts-the-elemen.md +6 -0
  223. package/corpus/templates/design/changelog/2026-07-29-shapes-can-be-drawn-directly-onto-live-localhost-screens.md +6 -0
  224. package/corpus/templates/design/changelog/2026-07-29-shapes-drawn-on-the-canvas-board-now-appear-immediately-inst.md +6 -0
  225. package/corpus/templates/design/changelog/2026-07-29-style-edits-on-a-running-localhost-screen-now-preview-live-a.md +6 -0
  226. package/corpus/templates/design/changelog/2026-07-29-the-apply-design-updates-control-now-appears-as-a-clean-conn.md +6 -0
  227. package/corpus/templates/design/changelog/2026-07-29-visual-edits-on-a-mapped-component-instance-now-tell-the-age.md +6 -0
  228. package/corpus/templates/design/server/lib/design-data-access.ts +21 -7
  229. package/corpus/templates/design/server/lib/localhost-connection.ts +240 -0
  230. package/corpus/templates/design/server/routes/[...page].get.ts +2 -5
  231. package/corpus/templates/design/server/source-workspace.ts +2 -0
  232. package/corpus/templates/design/shared/code-layer.ts +43 -0
  233. package/corpus/templates/design/shared/html-content.ts +26 -0
  234. package/corpus/templates/design/shared/html-integrity.ts +21 -1
  235. package/corpus/templates/design/shared/local-jsx-visual-edit.ts +15 -0
  236. package/corpus/templates/design/shared/source-mode.ts +76 -0
  237. package/corpus/templates/dispatch/changelog/2026-07-29-workspace-members-without-admin-access-now-see-a-clear-permi.md +6 -0
  238. package/corpus/templates/dispatch/server/lib/usage-metrics.ts +2 -1
  239. package/corpus/templates/plan/app/lib/plan-annotation-runtime.ts +3 -4
  240. package/corpus/templates/plan/server/routes/[...page].get.ts +2 -5
  241. package/corpus/templates/slides/actions/patch-deck.ts +29 -17
  242. package/corpus/toolkit/CHANGELOG.md +6 -0
  243. package/corpus/toolkit/package.json +1 -1
  244. package/corpus/toolkit/src/composer/ComposerPlusMenu.tsx +3 -2
  245. package/dist/action-ui.d.ts +1 -0
  246. package/dist/action-ui.d.ts.map +1 -1
  247. package/dist/action-ui.js +1 -0
  248. package/dist/action-ui.js.map +1 -1
  249. package/dist/action.d.ts +5 -1
  250. package/dist/action.d.ts.map +1 -1
  251. package/dist/action.js.map +1 -1
  252. package/dist/agent/engine/ai-sdk-engine.d.ts.map +1 -1
  253. package/dist/agent/engine/ai-sdk-engine.js +13 -5
  254. package/dist/agent/engine/ai-sdk-engine.js.map +1 -1
  255. package/dist/agent/harness/runner.d.ts.map +1 -1
  256. package/dist/agent/harness/runner.js +5 -0
  257. package/dist/agent/harness/runner.js.map +1 -1
  258. package/dist/agent/production-agent.d.ts +16 -0
  259. package/dist/agent/production-agent.d.ts.map +1 -1
  260. package/dist/agent/production-agent.js +18 -1
  261. package/dist/agent/production-agent.js.map +1 -1
  262. package/dist/agent/run-loop-with-resume.d.ts.map +1 -1
  263. package/dist/agent/run-loop-with-resume.js +6 -0
  264. package/dist/agent/run-loop-with-resume.js.map +1 -1
  265. package/dist/agent/run-manager.d.ts +14 -0
  266. package/dist/agent/run-manager.d.ts.map +1 -1
  267. package/dist/agent/run-manager.js +91 -1
  268. package/dist/agent/run-manager.js.map +1 -1
  269. package/dist/agent/thread-data-builder.d.ts +3 -0
  270. package/dist/agent/thread-data-builder.d.ts.map +1 -1
  271. package/dist/agent/thread-data-builder.js +35 -3
  272. package/dist/agent/thread-data-builder.js.map +1 -1
  273. package/dist/agent/types.d.ts +2 -0
  274. package/dist/agent/types.d.ts.map +1 -1
  275. package/dist/agent/types.js.map +1 -1
  276. package/dist/chat-threads/store.d.ts.map +1 -1
  277. package/dist/chat-threads/store.js +4 -6
  278. package/dist/chat-threads/store.js.map +1 -1
  279. package/dist/cli/create.d.ts +66 -6
  280. package/dist/cli/create.d.ts.map +1 -1
  281. package/dist/cli/create.js +765 -66
  282. package/dist/cli/create.js.map +1 -1
  283. package/dist/cli/design-connect.d.ts.map +1 -1
  284. package/dist/cli/design-connect.js +2 -7
  285. package/dist/cli/design-connect.js.map +1 -1
  286. package/dist/cli/index.js +5 -3
  287. package/dist/cli/index.js.map +1 -1
  288. package/dist/cli/skills-content/design-visual-edit-skill.d.ts +1 -1
  289. package/dist/cli/skills-content/design-visual-edit-skill.d.ts.map +1 -1
  290. package/dist/cli/skills-content/design-visual-edit-skill.js +83 -47
  291. package/dist/cli/skills-content/design-visual-edit-skill.js.map +1 -1
  292. package/dist/client/AssistantChat.d.ts.map +1 -1
  293. package/dist/client/AssistantChat.js +16 -9
  294. package/dist/client/AssistantChat.js.map +1 -1
  295. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  296. package/dist/client/agent-chat-adapter.js +21 -0
  297. package/dist/client/agent-chat-adapter.js.map +1 -1
  298. package/dist/client/blocks/library/wireframe-kit.d.ts +2 -0
  299. package/dist/client/blocks/library/wireframe-kit.d.ts.map +1 -1
  300. package/dist/client/blocks/library/wireframe-kit.js +8 -2
  301. package/dist/client/blocks/library/wireframe-kit.js.map +1 -1
  302. package/dist/client/chat/index.d.ts +1 -1
  303. package/dist/client/chat/index.d.ts.map +1 -1
  304. package/dist/client/chat/index.js +1 -1
  305. package/dist/client/chat/index.js.map +1 -1
  306. package/dist/client/chat/message-components.d.ts +17 -0
  307. package/dist/client/chat/message-components.d.ts.map +1 -1
  308. package/dist/client/chat/message-components.js +24 -2
  309. package/dist/client/chat/message-components.js.map +1 -1
  310. package/dist/client/chat/run-recovery.d.ts +6 -0
  311. package/dist/client/chat/run-recovery.d.ts.map +1 -1
  312. package/dist/client/chat/run-recovery.js +13 -3
  313. package/dist/client/chat/run-recovery.js.map +1 -1
  314. package/dist/client/chat/widgets/DataTableWidget.d.ts.map +1 -1
  315. package/dist/client/chat/widgets/DataTableWidget.js +2 -3
  316. package/dist/client/chat/widgets/DataTableWidget.js.map +1 -1
  317. package/dist/client/chat/widgets/WorkspaceFileWidget.d.ts +5 -0
  318. package/dist/client/chat/widgets/WorkspaceFileWidget.d.ts.map +1 -0
  319. package/dist/client/chat/widgets/WorkspaceFileWidget.js +34 -0
  320. package/dist/client/chat/widgets/WorkspaceFileWidget.js.map +1 -0
  321. package/dist/client/chat/widgets/builtin-tool-renderers.d.ts.map +1 -1
  322. package/dist/client/chat/widgets/builtin-tool-renderers.js +13 -1
  323. package/dist/client/chat/widgets/builtin-tool-renderers.js.map +1 -1
  324. package/dist/client/chat/widgets/workspace-file-result.d.ts +12 -0
  325. package/dist/client/chat/widgets/workspace-file-result.d.ts.map +1 -0
  326. package/dist/client/chat/widgets/workspace-file-result.js +34 -0
  327. package/dist/client/chat/widgets/workspace-file-result.js.map +1 -0
  328. package/dist/client/embed-auth.d.ts.map +1 -1
  329. package/dist/client/embed-auth.js +2 -1
  330. package/dist/client/embed-auth.js.map +1 -1
  331. package/dist/client/org/InvitationBanner.d.ts +5 -2
  332. package/dist/client/org/InvitationBanner.d.ts.map +1 -1
  333. package/dist/client/org/InvitationBanner.js +9 -2
  334. package/dist/client/org/InvitationBanner.js.map +1 -1
  335. package/dist/client/org/OrgSwitcher.d.ts.map +1 -1
  336. package/dist/client/org/OrgSwitcher.js +3 -2
  337. package/dist/client/org/OrgSwitcher.js.map +1 -1
  338. package/dist/client/org/TeamPage.d.ts.map +1 -1
  339. package/dist/client/org/TeamPage.js +27 -3
  340. package/dist/client/org/TeamPage.js.map +1 -1
  341. package/dist/client/org/WorkspaceNotice.d.ts +18 -0
  342. package/dist/client/org/WorkspaceNotice.d.ts.map +1 -0
  343. package/dist/client/org/WorkspaceNotice.js +56 -0
  344. package/dist/client/org/WorkspaceNotice.js.map +1 -0
  345. package/dist/client/org/hooks.d.ts +1 -0
  346. package/dist/client/org/hooks.d.ts.map +1 -1
  347. package/dist/client/org/hooks.js +12 -0
  348. package/dist/client/org/hooks.js.map +1 -1
  349. package/dist/client/org/index.d.ts +2 -1
  350. package/dist/client/org/index.d.ts.map +1 -1
  351. package/dist/client/org/index.js +2 -1
  352. package/dist/client/org/index.js.map +1 -1
  353. package/dist/client/resources/McpIntegrationDialog.d.ts.map +1 -1
  354. package/dist/client/resources/McpIntegrationDialog.js +8 -12
  355. package/dist/client/resources/McpIntegrationDialog.js.map +1 -1
  356. package/dist/client/resources/ResourcesPanel.d.ts +3 -0
  357. package/dist/client/resources/ResourcesPanel.d.ts.map +1 -1
  358. package/dist/client/resources/ResourcesPanel.js +49 -20
  359. package/dist/client/resources/ResourcesPanel.js.map +1 -1
  360. package/dist/client/resources/mcp-integration-catalog.d.ts +1 -0
  361. package/dist/client/resources/mcp-integration-catalog.d.ts.map +1 -1
  362. package/dist/client/resources/mcp-integration-catalog.js +3 -0
  363. package/dist/client/resources/mcp-integration-catalog.js.map +1 -1
  364. package/dist/client/resources/use-resources.d.ts +1 -0
  365. package/dist/client/resources/use-resources.d.ts.map +1 -1
  366. package/dist/client/resources/use-resources.js +3 -0
  367. package/dist/client/resources/use-resources.js.map +1 -1
  368. package/dist/client/use-action.d.ts +3 -1
  369. package/dist/client/use-action.d.ts.map +1 -1
  370. package/dist/client/use-action.js +3 -1
  371. package/dist/client/use-action.js.map +1 -1
  372. package/dist/client/widgets/index.d.ts +1 -1
  373. package/dist/client/widgets/index.d.ts.map +1 -1
  374. package/dist/client/widgets/index.js +1 -1
  375. package/dist/client/widgets/index.js.map +1 -1
  376. package/dist/coding-tools/run-code.js +2 -1
  377. package/dist/coding-tools/run-code.js.map +1 -1
  378. package/dist/collab/awareness.d.ts +2 -2
  379. package/dist/collab/awareness.d.ts.map +1 -1
  380. package/dist/db/client.d.ts +1 -0
  381. package/dist/db/client.d.ts.map +1 -1
  382. package/dist/db/client.js +24 -3
  383. package/dist/db/client.js.map +1 -1
  384. package/dist/deploy/build.d.ts.map +1 -1
  385. package/dist/deploy/build.js +25 -3
  386. package/dist/deploy/build.js.map +1 -1
  387. package/dist/eject/remote-mcp-presets.js +1 -1
  388. package/dist/eject/remote-mcp-presets.js.map +1 -1
  389. package/dist/index.browser.d.ts +1 -1
  390. package/dist/index.browser.d.ts.map +1 -1
  391. package/dist/index.browser.js +1 -1
  392. package/dist/index.browser.js.map +1 -1
  393. package/dist/index.d.ts +1 -1
  394. package/dist/index.d.ts.map +1 -1
  395. package/dist/index.js +1 -1
  396. package/dist/index.js.map +1 -1
  397. package/dist/integrations/google-docs-poller.d.ts.map +1 -1
  398. package/dist/integrations/google-docs-poller.js +4 -1
  399. package/dist/integrations/google-docs-poller.js.map +1 -1
  400. package/dist/integrations/webhook-handler.d.ts.map +1 -1
  401. package/dist/integrations/webhook-handler.js +23 -11
  402. package/dist/integrations/webhook-handler.js.map +1 -1
  403. package/dist/jobs/scheduler.js +4 -0
  404. package/dist/jobs/scheduler.js.map +1 -1
  405. package/dist/localization/default-messages.d.ts +3 -2
  406. package/dist/localization/default-messages.d.ts.map +1 -1
  407. package/dist/localization/default-messages.js +3 -2
  408. package/dist/localization/default-messages.js.map +1 -1
  409. package/dist/notifications/routes.d.ts +1 -1
  410. package/dist/observability/routes.d.ts +3 -3
  411. package/dist/observability/traces.d.ts.map +1 -1
  412. package/dist/observability/traces.js +27 -7
  413. package/dist/observability/traces.js.map +1 -1
  414. package/dist/org/handlers.d.ts +15 -0
  415. package/dist/org/handlers.d.ts.map +1 -1
  416. package/dist/org/handlers.js +45 -1
  417. package/dist/org/handlers.js.map +1 -1
  418. package/dist/org/migrations.d.ts.map +1 -1
  419. package/dist/org/migrations.js +4 -0
  420. package/dist/org/migrations.js.map +1 -1
  421. package/dist/org/plugin.d.ts +1 -0
  422. package/dist/org/plugin.d.ts.map +1 -1
  423. package/dist/org/plugin.js +10 -1
  424. package/dist/org/plugin.js.map +1 -1
  425. package/dist/org/schema.d.ts +19 -0
  426. package/dist/org/schema.d.ts.map +1 -1
  427. package/dist/org/schema.js +1 -0
  428. package/dist/org/schema.js.map +1 -1
  429. package/dist/org/types.d.ts +8 -0
  430. package/dist/org/types.d.ts.map +1 -1
  431. package/dist/org/types.js.map +1 -1
  432. package/dist/org/workspace-url.d.ts +32 -0
  433. package/dist/org/workspace-url.d.ts.map +1 -0
  434. package/dist/org/workspace-url.js +63 -0
  435. package/dist/org/workspace-url.js.map +1 -0
  436. package/dist/progress/routes.d.ts +1 -1
  437. package/dist/provider-api/actions/custom-provider-registration.d.ts +11 -11
  438. package/dist/provider-api/actions/provider-api.d.ts +7 -7
  439. package/dist/resources/handlers.d.ts +2 -3
  440. package/dist/resources/handlers.d.ts.map +1 -1
  441. package/dist/resources/handlers.js +25 -5
  442. package/dist/resources/handlers.js.map +1 -1
  443. package/dist/scripts/runner.d.ts +17 -0
  444. package/dist/scripts/runner.d.ts.map +1 -1
  445. package/dist/scripts/runner.js +130 -5
  446. package/dist/scripts/runner.js.map +1 -1
  447. package/dist/server/action-routes.d.ts.map +1 -1
  448. package/dist/server/action-routes.js +24 -2
  449. package/dist/server/action-routes.js.map +1 -1
  450. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  451. package/dist/server/agent-chat-plugin.js +26 -1
  452. package/dist/server/agent-chat-plugin.js.map +1 -1
  453. package/dist/server/agent-teams.d.ts.map +1 -1
  454. package/dist/server/agent-teams.js +10 -1
  455. package/dist/server/agent-teams.js.map +1 -1
  456. package/dist/server/auth.d.ts +22 -0
  457. package/dist/server/auth.d.ts.map +1 -1
  458. package/dist/server/auth.js +33 -7
  459. package/dist/server/auth.js.map +1 -1
  460. package/dist/server/embed-route.d.ts.map +1 -1
  461. package/dist/server/embed-route.js +6 -1
  462. package/dist/server/embed-route.js.map +1 -1
  463. package/dist/server/embed-session.d.ts +7 -0
  464. package/dist/server/embed-session.d.ts.map +1 -1
  465. package/dist/server/embed-session.js +46 -4
  466. package/dist/server/embed-session.js.map +1 -1
  467. package/dist/server/open-route.d.ts.map +1 -1
  468. package/dist/server/open-route.js +17 -7
  469. package/dist/server/open-route.js.map +1 -1
  470. package/dist/server/prompts/framework-core-compact.js +1 -1
  471. package/dist/server/prompts/framework-core-compact.js.map +1 -1
  472. package/dist/server/prompts/framework-core.d.ts.map +1 -1
  473. package/dist/server/prompts/framework-core.js +1 -0
  474. package/dist/server/prompts/framework-core.js.map +1 -1
  475. package/dist/server/realtime-token.d.ts +1 -1
  476. package/dist/server/request-context.d.ts +26 -0
  477. package/dist/server/request-context.d.ts.map +1 -1
  478. package/dist/server/request-context.js +18 -1
  479. package/dist/server/request-context.js.map +1 -1
  480. package/dist/server/transcribe-voice.d.ts +1 -1
  481. package/dist/shared/embed-auth.d.ts +1 -0
  482. package/dist/shared/embed-auth.d.ts.map +1 -1
  483. package/dist/shared/embed-auth.js +1 -0
  484. package/dist/shared/embed-auth.js.map +1 -1
  485. package/dist/shared/html-document.d.ts +12 -0
  486. package/dist/shared/html-document.d.ts.map +1 -0
  487. package/dist/shared/html-document.js +92 -0
  488. package/dist/shared/html-document.js.map +1 -0
  489. package/dist/shared/index.d.ts +1 -0
  490. package/dist/shared/index.d.ts.map +1 -1
  491. package/dist/shared/index.js +1 -0
  492. package/dist/shared/index.js.map +1 -1
  493. package/dist/sharing/access.d.ts +1 -0
  494. package/dist/sharing/access.d.ts.map +1 -1
  495. package/dist/sharing/access.js +8 -2
  496. package/dist/sharing/access.js.map +1 -1
  497. package/dist/sharing/registry.d.ts +3 -0
  498. package/dist/sharing/registry.d.ts.map +1 -1
  499. package/dist/sharing/registry.js.map +1 -1
  500. package/dist/workspace-files/actions.d.ts +28 -0
  501. package/dist/workspace-files/actions.d.ts.map +1 -0
  502. package/dist/workspace-files/actions.js +75 -0
  503. package/dist/workspace-files/actions.js.map +1 -0
  504. package/dist/workspace-files/tool.d.ts.map +1 -1
  505. package/dist/workspace-files/tool.js +4 -0
  506. package/dist/workspace-files/tool.js.map +1 -1
  507. package/docs/content/cloneable-saas.mdx +114 -0
  508. package/docs/content/creating-templates.mdx +28 -2
  509. package/docs/content/syncing-template-changes.mdx +7 -0
  510. package/docs/content/template-clips-developers.mdx +12 -5
  511. package/docs/content/template-dispatch-developers.mdx +1 -1
  512. package/docs/content/template-dispatch.mdx +1 -1
  513. package/package.json +2 -2
  514. package/src/action-ui.ts +1 -0
  515. package/src/action.ts +5 -1
  516. package/src/agent/engine/ai-sdk-engine.ts +15 -5
  517. package/src/agent/harness/runner.ts +5 -0
  518. package/src/agent/production-agent.ts +33 -0
  519. package/src/agent/run-loop-with-resume.ts +5 -0
  520. package/src/agent/run-manager.ts +126 -1
  521. package/src/agent/thread-data-builder.ts +47 -2
  522. package/src/agent/types.ts +2 -0
  523. package/src/chat-threads/store.ts +4 -5
  524. package/src/cli/create.ts +1139 -65
  525. package/src/cli/design-connect.ts +3 -7
  526. package/src/cli/index.ts +5 -3
  527. package/src/cli/skills-content/design-visual-edit-skill.ts +83 -47
  528. package/src/client/AssistantChat.tsx +27 -16
  529. package/src/client/agent-chat-adapter.ts +24 -0
  530. package/src/client/blocks/library/wireframe-kit.tsx +17 -2
  531. package/src/client/chat/index.ts +1 -0
  532. package/src/client/chat/message-components.tsx +104 -1
  533. package/src/client/chat/run-recovery.tsx +15 -3
  534. package/src/client/chat/widgets/DataTableWidget.tsx +10 -29
  535. package/src/client/chat/widgets/WorkspaceFileWidget.tsx +71 -0
  536. package/src/client/chat/widgets/builtin-tool-renderers.tsx +22 -0
  537. package/src/client/chat/widgets/workspace-file-result.ts +49 -0
  538. package/src/client/embed-auth.ts +2 -0
  539. package/src/client/org/InvitationBanner.tsx +14 -1
  540. package/src/client/org/OrgSwitcher.tsx +23 -0
  541. package/src/client/org/TeamPage.tsx +130 -0
  542. package/src/client/org/WorkspaceNotice.tsx +85 -0
  543. package/src/client/org/hooks.ts +14 -0
  544. package/src/client/org/index.ts +2 -0
  545. package/src/client/resources/McpIntegrationDialog.tsx +27 -40
  546. package/src/client/resources/ResourcesPanel.tsx +134 -51
  547. package/src/client/resources/mcp-integration-catalog.ts +7 -0
  548. package/src/client/resources/use-resources.ts +6 -0
  549. package/src/client/use-action.ts +3 -1
  550. package/src/client/widgets/index.ts +1 -0
  551. package/src/coding-tools/run-code.ts +2 -1
  552. package/src/db/client.ts +28 -4
  553. package/src/deploy/build.ts +31 -3
  554. package/src/eject/remote-mcp-presets.ts +1 -1
  555. package/src/index.browser.ts +1 -0
  556. package/src/index.ts +1 -0
  557. package/src/integrations/google-docs-poller.ts +3 -0
  558. package/src/integrations/webhook-handler.ts +28 -11
  559. package/src/jobs/scheduler.ts +4 -0
  560. package/src/localization/default-messages.ts +3 -2
  561. package/src/observability/traces.ts +48 -12
  562. package/src/org/handlers.ts +52 -1
  563. package/src/org/migrations.ts +4 -0
  564. package/src/org/plugin.ts +14 -0
  565. package/src/org/schema.ts +1 -0
  566. package/src/org/types.ts +8 -0
  567. package/src/org/workspace-url.ts +74 -0
  568. package/src/resources/handlers.ts +35 -5
  569. package/src/scripts/runner.ts +183 -5
  570. package/src/server/__snapshots__/agent-chat-plugin.surface.spec.ts.snap +2 -1
  571. package/src/server/action-routes.ts +32 -2
  572. package/src/server/agent-chat-plugin.ts +29 -0
  573. package/src/server/agent-teams.ts +10 -1
  574. package/src/server/auth.ts +33 -7
  575. package/src/server/embed-route.ts +9 -0
  576. package/src/server/embed-session.ts +62 -3
  577. package/src/server/open-route.ts +20 -6
  578. package/src/server/prompts/framework-core-compact.ts +1 -1
  579. package/src/server/prompts/framework-core.ts +1 -0
  580. package/src/server/request-context.ts +36 -1
  581. package/src/shared/embed-auth.ts +1 -0
  582. package/src/shared/html-document.ts +115 -0
  583. package/src/shared/index.ts +1 -0
  584. package/src/sharing/access.ts +8 -1
  585. package/src/sharing/registry.ts +11 -2
  586. package/src/workspace-files/actions.ts +100 -0
  587. package/src/workspace-files/tool.ts +4 -0
  588. package/corpus/templates/design/changelog/2026-07-28-interact-mode-can-preview-designs-in-responsive-device-sizes.md +0 -6
  589. package/corpus/templates/design/changelog/2026-07-28-interact-mode-now-opens-a-full-screen-responsive-preview-wit.md +0 -6
@@ -35,7 +35,11 @@ import {
35
35
  appendDurableContinuationContext,
36
36
  runAgentLoopDirectWithSoftTimeout,
37
37
  } from "../agent/run-loop-with-resume.js";
38
- import { startRun, type ActiveRun } from "../agent/run-manager.js";
38
+ import {
39
+ startRun,
40
+ type ActiveRun,
41
+ type StartRunOptions,
42
+ } from "../agent/run-manager.js";
39
43
  import {
40
44
  buildCurrentTimeUserContext,
41
45
  buildRuntimeContextPrompt,
@@ -1211,6 +1215,26 @@ async function processIncomingMessage(
1211
1215
  let usage: Awaited<ReturnType<typeof runAgentLoop>> | null = null;
1212
1216
  let budgetsSettled = false;
1213
1217
 
1218
+ // Populated once `resolvedModel`/`engine` are known inside the run
1219
+ // callback below (stored-model + platform-default resolution can't happen
1220
+ // until then) and read back by run-manager's terminal tracking event via
1221
+ // this same object reference — `startRun` reads `options.model` only in
1222
+ // its `.finally()`, after this callback has settled, so the mutation is
1223
+ // guaranteed to land before it's read.
1224
+ const runOptions: StartRunOptions = {
1225
+ useHostedSoftTimeoutDefault: true,
1226
+ backgroundFunction: isInBackgroundFunctionRuntime(),
1227
+ ...(campaign
1228
+ ? {
1229
+ turnId: campaign.row.turnId,
1230
+ noProgressTimeoutMs: INTEGRATION_CAMPAIGN_NO_PROGRESS_TIMEOUT_MS,
1231
+ }
1232
+ : {}),
1233
+ // No userId here: `ownerEmail` is PII (email), which the terminal event
1234
+ // must not carry.
1235
+ attemptCount: opts.attempts,
1236
+ };
1237
+
1214
1238
  // Wait for the run to complete inside this fresh function execution.
1215
1239
  // We use a Promise so the processor endpoint can await the full lifecycle.
1216
1240
  return new Promise<ProcessIntegrationTaskResult>((resolve) => {
@@ -1283,6 +1307,8 @@ async function processIncomingMessage(
1283
1307
  engine,
1284
1308
  modelCandidate,
1285
1309
  );
1310
+ runOptions.model = resolvedModel;
1311
+ runOptions.engineName = engine.name;
1286
1312
 
1287
1313
  // Wrapper, not raw `runAgentLoop`: an integration turn has no
1288
1314
  // browser to re-POST a continuation, so a transport-level cut
@@ -1847,16 +1873,7 @@ async function processIncomingMessage(
1847
1873
  // chains) with no visible answer. `isInBackgroundFunctionRuntime()` is
1848
1874
  // the runtime proof — never a config guess — so the wider ceiling is
1849
1875
  // taken only where the ~60s synchronous wall genuinely does not apply.
1850
- {
1851
- useHostedSoftTimeoutDefault: true,
1852
- backgroundFunction: isInBackgroundFunctionRuntime(),
1853
- ...(campaign
1854
- ? {
1855
- turnId: campaign.row.turnId,
1856
- noProgressTimeoutMs: INTEGRATION_CAMPAIGN_NO_PROGRESS_TIMEOUT_MS,
1857
- }
1858
- : {}),
1859
- },
1876
+ runOptions,
1860
1877
  );
1861
1878
  });
1862
1879
  }
@@ -692,6 +692,10 @@ async function executeJob(
692
692
  // streams a job, so it gets reaped mid-flight.
693
693
  dispatchMode: "background",
694
694
  // turnId defaults to runId — fine for single-turn jobs
695
+ // No userId here: `jobUserEmail` is PII (email), which the
696
+ // terminal event must not carry.
697
+ model,
698
+ engineName: engine.name,
695
699
  },
696
700
  );
697
701
 
@@ -4,6 +4,9 @@
4
4
  // templates ship as verbatim copy-only scaffolding (.ts), so their compiled
5
5
  // .js never exists in dist.
6
6
  const messages = {
7
+ workspaceFile: {
8
+ download: "Download",
9
+ },
7
10
  home: {
8
11
  settingsTitle: "Settings",
9
12
  settingsDescription: "Language and agent preferences",
@@ -867,8 +870,6 @@ const messages = {
867
870
  "This provider usually requires an OAuth setup. Follow the provider docs, or add an Authorization header if your endpoint supports token-based access.",
868
871
  personal: "Personal",
869
872
  organization: "Organization",
870
- orgNoOrg: "Join an organization to share MCP servers",
871
- orgAdminOnly: "Only owners and admins can add org-scope servers",
872
873
  serverNameRequired: "Enter a server name before connecting with OAuth.",
873
874
  serverName: "Server name",
874
875
  url: "URL",
@@ -74,12 +74,25 @@ function emitLlmGenerationTrackingEvent(args: {
74
74
  llmSpanId: string;
75
75
  engineName: string | undefined;
76
76
  model: string;
77
- inputTokens: number;
78
- outputTokens: number;
79
- cacheReadTokens: number;
80
- cacheWriteTokens: number;
81
- costCentsX100: number;
77
+ /**
78
+ * Undefined means the engine never reported a usage figure for this run
79
+ * (e.g. killed for silence before any provider response arrived) — not
80
+ * that the count was zero. Callers must omit these from the emitted event
81
+ * rather than coerce to 0; a coerced 0 is indistinguishable from a real
82
+ * empty-input run and defeats analysis of failing runs by input size.
83
+ */
84
+ inputTokens: number | undefined;
85
+ outputTokens: number | undefined;
86
+ cacheReadTokens: number | undefined;
87
+ cacheWriteTokens: number | undefined;
88
+ /** Same "unknown vs zero" rule as the token fields — cost is derived from
89
+ * them and is equally unmeasurable when they were never reported. */
90
+ costCentsX100: number | undefined;
82
91
  durationMs: number;
92
+ /** Elapsed ms from run start to the first non-heartbeat engine event.
93
+ * Undefined when no such event ever arrived (the run never produced a
94
+ * token before being aborted) — never coerced to 0. */
95
+ firstTokenMs: number | undefined;
83
96
  status: "success" | "error";
84
97
  errorMessage: string | null;
85
98
  toolCalls: number;
@@ -102,7 +115,14 @@ function emitLlmGenerationTrackingEvent(args: {
102
115
  modelSelectionSource?: string;
103
116
  }): void {
104
117
  const provider = llmProviderFromEngine(args.engineName, args.model);
105
- const costUsd = costUsdFromCenticents(args.costCentsX100);
118
+ const costUsd =
119
+ args.costCentsX100 !== undefined
120
+ ? costUsdFromCenticents(args.costCentsX100)
121
+ : undefined;
122
+ const totalTokens =
123
+ args.inputTokens !== undefined && args.outputTokens !== undefined
124
+ ? args.inputTokens + args.outputTokens
125
+ : undefined;
106
126
  const error = args.errorMessage ?? undefined;
107
127
  const properties: Record<string, unknown> = {
108
128
  ...trackingIdentityProperties(),
@@ -116,12 +136,13 @@ function emitLlmGenerationTrackingEvent(args: {
116
136
  provider,
117
137
  input_tokens: args.inputTokens,
118
138
  output_tokens: args.outputTokens,
119
- total_tokens: args.inputTokens + args.outputTokens,
139
+ total_tokens: totalTokens,
120
140
  cache_read_tokens: args.cacheReadTokens,
121
141
  cache_write_tokens: args.cacheWriteTokens,
122
142
  cost_cents_x100: args.costCentsX100,
123
143
  cost_usd: costUsd,
124
144
  duration_ms: args.durationMs,
145
+ time_to_first_token_ms: args.firstTokenMs,
125
146
  status: args.status,
126
147
  tool_calls: args.toolCalls,
127
148
  successful_tools: args.successfulTools,
@@ -643,6 +664,16 @@ export async function instrumentAgentLoop(opts: {
643
664
  cacheWriteTokens: 0,
644
665
  model: loopOpts.model,
645
666
  };
667
+ // The engine never reported a `usage` event for this run (killed for
668
+ // silence before any provider response, or the loop threw before
669
+ // returning). `generationUsage`'s token fields are placeholder zeros in
670
+ // that case, not measured values — the tracking event below must omit
671
+ // them rather than report a fabricated 0.
672
+ const usageReported = usage?.usageReported === true;
673
+ const firstTokenMs =
674
+ usage?.firstEngineEventAtMs !== undefined
675
+ ? Math.max(0, usage.firstEngineEventAtMs - runStart)
676
+ : undefined;
646
677
  const llmSpanId = spanId();
647
678
  const llmSpan: TraceSpan = {
648
679
  id: llmSpanId,
@@ -675,12 +706,17 @@ export async function instrumentAgentLoop(opts: {
675
706
  ? loopOpts.engine.name
676
707
  : undefined,
677
708
  model: generationUsage.model,
678
- inputTokens: generationUsage.inputTokens,
679
- outputTokens: generationUsage.outputTokens,
680
- cacheReadTokens: generationUsage.cacheReadTokens,
681
- cacheWriteTokens: generationUsage.cacheWriteTokens,
682
- costCentsX100,
709
+ inputTokens: usageReported ? generationUsage.inputTokens : undefined,
710
+ outputTokens: usageReported ? generationUsage.outputTokens : undefined,
711
+ cacheReadTokens: usageReported
712
+ ? generationUsage.cacheReadTokens
713
+ : undefined,
714
+ cacheWriteTokens: usageReported
715
+ ? generationUsage.cacheWriteTokens
716
+ : undefined,
717
+ costCentsX100: usageReported ? costCentsX100 : undefined,
683
718
  durationMs: totalDurationMs,
719
+ firstTokenMs,
684
720
  status: runStatus,
685
721
  errorMessage,
686
722
  toolCalls: toolCallCount,
@@ -47,6 +47,7 @@ import { setActiveOrgId } from "./active-org.js";
47
47
  import { getOrgContext, createOrganization } from "./context.js";
48
48
  import { isFreeEmailProvider } from "./free-email-providers.js";
49
49
  import type { OrgRole } from "./types.js";
50
+ import { parseWorkspaceUrl } from "./workspace-url.js";
50
51
 
51
52
  function getInviteAppUrl(event: H3Event): string {
52
53
  return getAppProductionUrl(event);
@@ -108,16 +109,19 @@ export const getMyOrgHandler = defineEventHandler(async (event: H3Event) => {
108
109
  }
109
110
 
110
111
  let allowedDomain: string | null = null;
112
+ let workspaceUrl: string | null = null;
111
113
  let a2aSecretSet = false;
112
114
  if (ctx.orgId) {
113
115
  try {
114
116
  const adRes = await e.execute({
115
- sql: `SELECT allowed_domain, a2a_secret FROM organizations WHERE id = ? LIMIT 1`,
117
+ sql: `SELECT allowed_domain, a2a_secret, workspace_url FROM organizations WHERE id = ? LIMIT 1`,
116
118
  args: [ctx.orgId],
117
119
  });
118
120
  if (adRes.rows[0]) {
119
121
  allowedDomain =
120
122
  String((adRes.rows[0] as any).allowed_domain ?? "") || null;
123
+ workspaceUrl =
124
+ String((adRes.rows[0] as any).workspace_url ?? "") || null;
121
125
  a2aSecretSet = Boolean(
122
126
  String((adRes.rows[0] as any).a2a_secret ?? "").trim(),
123
127
  );
@@ -156,6 +160,7 @@ export const getMyOrgHandler = defineEventHandler(async (event: H3Event) => {
156
160
  pendingInvitations,
157
161
  domainMatches,
158
162
  allowedDomain,
163
+ workspaceUrl,
159
164
  // Never serialize the A2A secret here. This route runs on every page load,
160
165
  // so the value would sit in JSON any script on the page can read, and it
161
166
  // signs the JWTs peers accept as first-party callers. Reveal is an explicit
@@ -954,6 +959,52 @@ export const setDomainHandler = defineEventHandler(async (event: H3Event) => {
954
959
  return { domain: raw };
955
960
  });
956
961
 
962
+ /**
963
+ * PUT /_agent-native/org/workspace-url — set or clear the org's own workspace
964
+ * origin (owner/admin only).
965
+ *
966
+ * Members who reach a shared hosted app from the template catalog land in a
967
+ * different deployment than their team's workspace, with the same org name in
968
+ * the switcher, and read the empty app as broken rather than as somewhere
969
+ * else. Setting this points them home from wherever they land.
970
+ *
971
+ * Body: { url: string | null } — a full URL or bare host; stored as an origin.
972
+ */
973
+ export const setWorkspaceUrlHandler = defineEventHandler(
974
+ async (event: H3Event) => {
975
+ const ctx = await getOrgContext(event);
976
+ if (!ctx.orgId) {
977
+ throw createError({ statusCode: 400, message: "No active organization" });
978
+ }
979
+ if (ctx.role !== "owner" && ctx.role !== "admin") {
980
+ throw createError({
981
+ statusCode: 403,
982
+ message: "Only owners and admins can set the workspace URL",
983
+ });
984
+ }
985
+
986
+ const body = await readBody(event);
987
+ const raw = typeof body?.url === "string" ? body.url.trim() : "";
988
+
989
+ let workspaceUrl: string | null = null;
990
+ if (raw) {
991
+ const parsed = parseWorkspaceUrl(raw);
992
+ if (!parsed.ok) {
993
+ throw createError({ statusCode: 400, message: parsed.reason });
994
+ }
995
+ workspaceUrl = parsed.url;
996
+ }
997
+
998
+ const e = await exec();
999
+ await e.execute({
1000
+ sql: `UPDATE organizations SET workspace_url = ? WHERE id = ?`,
1001
+ args: [workspaceUrl, ctx.orgId],
1002
+ });
1003
+
1004
+ return { url: workspaceUrl };
1005
+ },
1006
+ );
1007
+
957
1008
  /**
958
1009
  * GET /_agent-native/org/a2a-secret — reveal the org's A2A secret
959
1010
  * (owner/admin only). Separate from `/org/me` so the secret is only ever sent
@@ -124,4 +124,8 @@ export const ORG_MIGRATIONS = [
124
124
  sql: `CREATE UNIQUE INDEX IF NOT EXISTS app_member_roles_org_app_lower_email_uidx
125
125
  ON app_member_roles (org_id, app_id, LOWER(email))`,
126
126
  },
127
+ {
128
+ version: 1013,
129
+ sql: `ALTER TABLE organizations ADD COLUMN IF NOT EXISTS workspace_url TEXT`,
130
+ },
127
131
  ];
@@ -31,6 +31,7 @@ import {
31
31
  acceptInvitationHandler,
32
32
  joinByDomainHandler,
33
33
  setDomainHandler,
34
+ setWorkspaceUrlHandler,
34
35
  revealA2ASecretHandler,
35
36
  setA2ASecretHandler,
36
37
  syncA2ASecretHandler,
@@ -61,6 +62,7 @@ const ORG_PREFIX = `${FRAMEWORK_PREFIX}/org`;
61
62
  * POST /_agent-native/org/invitations/:id/accept — accept an invitation
62
63
  * POST /_agent-native/org/join-by-domain — join org via email domain match
63
64
  * PUT /_agent-native/org/domain — set/clear allowed email domain (owner/admin)
65
+ * PUT /_agent-native/org/workspace-url — set/clear the org's workspace origin (owner/admin)
64
66
  * GET /_agent-native/org/a2a-secret — reveal A2A secret on demand (owner/admin)
65
67
  * PUT /_agent-native/org/a2a-secret — regenerate or set A2A secret (owner/admin)
66
68
  * POST /_agent-native/org/a2a-secret/sync — push secret to all connected apps (owner/admin)
@@ -251,6 +253,18 @@ export function createOrgPlugin(): NitroPluginDef {
251
253
  }),
252
254
  );
253
255
 
256
+ // PUT /workspace-url
257
+ app.use(
258
+ `${ORG_PREFIX}/workspace-url`,
259
+ defineEventHandler(async (event: H3Event) => {
260
+ if (getMethod(event) !== "PUT") {
261
+ setResponseStatus(event, 405);
262
+ return { error: "Method not allowed" };
263
+ }
264
+ return setWorkspaceUrlHandler(event);
265
+ }),
266
+ );
267
+
254
268
  // PUT /switch
255
269
  app.use(
256
270
  `${ORG_PREFIX}/switch`,
@@ -7,6 +7,7 @@ export const organizations = table("organizations", {
7
7
  createdAt: integer("created_at").notNull(),
8
8
  allowedDomain: text("allowed_domain"),
9
9
  a2aSecret: text("a2a_secret"),
10
+ workspaceUrl: text("workspace_url"),
10
11
  });
11
12
 
12
13
  export const orgMembers = table("org_members", {
@@ -38,6 +38,14 @@ export interface OrgInfo {
38
38
  pendingInvitations: OrgInvitationSummary[];
39
39
  domainMatches: DomainMatchOrg[];
40
40
  allowedDomain: string | null;
41
+ /**
42
+ * Origin of the org's own workspace deployment, when it runs one. Members
43
+ * who land on a different host (a shared hosted app reached from the
44
+ * template catalog) get pointed here instead of concluding their team's
45
+ * apps are missing. Null for the common case of an org with no separate
46
+ * workspace.
47
+ */
48
+ workspaceUrl: string | null;
41
49
  /**
42
50
  * Whether the active org has an A2A secret. The value itself is never part
43
51
  * of this payload — owners/admins fetch it on demand from
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Parsing and comparison for `organizations.workspace_url` — the origin of an
3
+ * org's own workspace deployment.
4
+ *
5
+ * The value is set by an owner/admin and then rendered as a link target for
6
+ * every member of the org, so it is parsed at the trust boundary rather than
7
+ * on the way out: anything that is not an `http(s)` origin never reaches the
8
+ * database.
9
+ */
10
+
11
+ export type ParsedWorkspaceUrl =
12
+ | { ok: true; url: string }
13
+ | { ok: false; reason: string };
14
+
15
+ /**
16
+ * Normalize a workspace URL to a bare origin (`https://host[:port]`).
17
+ *
18
+ * Path, query, and hash are dropped: this points at a deployment, not a page,
19
+ * and keeping them would send members to a route that may not exist in the
20
+ * app they arrive at.
21
+ */
22
+ export function parseWorkspaceUrl(raw: string): ParsedWorkspaceUrl {
23
+ const trimmed = raw.trim();
24
+ if (!trimmed) {
25
+ return { ok: false, reason: "Workspace URL is empty" };
26
+ }
27
+
28
+ // Accept a bare host ("agent-workspace.builder.io") the way a browser bar
29
+ // does — otherwise the most natural thing to paste is rejected.
30
+ const withScheme = /^[a-z][a-z0-9+.-]*:\/\//i.test(trimmed)
31
+ ? trimmed
32
+ : `https://${trimmed}`;
33
+
34
+ let parsed: URL;
35
+ try {
36
+ parsed = new URL(withScheme);
37
+ } catch {
38
+ return { ok: false, reason: "Not a valid URL" };
39
+ }
40
+
41
+ if (parsed.protocol !== "https:" && parsed.protocol !== "http:") {
42
+ return { ok: false, reason: "Workspace URL must be http or https" };
43
+ }
44
+ if (!parsed.hostname.includes(".") && parsed.hostname !== "localhost") {
45
+ return { ok: false, reason: "Workspace URL must include a full hostname" };
46
+ }
47
+
48
+ return { ok: true, url: parsed.origin };
49
+ }
50
+
51
+ /**
52
+ * Whether a member currently on `currentUrl` should be pointed at the org's
53
+ * workspace. False when the org has no workspace, when the stored value is
54
+ * unusable, or when they are already on it — including any subdomain-free
55
+ * port/scheme difference, which `URL.origin` compares exactly.
56
+ */
57
+ export function shouldOfferWorkspace(
58
+ currentUrl: string,
59
+ workspaceUrl: string | null | undefined,
60
+ ): boolean {
61
+ if (!workspaceUrl) return false;
62
+
63
+ const parsed = parseWorkspaceUrl(workspaceUrl);
64
+ if (!parsed.ok) return false;
65
+
66
+ let currentOrigin: string;
67
+ try {
68
+ currentOrigin = new URL(currentUrl).origin;
69
+ } catch {
70
+ return false;
71
+ }
72
+
73
+ return currentOrigin !== parsed.url;
74
+ }
@@ -72,6 +72,28 @@ function canReadOwner(
72
72
  );
73
73
  }
74
74
 
75
+ function resourceDownloadDisposition(path: string): string {
76
+ const basename = path.replaceAll("\\", "/").split("/").pop()?.trim() || "";
77
+ const filename = Array.from(basename)
78
+ .slice(0, 180)
79
+ .map((character) => {
80
+ const codePoint = character.codePointAt(0) ?? 0;
81
+ return codePoint <= 31 || codePoint === 127 ? "_" : character;
82
+ })
83
+ .join("");
84
+ const safeFilename =
85
+ filename && filename !== "." && filename !== ".." ? filename : "download";
86
+ const asciiFilename = safeFilename
87
+ .replace(/[^\x20-\x7e]/g, "_")
88
+ .replace(/["\\]/g, "_");
89
+ const encodedFilename = encodeURIComponent(safeFilename).replace(
90
+ /['()*]/g,
91
+ (character) => `%${character.charCodeAt(0).toString(16).toUpperCase()}`,
92
+ );
93
+
94
+ return `attachment; filename="${asciiFilename}"; filename*=UTF-8''${encodedFilename}`;
95
+ }
96
+
75
97
  function mergeScopedResources(
76
98
  primary: ResourceMeta[],
77
99
  inherited: ResourceMeta[],
@@ -398,9 +420,8 @@ async function enrichTreeNodes(nodes: TreeNode[]): Promise<void> {
398
420
  }
399
421
 
400
422
  /** GET /_agent-native/resources/:id — get single resource with content.
401
- * If the request comes from an <img>/<video>/etc tag (Accept includes the
402
- * resource's mime type, or query param `?raw` is set), return the raw binary
403
- * with the correct Content-Type so the browser can render it inline. */
423
+ * `?raw` returns the bytes inline; `?download=1` returns the same bytes as a
424
+ * safe attachment. */
404
425
  export async function handleGetResource(event: any) {
405
426
  const id = getRouterParam(event, "id") || event.context.params?.id;
406
427
  if (!id) {
@@ -421,11 +442,11 @@ export async function handleGetResource(event: any) {
421
442
  return { error: "Resource not found" };
422
443
  }
423
444
 
424
- // Serve raw binary when ?raw query param is set (used by <img> tags etc.)
425
445
  const query = getQuery(event);
426
446
  const wantsRaw = query.raw !== undefined;
447
+ const wantsDownload = query.download === "1";
427
448
 
428
- if (wantsRaw && resource.content) {
449
+ if ((wantsRaw || wantsDownload) && typeof resource.content === "string") {
429
450
  const isText =
430
451
  resource.mimeType.startsWith("text/") ||
431
452
  resource.mimeType === "application/json";
@@ -435,6 +456,15 @@ export async function handleGetResource(event: any) {
435
456
 
436
457
  setResponseHeader(event, "Content-Type", resource.mimeType);
437
458
  setResponseHeader(event, "Content-Length", String(buf.length));
459
+ setResponseHeader(event, "Cache-Control", "private, no-store");
460
+ setResponseHeader(event, "X-Content-Type-Options", "nosniff");
461
+ if (wantsDownload) {
462
+ setResponseHeader(
463
+ event,
464
+ "Content-Disposition",
465
+ resourceDownloadDisposition(resource.path),
466
+ );
467
+ }
438
468
  return new Response(buf);
439
469
  }
440
470