@agent-native/core 0.80.2 → 0.80.5

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 (322) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +66 -2
  3. package/corpus/core/docs/content/locales/ar-SA/real-time-collaboration.mdx +2 -2
  4. package/corpus/core/docs/content/locales/ar-SA/template-design.mdx +1 -1
  5. package/corpus/core/docs/content/locales/de-DE/real-time-collaboration.mdx +3 -3
  6. package/corpus/core/docs/content/locales/de-DE/template-design.mdx +1 -1
  7. package/corpus/core/docs/content/locales/es-ES/real-time-collaboration.mdx +2 -2
  8. package/corpus/core/docs/content/locales/es-ES/template-design.mdx +1 -1
  9. package/corpus/core/docs/content/locales/fr-FR/real-time-collaboration.mdx +2 -2
  10. package/corpus/core/docs/content/locales/fr-FR/template-design.mdx +1 -1
  11. package/corpus/core/docs/content/locales/hi-IN/template-design.mdx +1 -1
  12. package/corpus/core/docs/content/locales/ja-JP/real-time-collaboration.mdx +2 -2
  13. package/corpus/core/docs/content/locales/ja-JP/template-design.mdx +1 -1
  14. package/corpus/core/docs/content/locales/ko-KR/real-time-collaboration.mdx +2 -2
  15. package/corpus/core/docs/content/locales/ko-KR/template-design.mdx +1 -1
  16. package/corpus/core/docs/content/locales/pt-BR/real-time-collaboration.mdx +2 -2
  17. package/corpus/core/docs/content/locales/pt-BR/template-design.mdx +1 -1
  18. package/corpus/core/docs/content/locales/zh-CN/real-time-collaboration.mdx +2 -2
  19. package/corpus/core/docs/content/locales/zh-CN/template-design.mdx +1 -1
  20. package/corpus/core/docs/content/locales/zh-TW/real-time-collaboration.mdx +2 -2
  21. package/corpus/core/docs/content/locales/zh-TW/template-design.mdx +1 -1
  22. package/corpus/core/docs/content/real-time-collaboration.mdx +2 -2
  23. package/corpus/core/docs/content/template-design.mdx +1 -1
  24. package/corpus/core/package.json +3 -7
  25. package/corpus/core/src/action.ts +32 -0
  26. package/corpus/core/src/agent/durable-background.ts +32 -11
  27. package/corpus/core/src/agent/production-agent.ts +14 -1
  28. package/corpus/core/src/agent/run-loop-with-resume.ts +3 -1
  29. package/corpus/core/src/brand-kit/fig/index.ts +17 -37
  30. package/corpus/core/src/cli/index.ts +1 -1
  31. package/corpus/core/src/cli/mcp-config-writers.ts +187 -51
  32. package/corpus/core/src/cli/plan-local.ts +445 -108
  33. package/corpus/core/src/cli/skills.ts +32 -8
  34. package/corpus/core/src/client/AssistantChat.tsx +11 -1
  35. package/corpus/core/src/client/agent-chat.ts +12 -1
  36. package/corpus/core/src/client/composer/PromptComposer.tsx +100 -41
  37. package/corpus/core/src/client/org/OrgSwitcher.tsx +1 -1
  38. package/corpus/core/src/client/sharing/ShareButton.tsx +3 -27
  39. package/corpus/core/src/collab/presence.ts +1 -1
  40. package/corpus/core/src/mcp/connect-route.ts +34 -5
  41. package/corpus/core/src/server/action-discovery.ts +4 -0
  42. package/corpus/core/src/server/action-routes.ts +14 -0
  43. package/corpus/core/src/server/agent-chat-plugin.ts +20 -0
  44. package/corpus/core/src/vite/client.ts +15 -1
  45. package/corpus/templates/analytics/actions/dashboard-mutation-api.ts +2 -0
  46. package/corpus/templates/analytics/actions/update-dashboard.ts +8 -0
  47. package/corpus/templates/analytics/app/components/layout/Layout.tsx +1 -1
  48. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +117 -33
  49. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +4 -0
  50. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/types.ts +7 -0
  51. package/corpus/templates/analytics/changelog/2026-06-27-dashboards-can-now-nest-under-a-parent-in-the-sidebar-via-a-.md +6 -0
  52. package/corpus/templates/analytics/changelog/2026-06-29-analytics-pages-now-sit-closer-under-the-header-with-tighter.md +6 -0
  53. package/corpus/templates/assets/actions/generate-image-batch.ts +3 -0
  54. package/corpus/templates/assets/actions/generate-image.ts +3 -0
  55. package/corpus/templates/assets/changelog/2026-06-29-longer-agent-generation-window.md +6 -0
  56. package/corpus/templates/assets/netlify.toml +3 -3
  57. package/corpus/templates/assets/server/plugins/agent-chat.ts +4 -1
  58. package/corpus/templates/clips/app/components/capture-install-options.tsx +7 -8
  59. package/corpus/templates/clips/app/components/player/timestamped-comment-button.tsx +162 -0
  60. package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +1 -1
  61. package/corpus/templates/clips/app/i18n/ar-SA.ts +4 -0
  62. package/corpus/templates/clips/app/i18n/de-DE.ts +4 -0
  63. package/corpus/templates/clips/app/i18n/en-US.ts +4 -0
  64. package/corpus/templates/clips/app/i18n/es-ES.ts +4 -0
  65. package/corpus/templates/clips/app/i18n/fr-FR.ts +4 -0
  66. package/corpus/templates/clips/app/i18n/hi-IN.ts +4 -0
  67. package/corpus/templates/clips/app/i18n/ja-JP.ts +4 -0
  68. package/corpus/templates/clips/app/i18n/ko-KR.ts +4 -0
  69. package/corpus/templates/clips/app/i18n/pt-BR.ts +4 -0
  70. package/corpus/templates/clips/app/i18n/zh-CN.ts +4 -0
  71. package/corpus/templates/clips/app/i18n/zh-TW.ts +4 -0
  72. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +42 -18
  73. package/corpus/templates/content/AGENTS.md +12 -0
  74. package/corpus/templates/content/app/blocks/BuilderDocsBlocks.tsx +10 -0
  75. package/corpus/templates/content/app/components/editor/BubbleToolbar.tsx +1 -0
  76. package/corpus/templates/content/app/components/editor/ContentReferencePreview.tsx +185 -0
  77. package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +3 -0
  78. package/corpus/templates/content/app/components/editor/VisualEditor.tsx +19 -0
  79. package/corpus/templates/content/app/components/editor/extensions/ContentReferenceNode.tsx +82 -0
  80. package/corpus/templates/content/app/global.css +9 -0
  81. package/corpus/templates/content/app/i18n/zh-TW.ts +12 -0
  82. package/corpus/templates/content/app/i18n-data.ts +140 -0
  83. package/corpus/templates/content/changelog/2026-06-29-reusable-mdx-references-now-preview-linked-local-documents-i.md +6 -0
  84. package/corpus/templates/content/shared/builder-docs-blocks.ts +8 -0
  85. package/corpus/templates/content/shared/builder-mdx.ts +141 -4
  86. package/corpus/templates/content/shared/nfm.ts +62 -0
  87. package/corpus/templates/design/.agents/skills/design-systems/SKILL.md +10 -11
  88. package/corpus/templates/design/AGENTS.md +5 -0
  89. package/corpus/templates/design/_gitignore +7 -0
  90. package/corpus/templates/design/actions/apply-visual-edit.ts +22 -12
  91. package/corpus/templates/design/actions/create-design-system.ts +15 -4
  92. package/corpus/templates/design/actions/create-file.ts +20 -1
  93. package/corpus/templates/design/actions/delete-design-system.ts +2 -2
  94. package/corpus/templates/design/actions/duplicate-design.ts +35 -9
  95. package/corpus/templates/design/actions/generate-design.ts +146 -69
  96. package/corpus/templates/design/actions/generate-screens.ts +51 -19
  97. package/corpus/templates/design/actions/get-design-snapshot.ts +5 -1
  98. package/corpus/templates/design/actions/get-design.ts +2 -0
  99. package/corpus/templates/design/actions/import-design-project.ts +28 -9
  100. package/corpus/templates/design/actions/import-document.ts +22 -8
  101. package/corpus/templates/design/actions/index-design-system-with-builder.ts +6 -153
  102. package/corpus/templates/design/actions/navigate.ts +105 -54
  103. package/corpus/templates/design/actions/set-default-design-system.ts +17 -3
  104. package/corpus/templates/design/actions/show-design-questions.ts +2 -0
  105. package/corpus/templates/design/actions/update-design.ts +2 -1
  106. package/corpus/templates/design/actions/view-screen.ts +12 -6
  107. package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +4 -4
  108. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +159 -41
  109. package/corpus/templates/design/app/components/design/DesignExtensionsPanel.tsx +8 -4
  110. package/corpus/templates/design/app/components/design/DrawOverlay.tsx +37 -42
  111. package/corpus/templates/design/app/components/design/EditPanel.tsx +336 -183
  112. package/corpus/templates/design/app/components/design/LayersPanel.tsx +153 -34
  113. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +135 -33
  114. package/corpus/templates/design/app/components/design/QuestionFlow.tsx +6 -0
  115. package/corpus/templates/design/app/components/design/TweaksPanel.tsx +2 -1
  116. package/corpus/templates/design/app/components/design/inspector/AlignmentMatrix.tsx +4 -10
  117. package/corpus/templates/design/app/components/design/inspector/AutoLayoutMatrix.tsx +84 -43
  118. package/corpus/templates/design/app/components/design/inspector/ConstraintsWidget.tsx +4 -4
  119. package/corpus/templates/design/app/components/design/inspector/{FigmaColorPicker.tsx → DesignColorPicker.tsx} +89 -62
  120. package/corpus/templates/design/app/components/design/inspector/ExportSettingsPanel.tsx +14 -26
  121. package/corpus/templates/design/app/components/design/inspector/GradientEditor.tsx +40 -12
  122. package/corpus/templates/design/app/components/design/inspector/ImageFillControls.tsx +13 -4
  123. package/corpus/templates/design/app/components/design/inspector/SHADER_INTEGRATION.md +13 -13
  124. package/corpus/templates/design/app/components/design/inspector/ScrubInput.tsx +13 -9
  125. package/corpus/templates/design/app/components/design/inspector/ShaderControls.tsx +13 -4
  126. package/corpus/templates/design/app/components/design/inspector/ShaderFillsPanel.tsx +6 -6
  127. package/corpus/templates/design/app/components/design/inspector/{figma-icons.tsx → design-icons.tsx} +2 -2
  128. package/corpus/templates/design/app/components/design/inspector/index.ts +12 -12
  129. package/corpus/templates/design/app/components/design/inspector/scrub-input-utils.ts +5 -2
  130. package/corpus/templates/design/app/components/editor/PromptDialog.tsx +3 -3
  131. package/corpus/templates/design/app/components/layout/Layout.tsx +5 -2
  132. package/corpus/templates/design/app/components/layout/Sidebar.tsx +1 -1
  133. package/corpus/templates/design/app/components/visual-editor/CanvasCommentPins.tsx +167 -91
  134. package/corpus/templates/design/app/components/visual-editor/DrawOverlay.tsx +16 -3
  135. package/corpus/templates/design/app/components/visual-editor/SaveStatusIndicator.tsx +15 -0
  136. package/corpus/templates/design/app/global.css +4 -0
  137. package/corpus/templates/design/app/hooks/use-design-system.ts +4 -1
  138. package/corpus/templates/design/app/hooks/use-navigation-state.ts +38 -3
  139. package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +9 -2
  140. package/corpus/templates/design/app/i18n/zh-TW.ts +22 -0
  141. package/corpus/templates/design/app/i18n-data.ts +527 -0
  142. package/corpus/templates/design/app/lib/design-systems.ts +6 -4
  143. package/corpus/templates/design/app/lib/design-templates.ts +15 -3
  144. package/corpus/templates/design/app/pages/DesignEditor.tsx +641 -158
  145. package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +42 -34
  146. package/corpus/templates/design/app/pages/VisualEdit.tsx +100 -0
  147. package/corpus/templates/design/app/root.tsx +42 -9
  148. package/corpus/templates/design/app/routes/visual-edit.tsx +7 -0
  149. package/corpus/templates/design/changelog/2026-06-28-live-cursors-now-keep-names-beside-a-cleaner-pointer-marker.md +1 -1
  150. package/corpus/templates/design/changelog/2026-06-28-mode-switching-now-lives-in-a-compact-bottom-right-icon-dock.md +1 -1
  151. package/corpus/templates/design/changelog/2026-06-28-visual-code-design-mode.md +6 -0
  152. package/corpus/templates/design/changelog/2026-06-29-design-generation-prompts-now-show-connect-ai-before-sending.md +6 -0
  153. package/corpus/templates/design/changelog/2026-06-29-design-mode-top-chrome-now-groups-collaborators-preview-shar.md +1 -1
  154. package/corpus/templates/design/changelog/2026-06-29-fixed-design-editor-exports-and-gradient-edits-so-multi-scre.md +6 -0
  155. package/corpus/templates/design/changelog/2026-06-29-longer-hosted-agent-turns.md +6 -0
  156. package/corpus/templates/design/changelog/2026-06-29-png-export-handles-modern-css-color-functions-more-reliably.md +6 -0
  157. package/corpus/templates/design/changelog/2026-06-29-png-export-now-ignores-duplicate-clicks-while-a-download-is-.md +6 -0
  158. package/corpus/templates/design/changelog/2026-06-29-public-visual-edit-and-shared-design-links-now-invite-visito.md +6 -0
  159. package/corpus/templates/design/changelog/2026-06-29-visual-edit-actions-now-reject-missing-design-targets-before.md +6 -0
  160. package/corpus/templates/design/e2e/README.md +71 -0
  161. package/corpus/templates/design/e2e/global-setup.ts +157 -0
  162. package/corpus/templates/design/e2e/helpers.ts +148 -0
  163. package/corpus/templates/design/netlify.toml +3 -4
  164. package/corpus/templates/design/package.json +5 -1
  165. package/corpus/templates/design/playwright.config.ts +51 -0
  166. package/corpus/templates/design/server/handlers/index-design-system-with-builder.ts +121 -0
  167. package/corpus/templates/design/server/handlers/uploads.ts +89 -38
  168. package/corpus/templates/design/server/lib/builder-design-system-proxy.ts +181 -0
  169. package/corpus/templates/design/server/lib/coding-handoff.ts +33 -4
  170. package/corpus/templates/design/server/lib/design-export.ts +35 -8
  171. package/corpus/templates/design/server/plugins/agent-chat.ts +4 -0
  172. package/corpus/templates/design/server/plugins/auth.ts +10 -1
  173. package/corpus/templates/design/server/routes/api/index-design-system-with-builder.post.ts +1 -0
  174. package/corpus/templates/design/shared/api.ts +2 -0
  175. package/corpus/templates/design/shared/apply-edits.ts +12 -8
  176. package/corpus/templates/design/shared/canvas-math.ts +19 -1
  177. package/corpus/templates/design/shared/code-layer.ts +87 -28
  178. package/corpus/templates/design/shared/generation-session.ts +1 -0
  179. package/corpus/templates/design/shared/resolve-tweaks.ts +4 -3
  180. package/corpus/templates/design/shared/shader-presets.ts +10 -0
  181. package/corpus/templates/design/shared/source-mode.ts +9 -0
  182. package/corpus/templates/design/vitest.config.ts +2 -1
  183. package/corpus/templates/mail/app/components/layout/AppLayout.tsx +1 -1
  184. package/corpus/templates/plan/.agents/skills/visual-plan/references/canvas.md +1 -1
  185. package/corpus/templates/plan/.agents/skills/visual-plan/references/local-files.md +14 -5
  186. package/corpus/templates/plan/.agents/skills/visual-recap/references/local-files.md +14 -5
  187. package/corpus/templates/plan/AGENTS.md +1 -1
  188. package/corpus/templates/plan/actions/create-plan-design.ts +1 -1
  189. package/corpus/templates/plan/actions/validate-local-plan-source.ts +110 -0
  190. package/corpus/templates/plan/app/pages/PlansPage.tsx +1 -0
  191. package/corpus/templates/plan/docs/commenting-ux-plan.md +2 -2
  192. package/corpus/templates/plan/server/lib/plan-connector-catalog.ts +1 -0
  193. package/corpus/templates/plan/server/lib/public-action-paths.ts +1 -0
  194. package/corpus/templates/plan/server/plan-content.ts +1 -1
  195. package/corpus/templates/plan/server/ui-plan-html.ts +2 -2
  196. package/corpus/templates/slides/actions/index-design-system-with-builder.ts +6 -153
  197. package/corpus/templates/slides/app/components/design-system/DesignSystemSetup.tsx +53 -38
  198. package/corpus/templates/slides/app/components/design-system/{fig-import-response.ts → builder-index-response.ts} +9 -6
  199. package/corpus/templates/slides/app/components/visual-editor/MultiSelectChip.tsx +1 -1
  200. package/corpus/templates/slides/changelog/2026-06-29-design-system-setup-now-indexes-uploaded-design-files-throug.md +6 -0
  201. package/corpus/templates/slides/changelog/2026-06-29-longer-hosted-agent-turns.md +6 -0
  202. package/corpus/templates/slides/netlify.toml +3 -6
  203. package/corpus/templates/slides/server/handlers/index-design-system-with-builder.ts +116 -0
  204. package/corpus/templates/slides/server/lib/builder-design-system-proxy.ts +179 -0
  205. package/corpus/templates/slides/server/plugins/agent-chat.ts +4 -1
  206. package/corpus/templates/slides/server/routes/api/index-design-system-with-builder.post.ts +1 -0
  207. package/dist/action.d.ts +23 -0
  208. package/dist/action.d.ts.map +1 -1
  209. package/dist/action.js +9 -0
  210. package/dist/action.js.map +1 -1
  211. package/dist/agent/durable-background.d.ts +9 -7
  212. package/dist/agent/durable-background.d.ts.map +1 -1
  213. package/dist/agent/durable-background.js +27 -11
  214. package/dist/agent/durable-background.js.map +1 -1
  215. package/dist/agent/production-agent.d.ts +10 -0
  216. package/dist/agent/production-agent.d.ts.map +1 -1
  217. package/dist/agent/production-agent.js +4 -1
  218. package/dist/agent/production-agent.js.map +1 -1
  219. package/dist/agent/run-loop-with-resume.d.ts +2 -1
  220. package/dist/agent/run-loop-with-resume.d.ts.map +1 -1
  221. package/dist/agent/run-loop-with-resume.js +2 -2
  222. package/dist/agent/run-loop-with-resume.js.map +1 -1
  223. package/dist/brand-kit/fig/index.d.ts +4 -4
  224. package/dist/brand-kit/fig/index.d.ts.map +1 -1
  225. package/dist/brand-kit/fig/index.js +14 -27
  226. package/dist/brand-kit/fig/index.js.map +1 -1
  227. package/dist/cli/index.js +1 -1
  228. package/dist/cli/index.js.map +1 -1
  229. package/dist/cli/mcp-config-writers.d.ts +15 -7
  230. package/dist/cli/mcp-config-writers.d.ts.map +1 -1
  231. package/dist/cli/mcp-config-writers.js +198 -45
  232. package/dist/cli/mcp-config-writers.js.map +1 -1
  233. package/dist/cli/plan-local.d.ts +30 -0
  234. package/dist/cli/plan-local.d.ts.map +1 -1
  235. package/dist/cli/plan-local.js +281 -56
  236. package/dist/cli/plan-local.js.map +1 -1
  237. package/dist/cli/skills.d.ts +2 -2
  238. package/dist/cli/skills.d.ts.map +1 -1
  239. package/dist/cli/skills.js +32 -8
  240. package/dist/cli/skills.js.map +1 -1
  241. package/dist/client/AssistantChat.d.ts.map +1 -1
  242. package/dist/client/AssistantChat.js +11 -1
  243. package/dist/client/AssistantChat.js.map +1 -1
  244. package/dist/client/agent-chat.d.ts.map +1 -1
  245. package/dist/client/agent-chat.js +15 -2
  246. package/dist/client/agent-chat.js.map +1 -1
  247. package/dist/client/composer/PromptComposer.d.ts.map +1 -1
  248. package/dist/client/composer/PromptComposer.js +35 -1
  249. package/dist/client/composer/PromptComposer.js.map +1 -1
  250. package/dist/client/org/OrgSwitcher.js +1 -1
  251. package/dist/client/org/OrgSwitcher.js.map +1 -1
  252. package/dist/client/sharing/ShareButton.d.ts +1 -1
  253. package/dist/client/sharing/ShareButton.d.ts.map +1 -1
  254. package/dist/client/sharing/ShareButton.js +2 -15
  255. package/dist/client/sharing/ShareButton.js.map +1 -1
  256. package/dist/collab/presence.d.ts +1 -1
  257. package/dist/collab/presence.js +1 -1
  258. package/dist/collab/presence.js.map +1 -1
  259. package/dist/collab/routes.d.ts +1 -1
  260. package/dist/file-upload/actions/upload-image.d.ts +2 -2
  261. package/dist/mcp/connect-route.d.ts.map +1 -1
  262. package/dist/mcp/connect-route.js +34 -5
  263. package/dist/mcp/connect-route.js.map +1 -1
  264. package/dist/observability/routes.d.ts +2 -2
  265. package/dist/progress/routes.d.ts +1 -1
  266. package/dist/resources/handlers.d.ts +1 -1
  267. package/dist/server/action-discovery.d.ts.map +1 -1
  268. package/dist/server/action-discovery.js +5 -0
  269. package/dist/server/action-discovery.js.map +1 -1
  270. package/dist/server/action-routes.d.ts.map +1 -1
  271. package/dist/server/action-routes.js +14 -0
  272. package/dist/server/action-routes.js.map +1 -1
  273. package/dist/server/agent-chat-plugin.d.ts +6 -0
  274. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  275. package/dist/server/agent-chat-plugin.js +12 -3
  276. package/dist/server/agent-chat-plugin.js.map +1 -1
  277. package/dist/vite/client.d.ts.map +1 -1
  278. package/dist/vite/client.js +12 -1
  279. package/dist/vite/client.js.map +1 -1
  280. package/docs/content/locales/ar-SA/real-time-collaboration.mdx +2 -2
  281. package/docs/content/locales/ar-SA/template-design.mdx +1 -1
  282. package/docs/content/locales/de-DE/real-time-collaboration.mdx +3 -3
  283. package/docs/content/locales/de-DE/template-design.mdx +1 -1
  284. package/docs/content/locales/es-ES/real-time-collaboration.mdx +2 -2
  285. package/docs/content/locales/es-ES/template-design.mdx +1 -1
  286. package/docs/content/locales/fr-FR/real-time-collaboration.mdx +2 -2
  287. package/docs/content/locales/fr-FR/template-design.mdx +1 -1
  288. package/docs/content/locales/hi-IN/template-design.mdx +1 -1
  289. package/docs/content/locales/ja-JP/real-time-collaboration.mdx +2 -2
  290. package/docs/content/locales/ja-JP/template-design.mdx +1 -1
  291. package/docs/content/locales/ko-KR/real-time-collaboration.mdx +2 -2
  292. package/docs/content/locales/ko-KR/template-design.mdx +1 -1
  293. package/docs/content/locales/pt-BR/real-time-collaboration.mdx +2 -2
  294. package/docs/content/locales/pt-BR/template-design.mdx +1 -1
  295. package/docs/content/locales/zh-CN/real-time-collaboration.mdx +2 -2
  296. package/docs/content/locales/zh-CN/template-design.mdx +1 -1
  297. package/docs/content/locales/zh-TW/real-time-collaboration.mdx +2 -2
  298. package/docs/content/locales/zh-TW/template-design.mdx +1 -1
  299. package/docs/content/real-time-collaboration.mdx +2 -2
  300. package/docs/content/template-design.mdx +1 -1
  301. package/package.json +3 -7
  302. package/corpus/core/src/brand-kit/fig/decode.ts +0 -410
  303. package/corpus/core/src/brand-kit/fig/extract-design-system.ts +0 -947
  304. package/corpus/core/src/brand-kit/fig/fig-to-html.ts +0 -1906
  305. package/corpus/templates/design/actions/import-figma.ts +0 -55
  306. package/corpus/templates/design/changelog/2026-06-28-figma-style-code-design-mode.md +0 -6
  307. package/corpus/templates/design/server/handlers/import-figma-system.ts +0 -86
  308. package/corpus/templates/design/server/routes/api/import-figma-system.post.ts +0 -1
  309. package/corpus/templates/slides/server/handlers/import-figma-system.ts +0 -101
  310. package/corpus/templates/slides/server/routes/api/import-figma-system.post.ts +0 -1
  311. package/dist/brand-kit/fig/decode.d.ts +0 -33
  312. package/dist/brand-kit/fig/decode.d.ts.map +0 -1
  313. package/dist/brand-kit/fig/decode.js +0 -358
  314. package/dist/brand-kit/fig/decode.js.map +0 -1
  315. package/dist/brand-kit/fig/extract-design-system.d.ts +0 -44
  316. package/dist/brand-kit/fig/extract-design-system.d.ts.map +0 -1
  317. package/dist/brand-kit/fig/extract-design-system.js +0 -752
  318. package/dist/brand-kit/fig/extract-design-system.js.map +0 -1
  319. package/dist/brand-kit/fig/fig-to-html.d.ts +0 -246
  320. package/dist/brand-kit/fig/fig-to-html.d.ts.map +0 -1
  321. package/dist/brand-kit/fig/fig-to-html.js +0 -1506
  322. package/dist/brand-kit/fig/fig-to-html.js.map +0 -1
@@ -398,8 +398,8 @@ iframe-backed screens on the infinite canvas.
398
398
  - Each screen is a URL-backed iframe, not copied HTML.
399
399
  - Each screen keeps URL metadata: \`connectionId\`, \`routeId\`, \`path\`,
400
400
  \`url\`, \`bridgeUrl\`, title, and viewport size.
401
- - Start in Design's screen overview mode. In overview, screens are static like
402
- Figma frames; full-screen focus is for scrolling and app interaction.
401
+ - Start in Design's screen overview mode. In overview, screens are static
402
+ design frames; full-screen focus is for scrolling and app interaction.
403
403
  - Alt-drag duplicates a screen. For localhost screens, duplication copies the
404
404
  iframe frame and URL metadata; change the copy's path/query for a new state.
405
405
  - Flow visualization is multiple URL states: \`/checkout?step=shipping\`,
@@ -466,6 +466,21 @@ route from the latest localhost manifest.
466
466
  pnpm action navigate --view editor --designId "<design-id>" --editorView overview
467
467
  \`\`\`
468
468
 
469
+ ## Open The Design Surface
470
+
471
+ - Use the \`link\`, \`deepLink\`, or MCP App embed returned by Design actions so
472
+ the user sees the canvas. In Codex Desktop or VS Code, prefer opening that
473
+ Design URL in the available preview/webview panel; otherwise surface the
474
+ "Open design" link.
475
+ - If the user is working in VS Code, the Agent Native extension can open the
476
+ same URL via
477
+ \`vscode://builder.agent-native/open?url=<encoded-design-url>\`. Its
478
+ \`Agent Native: Open Design Canvas\` command also starts the local bridge and
479
+ opens hosted Design in the VS Code side panel.
480
+ - After \`add-localhost-screens\`, confirm the Design editor is in overview mode
481
+ with the requested URL-backed frames visible. Do not stop at "screens added"
482
+ when the user asked to inspect or edit visually.
483
+
469
484
  ## Editing URLs
470
485
 
471
486
  Keep localhost screens as URL files plus \`screenMetadata[fileId]\`. Do not
@@ -930,7 +945,7 @@ and move any frame whose label, connector, or annotation crosses another frame.
930
945
  When in doubt, use larger values — the canvas auto-zooms to fit everything.
931
946
 
932
947
  **Canvas annotations are designer notes on the artboard.** When a top canvas is
933
- present, sprinkle Figma-style notes near the frames they explain: a short
948
+ present, sprinkle design-review notes near the frames they explain: a short
934
949
  heading, supporting text, and bullets — plain text layers, never bordered or
935
950
  shadowed cards, and never a box around a frame. The renderer spaces notes away
936
951
  from frames, so place each note by the frame it describes. Use an arrow only to
@@ -1405,8 +1420,10 @@ The local-files contract:
1405
1420
  \`id\` and \`label\`; and \`Code\` / \`AnnotatedCode\` / \`Diff\` are whitespace-sensitive
1406
1421
  — encode multiline code as JSON string attributes such as \`code={"const x =\\n y"}\`
1407
1422
  (a static template literal is accepted only when it has no \`\${...}\`
1408
- interpolation). \`plan local check\` validates these required fields against the
1409
- renderer schema.
1423
+ interpolation). \`plan local check\` is a quick OFFLINE lint (a subset of the
1424
+ renderer schema), so a green \`check\` does not guarantee the plan renders;
1425
+ \`plan local verify\` is the authoritative validation against the real renderer
1426
+ schema.
1410
1427
  - **Write a local MDX folder.** Use \`plans/<slug>/\` to check the artifact into the
1411
1428
  repo, or a repo-ignored/temporary folder such as \`.agent-native/plans/<slug>/\`
1412
1429
  or \`/tmp/agent-native-plans/<slug>/\` when it should not be checked in. The
@@ -1431,9 +1448,16 @@ The local-files contract:
1431
1448
  running local Plan app.
1432
1449
  - **Headless verify.** Run
1433
1450
  \`npx @agent-native/core@latest plan local verify --dir <plan-dir> --kind <plan|recap>\`.
1434
- It starts the bridge, checks the private-network preflight and JSON payload,
1435
- prints diagnostics, and exits. If the browser hangs on "Loading plan", fetch the
1436
- \`bridgeUrl\` from the verify/serve JSON to read the concrete validation error.
1451
+ It starts the bridge, checks the private-network preflight and JSON payload, AND
1452
+ validates the content against the real renderer schema via the Plan app's
1453
+ \`validate-local-plan-source\` action. A non-\`ok\` result with
1454
+ \`validation.valid: false\` lists the renderer's exact schema-path issues (e.g.
1455
+ \`blocks[1].data.tabs[0]...\`); fix those before handing off. If \`validation.ran\`
1456
+ is \`false\`, the Plan app did not expose the validate endpoint (older/unreachable
1457
+ deploy) — point \`--app-url\` at a current Plan app (e.g. a local
1458
+ \`http://localhost:8096\`) for the authoritative check. If the browser hangs on
1459
+ "Loading plan", fetch the \`bridgeUrl\` from the verify/serve JSON to read the
1460
+ concrete validation error.
1437
1461
  - **Never call hosted tools for that plan/recap.** Do not call
1438
1462
  \`create-visual-plan\`, \`create-ui-plan\`, \`create-prototype-plan\`,
1439
1463
  \`create-plan-design\`, \`create-visual-recap\`, \`create-visual-questions\`,
@@ -1191,9 +1191,19 @@ const AssistantChatInner = forwardRef<
1191
1191
  setComposerContextItems((previous) => {
1192
1192
  const next = updater(previous);
1193
1193
  composerContextItemsRef.current = next;
1194
- publishComposerContextItems(next);
1195
1194
  return next;
1196
1195
  });
1196
+ // Publish outside the setState updater. `publishComposerContextItems`
1197
+ // mutates the module-level context store and synchronously dispatches a
1198
+ // window event, which would re-enter React (notifying
1199
+ // `useSyncExternalStore` subscribers like `useAgentChatContext`) while the
1200
+ // updater runs during the render phase. React 19 then throws "Cannot
1201
+ // update a component while rendering a different component". Queueing a
1202
+ // microtask runs the publish after the commit; it reads the freshly
1203
+ // updated `composerContextItemsRef`, not React state.
1204
+ queueMicrotask(() => {
1205
+ publishComposerContextItems(composerContextItemsRef.current);
1206
+ });
1197
1207
  },
1198
1208
  [publishComposerContextItems],
1199
1209
  );
@@ -188,6 +188,7 @@ let agentChatContextState: AgentChatContextState = {
188
188
  updatedAt: 0,
189
189
  };
190
190
  const agentChatContextListeners = new Set<() => void>();
191
+ let agentChatContextNotifyQueued = false;
191
192
 
192
193
  /**
193
194
  * Listen for chatRunning messages from the frame (postMessage)
@@ -345,7 +346,17 @@ function withReplacedAgentChatContextItem(
345
346
  }
346
347
 
347
348
  function notifyAgentChatContextListeners(): void {
348
- for (const listener of agentChatContextListeners) listener();
349
+ if (agentChatContextNotifyQueued) return;
350
+ agentChatContextNotifyQueued = true;
351
+ const notify = () => {
352
+ agentChatContextNotifyQueued = false;
353
+ for (const listener of Array.from(agentChatContextListeners)) listener();
354
+ };
355
+ if (typeof queueMicrotask === "function") {
356
+ queueMicrotask(notify);
357
+ } else {
358
+ setTimeout(notify, 0);
359
+ }
349
360
  }
350
361
 
351
362
  function persistAgentChatContextState(state: AgentChatContextState): void {
@@ -30,7 +30,12 @@ import {
30
30
 
31
31
  import type { ReasoningEffort } from "../../shared/reasoning-effort.js";
32
32
  import { AssistantUiStaleIndexErrorBoundary } from "../assistant-ui-recovery.js";
33
+ import { BuilderSetupCard } from "../chat/run-recovery.js";
33
34
  import { TooltipProvider } from "../components/ui/tooltip.js";
35
+ import {
36
+ fetchAgentEngineConfiguredState,
37
+ useAgentEngineConfigured,
38
+ } from "../use-agent-engine-configured.js";
34
39
  import { useChatModels, type EngineModelGroup } from "../use-chat-models.js";
35
40
  import { cn } from "../utils.js";
36
41
  import { AgentComposerFrame } from "./AgentComposerFrame.js";
@@ -57,6 +62,7 @@ import type {
57
62
  } from "./types.js";
58
63
 
59
64
  const MAX_INLINE_TEXT_FILE_CHARS = 60_000;
65
+ const SUBMIT_ENGINE_STATUS_TIMEOUT_MS = 1000;
60
66
 
61
67
  /**
62
68
  * Files the user attached via the "+" button in PromptComposer. The host owns
@@ -498,6 +504,41 @@ function PromptComposerInner({
498
504
  const handleEffortChange = showModelSelector
499
505
  ? (onEffortChange ?? models.onEffortChange)
500
506
  : undefined;
507
+ const agentEngineConfigured = useAgentEngineConfigured(
508
+ resolvedModelStatusChecksEnabled,
509
+ );
510
+ const missingApiKey = agentEngineConfigured.missing;
511
+ const [missingKeyBouncePulse, setMissingKeyBouncePulse] = useState(0);
512
+ const bounceMissingKeySetup = useCallback(() => {
513
+ setMissingKeyBouncePulse((pulse) => pulse + 1);
514
+ if (typeof window !== "undefined") {
515
+ window.dispatchEvent(new Event("agent-chat:missing-api-key"));
516
+ }
517
+ }, []);
518
+ const handleBuilderConnected = useCallback(() => {
519
+ if (typeof window !== "undefined") {
520
+ window.dispatchEvent(new Event("agent-engine:configured-changed"));
521
+ }
522
+ }, []);
523
+ const ensureAgentEngineReadyForSubmit = useCallback(async () => {
524
+ if (!resolvedModelStatusChecksEnabled) return true;
525
+ const state =
526
+ agentEngineConfigured.state === "missing"
527
+ ? "missing"
528
+ : await fetchAgentEngineConfiguredState(
529
+ resolvedModelStatusChecksEnabled,
530
+ {
531
+ timeoutMs: SUBMIT_ENGINE_STATUS_TIMEOUT_MS,
532
+ },
533
+ );
534
+ if (state !== "missing") return true;
535
+ bounceMissingKeySetup();
536
+ return false;
537
+ }, [
538
+ agentEngineConfigured.state,
539
+ bounceMissingKeySetup,
540
+ resolvedModelStatusChecksEnabled,
541
+ ]);
501
542
 
502
543
  useEffect(() => {
503
544
  if (!autoFocus) return;
@@ -539,48 +580,66 @@ function PromptComposerInner({
539
580
  );
540
581
 
541
582
  return (
542
- <AgentComposerFrame
543
- className={cn("text-start", className)}
544
- rootClassName={rootClassName}
545
- style={style}
546
- rootStyle={rootStyle}
547
- layoutVariant={layoutVariant}
548
- >
549
- <PromptAttachmentStrip />
550
- <TiptapComposer
551
- focusRef={handleRef}
552
- disabled={disabled}
553
- placeholder={placeholder}
554
- initialText={initialText}
555
- initialTextKey={initialTextKey}
556
- onSubmit={handleSubmit}
557
- clearOnSubmit={!preserveDraftOnSubmit}
558
- plusMenuMode={
559
- plusMenuMode ?? (attachmentsEnabled ? "upload-only" : "hidden")
560
- }
561
- attachButton={attachButton}
562
- modeControl={modeControl}
563
- toolbarSlot={toolbarSlot}
564
- actionButton={actionButton}
565
- extraActionButton={extraActionButton}
583
+ <>
584
+ {missingApiKey ? (
585
+ <BuilderSetupCard
586
+ onConnected={handleBuilderConnected}
587
+ bouncePulse={missingKeyBouncePulse}
588
+ fullWidth
589
+ layout="sidebar"
590
+ />
591
+ ) : null}
592
+ <AgentComposerFrame
593
+ className={cn(
594
+ "text-start",
595
+ missingApiKey && "cursor-pointer",
596
+ className,
597
+ )}
598
+ rootClassName={rootClassName}
599
+ style={style}
600
+ rootStyle={rootStyle}
566
601
  layoutVariant={layoutVariant}
567
- slashCommands={slashCommands}
568
- slashSkills={slashSkills}
569
- includeDefaultSlashCommands={includeDefaultSlashCommands}
570
- includeDefaultSlashSkills={includeDefaultSlashSkills}
571
- onSlashCommand={onSlashCommand}
572
- voiceEnabled={voiceEnabled}
573
- onTextChange={onTextChange}
574
- draftScope={draftScope}
575
- selectedModel={composerModel}
576
- selectedEffort={composerEffort}
577
- availableModels={composerModelGroups}
578
- onModelChange={handleModelChange}
579
- onEffortChange={handleEffortChange}
580
- providerConnectStatusEnabled={resolvedModelStatusChecksEnabled}
581
- onConnectProvider={onConnectProvider}
582
- />
583
- </AgentComposerFrame>
602
+ onClick={missingApiKey ? bounceMissingKeySetup : undefined}
603
+ >
604
+ <PromptAttachmentStrip />
605
+ <TiptapComposer
606
+ focusRef={handleRef}
607
+ disabled={disabled || missingApiKey}
608
+ placeholder={
609
+ missingApiKey ? "Connect AI above to continue..." : placeholder
610
+ }
611
+ initialText={initialText}
612
+ initialTextKey={initialTextKey}
613
+ onSubmit={handleSubmit}
614
+ onBeforeSubmit={ensureAgentEngineReadyForSubmit}
615
+ clearOnSubmit={!preserveDraftOnSubmit}
616
+ plusMenuMode={
617
+ plusMenuMode ?? (attachmentsEnabled ? "upload-only" : "hidden")
618
+ }
619
+ attachButton={attachButton}
620
+ modeControl={modeControl}
621
+ toolbarSlot={toolbarSlot}
622
+ actionButton={actionButton}
623
+ extraActionButton={extraActionButton}
624
+ layoutVariant={layoutVariant}
625
+ slashCommands={slashCommands}
626
+ slashSkills={slashSkills}
627
+ includeDefaultSlashCommands={includeDefaultSlashCommands}
628
+ includeDefaultSlashSkills={includeDefaultSlashSkills}
629
+ onSlashCommand={onSlashCommand}
630
+ voiceEnabled={voiceEnabled}
631
+ onTextChange={onTextChange}
632
+ draftScope={draftScope}
633
+ selectedModel={composerModel}
634
+ selectedEffort={composerEffort}
635
+ availableModels={composerModelGroups}
636
+ onModelChange={handleModelChange}
637
+ onEffortChange={handleEffortChange}
638
+ providerConnectStatusEnabled={resolvedModelStatusChecksEnabled}
639
+ onConnectProvider={onConnectProvider}
640
+ />
641
+ </AgentComposerFrame>
642
+ </>
584
643
  );
585
644
  }
586
645
 
@@ -368,7 +368,7 @@ export function OrgSwitcher({
368
368
  <PopoverPrimitive.Trigger asChild>
369
369
  <button
370
370
  type="button"
371
- className={`flex w-full items-center gap-2 rounded-md border border-border/50 px-2.5 py-1.5 text-xs font-medium text-muted-foreground hover:bg-accent/50 hover:text-foreground focus:outline-none focus-visible:ring-2 focus-visible:ring-ring cursor-pointer ${className ?? ""}`}
371
+ className={`flex w-full items-center gap-2 rounded-md border border-border/70 px-2.5 py-1.5 text-xs font-medium text-muted-foreground hover:bg-accent/50 hover:text-foreground focus:outline-none focus-visible:ring-2 focus-visible:ring-ring cursor-pointer ${className ?? ""}`}
372
372
  >
373
373
  <ButtonIcon className="h-3.5 w-3.5 shrink-0" />
374
374
  <span className="truncate flex-1 text-start">{buttonLabel}</span>
@@ -47,7 +47,7 @@ export interface ShareButtonProps {
47
47
  variant?: "compact" | "label";
48
48
  /** Optional trigger style. Defaults to the Google-Docs-style "Share" label. */
49
49
  trigger?: "label" | "icon";
50
- /** Hide the visibility/share glyph in the label trigger. */
50
+ /** @deprecated Label triggers no longer render a visibility/share glyph. */
51
51
  hideTriggerIcon?: boolean;
52
52
  /** Optional className applied to the trigger button. */
53
53
  triggerClassName?: string;
@@ -298,23 +298,8 @@ export function ShareButton(props: ShareButtonProps) {
298
298
  });
299
299
  };
300
300
 
301
- // The default trigger says "Share" the icon reflects the resource's
302
- // current visibility (lock / building / globe), matching Google Docs.
303
- // While the query is loading and we don't know the visibility yet,
304
- // render a skeleton placeholder in the icon slot instead of guessing.
301
+ // The default trigger stays text-only; the icon trigger keeps the share glyph.
305
302
  const iconOnly = props.trigger === "icon";
306
- const loaded = sharesQuery.data !== undefined;
307
- const serverVisibility =
308
- (sharesQuery.data?.visibility as Visibility | null) ?? "private";
309
- const currentVisibility = pendingVisibility ?? serverVisibility;
310
- const VisibilityIcon =
311
- currentVisibility === "public"
312
- ? IconWorld
313
- : currentVisibility === "org"
314
- ? IconBuilding
315
- : IconLock;
316
- const showTriggerIcon = iconOnly || !props.hideTriggerIcon;
317
- const TriggerIcon = iconOnly ? IconShare3 : VisibilityIcon;
318
303
 
319
304
  return (
320
305
  <Popover open={open} onOpenChange={handleOpenChange}>
@@ -327,16 +312,7 @@ export function ShareButton(props: ShareButtonProps) {
327
312
  )}
328
313
  aria-label={iconOnly ? "Share" : undefined}
329
314
  >
330
- {showTriggerIcon ? (
331
- loaded || iconOnly ? (
332
- <TriggerIcon size={16} strokeWidth={1.75} />
333
- ) : (
334
- <span
335
- aria-hidden
336
- className="inline-block h-4 w-4 rounded-sm bg-muted animate-pulse"
337
- />
338
- )
339
- ) : null}
315
+ {iconOnly ? <IconShare3 size={16} strokeWidth={1.75} /> : null}
340
316
  {!iconOnly && <span>Share</span>}
341
317
  </button>
342
318
  </PopoverTrigger>
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Presence kit — Liveblocks/Figma-grade presence primitives.
2
+ * Presence kit — Liveblocks/collaboration-grade presence primitives.
3
3
  *
4
4
  * usePresence(awareness) returns:
5
5
  * - others: reactive array of remote participants (human + agent)
@@ -639,6 +639,20 @@ function renderConnectPage(params: {
639
639
  }
640
640
  .primary:hover:not(:disabled) { background: #e4e4e7; }
641
641
  .primary:disabled { opacity: 0.55; cursor: default; }
642
+ .primary.is-loading {
643
+ display: inline-flex; align-items: center; justify-content: center;
644
+ gap: 0.55rem; opacity: 1;
645
+ }
646
+ .primary.is-loading::before {
647
+ content: ""; width: 1rem; height: 1rem; flex: 0 0 auto;
648
+ border-radius: 999px; border: 2px solid rgba(0,0,0,0.22);
649
+ border-top-color: var(--accent-fg);
650
+ animation: spin 0.75s linear infinite;
651
+ }
652
+ @keyframes spin { to { transform: rotate(360deg); } }
653
+ @media (prefers-reduced-motion: reduce) {
654
+ .primary.is-loading::before { animation: none; }
655
+ }
642
656
  .ghost {
643
657
  background: transparent; color: var(--muted);
644
658
  border: 1px solid var(--border-strong); padding: 0.35rem 0.7rem;
@@ -900,7 +914,7 @@ function renderConnectPage(params: {
900
914
  <span class="chev" aria-hidden="true"></span>
901
915
  </summary>
902
916
  <div class="static-token-body">
903
- <div id="msg" class="msg"></div>
917
+ <div id="msg" class="msg" role="status" aria-live="polite"></div>
904
918
  <div id="mintForm">
905
919
  <button id="authorizeBtn" class="primary">${safeUserCode ? "Authorize device" : "Create connection token"}</button>
906
920
  ${tokenAdvancedOptionsHtml}
@@ -983,6 +997,21 @@ function renderConnectPage(params: {
983
997
  }
984
998
  function clearMsg() { msgEl.className = "msg"; msgEl.textContent = ""; }
985
999
 
1000
+ function setButtonLoading(btn, text) {
1001
+ if (!btn.dataset.idleText) btn.dataset.idleText = btn.textContent || "";
1002
+ btn.textContent = text;
1003
+ btn.classList.add("is-loading");
1004
+ btn.setAttribute("aria-busy", "true");
1005
+ btn.disabled = true;
1006
+ }
1007
+
1008
+ function resetButtonLoading(btn) {
1009
+ btn.disabled = false;
1010
+ btn.classList.remove("is-loading");
1011
+ btn.removeAttribute("aria-busy");
1012
+ if (btn.dataset.idleText) btn.textContent = btn.dataset.idleText;
1013
+ }
1014
+
986
1015
  function renderResult(data) {
987
1016
  document.getElementById("mintForm").classList.add("hidden");
988
1017
  var entry = {};
@@ -1060,13 +1089,13 @@ function renderConnectPage(params: {
1060
1089
 
1061
1090
  document.getElementById("authorizeBtn").onclick = async function () {
1062
1091
  var btn = this;
1063
- btn.disabled = true;
1092
+ setButtonLoading(btn, USER_CODE ? "Authorizing device..." : "Creating token...");
1064
1093
  clearMsg();
1065
1094
  try {
1066
1095
  if (USER_CODE) {
1067
1096
  var a = await postJson("/device/authorize", { user_code: USER_CODE });
1068
1097
  if (!a.ok) {
1069
- btn.disabled = false;
1098
+ resetButtonLoading(btn);
1070
1099
  showMsg((a.data && a.data.error) || "Could not authorize this device code.");
1071
1100
  return;
1072
1101
  }
@@ -1128,7 +1157,7 @@ function renderConnectPage(params: {
1128
1157
  var ttlDays = ttlEl ? parseInt(ttlEl.value, 10) || undefined : undefined;
1129
1158
  var m = await postJson("/token", { label: label, ttlDays: ttlDays });
1130
1159
  if (!m.ok) {
1131
- btn.disabled = false;
1160
+ resetButtonLoading(btn);
1132
1161
  showMsg((m.data && m.data.error) || "Could not create token.");
1133
1162
  return;
1134
1163
  }
@@ -1136,7 +1165,7 @@ function renderConnectPage(params: {
1136
1165
  }
1137
1166
  loadTokens();
1138
1167
  } catch (e) {
1139
- btn.disabled = false;
1168
+ resetButtonLoading(btn);
1140
1169
  showMsg("Network error. Please try again.");
1141
1170
  }
1142
1171
  };
@@ -216,6 +216,10 @@ function preserveActionFlags(entry: Record<string, any>): Partial<ActionEntry> {
216
216
  ) {
217
217
  out.chatUI = entry.chatUI;
218
218
  }
219
+ if (typeof entry.timeoutMs === "number") out.timeoutMs = entry.timeoutMs;
220
+ if (typeof entry.maxResultChars === "number") {
221
+ out.maxResultChars = entry.maxResultChars;
222
+ }
219
223
  if (
220
224
  typeof entry.needsApproval === "boolean" ||
221
225
  typeof entry.needsApproval === "function"
@@ -284,6 +284,20 @@ export function mountActionRoutes(
284
284
  return runWithRequestContext(
285
285
  { userEmail, userName, orgId, timezone },
286
286
  async () => {
287
+ // Reject oversize bodies from Content-Length before parsing, so a
288
+ // public no-auth POST can't force parse work on a huge request.
289
+ if (typeof entry.maxBodyBytes === "number" && method !== "GET") {
290
+ const clRaw = getHeader(event, "content-length");
291
+ if (clRaw) {
292
+ const declared = parseInt(clRaw, 10);
293
+ if (!Number.isNaN(declared) && declared > entry.maxBodyBytes) {
294
+ setResponseStatus(event, 413);
295
+ return {
296
+ error: `Request body too large (max ${entry.maxBodyBytes} bytes)`,
297
+ };
298
+ }
299
+ }
300
+ }
287
301
  // Parse params based on method. On web-standard runtimes (Netlify
288
302
  // Functions, CF Workers), event.req IS the web Request — use .json()
289
303
  // directly. H3's readBody fails on those runtimes because it expects
@@ -36,6 +36,7 @@ import { DEFAULT_ANTHROPIC_MODEL } from "../agent/default-model.js";
36
36
  import {
37
37
  AGENT_CHAT_PROCESS_RUN_PATH,
38
38
  extractProcessRunId,
39
+ isInBackgroundFunctionRuntime,
39
40
  prepareProcessRunRequest,
40
41
  } from "../agent/durable-background.js";
41
42
  import {
@@ -2567,6 +2568,12 @@ export interface AgentChatPluginOptions {
2567
2568
  * timeout. When reached, long runs continue through the hidden continuation
2568
2569
  * path instead of surfacing a timeout warning. */
2569
2570
  runSoftTimeoutMs?: number;
2571
+ /**
2572
+ * Opt this app into Netlify durable background-function agent-chat runs. This
2573
+ * gives hosted agent turns the 15-minute async-function budget when the app's
2574
+ * Netlify build also emits the background function.
2575
+ */
2576
+ durableBackgroundRuns?: boolean;
2570
2577
  /** Anthropic API key. Falls back to ANTHROPIC_API_KEY env var */
2571
2578
  apiKey?: string;
2572
2579
  /**
@@ -4837,6 +4844,11 @@ export function createAgentChatPlugin(
4837
4844
  signal: controller.signal,
4838
4845
  },
4839
4846
  options?.runSoftTimeoutMs,
4847
+ {
4848
+ backgroundFunction:
4849
+ options?.durableBackgroundRuns === true &&
4850
+ isInBackgroundFunctionRuntime(),
4851
+ },
4840
4852
  );
4841
4853
 
4842
4854
  const { responseText, finalText } = assembleA2AFinalResponse(
@@ -5035,6 +5047,11 @@ export function createAgentChatPlugin(
5035
5047
  signal: controller.signal,
5036
5048
  },
5037
5049
  options?.runSoftTimeoutMs,
5050
+ {
5051
+ backgroundFunction:
5052
+ options?.durableBackgroundRuns === true &&
5053
+ isInBackgroundFunctionRuntime(),
5054
+ },
5038
5055
  );
5039
5056
 
5040
5057
  return accumulatedText || "(no response)";
@@ -5712,6 +5729,7 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
5712
5729
  appId: options?.appId,
5713
5730
  apiKey: options?.apiKey,
5714
5731
  runSoftTimeoutMs: options?.runSoftTimeoutMs,
5732
+ durableBackgroundRuns: options?.durableBackgroundRuns,
5715
5733
  finalResponseGuard: options?.finalResponseGuard,
5716
5734
  prepareRequest: async (details) => {
5717
5735
  // Stash the threadId on runCtx so systemPrompt can check isNewThread().
@@ -5802,6 +5820,7 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
5802
5820
  appId: options?.appId,
5803
5821
  apiKey: options?.apiKey,
5804
5822
  runSoftTimeoutMs: options?.runSoftTimeoutMs,
5823
+ durableBackgroundRuns: options?.durableBackgroundRuns,
5805
5824
  finalResponseGuard: options?.finalResponseGuard,
5806
5825
  prepareRequest: options?.prepareRequest,
5807
5826
  skipFilesContext: true,
@@ -5932,6 +5951,7 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
5932
5951
  appId: options?.appId,
5933
5952
  apiKey: options?.apiKey,
5934
5953
  runSoftTimeoutMs: options?.runSoftTimeoutMs,
5954
+ durableBackgroundRuns: options?.durableBackgroundRuns,
5935
5955
  finalResponseGuard: options?.finalResponseGuard,
5936
5956
  prepareRequest: options?.prepareRequest,
5937
5957
  skipFilesContext,
@@ -1087,7 +1087,21 @@ function baseRedirectGuard(): Plugin {
1087
1087
  if (serveMountedEmbedRuntimeModule(server, req, res, base)) {
1088
1088
  return;
1089
1089
  }
1090
- req.url = stripMountedDevApiPath(req.url, base);
1090
+ // Nitro's pre-middleware only intercepts document/iframe/frame/empty
1091
+ // fetch-dest requests. For video/audio/image etc. it calls next() and
1092
+ // the post-internal Nitro middleware handles them instead. If we strip
1093
+ // the base path here for those requests, Vite's base middleware sees the
1094
+ // stripped path (e.g. /api/video/:id without /clips/) and responds with
1095
+ // a "did you mean /clips/api/video/:id" error before Nitro can handle it.
1096
+ // Only strip when the request type matches Nitro's pre-middleware gate.
1097
+ const secFetchDest = req.headers["sec-fetch-dest"] as
1098
+ | string
1099
+ | undefined;
1100
+ const isNitroPreHandled =
1101
+ !secFetchDest || /^(document|iframe|frame|empty)$/.test(secFetchDest);
1102
+ if (isNitroPreHandled) {
1103
+ req.url = stripMountedDevApiPath(req.url, base);
1104
+ }
1091
1105
  if (
1092
1106
  req.method === "HEAD" &&
1093
1107
  req.url &&
@@ -28,6 +28,8 @@ type DashboardPatch = {
28
28
  columns?: number;
29
29
  filters?: unknown[];
30
30
  variables?: Record<string, string>;
31
+ /** Id of another dashboard to nest this one under in the sidebar. */
32
+ parentId?: string;
31
33
  };
32
34
 
33
35
  type PanelPatch = {
@@ -277,6 +277,14 @@ export function validateDashboardConfig(
277
277
  if (typeof config.name !== "string" || config.name.trim().length === 0) {
278
278
  return "config.name is required (non-empty string) — without it the dashboard renders as a blank row in the sidebar";
279
279
  }
280
+ if (config.parentId !== undefined && config.parentId !== null) {
281
+ if (
282
+ typeof config.parentId !== "string" ||
283
+ config.parentId.trim().length === 0
284
+ ) {
285
+ return "config.parentId must be a non-empty dashboard id (or omitted) — it nests this dashboard under that parent in the sidebar";
286
+ }
287
+ }
280
288
  // Filter ID collisions cause two controls to read/write the same URL param.
281
289
  // For paired start/end dates use a single date-range filter — the FilterBar
282
290
  // expands it to <id>Start / <id>End at runtime, so the SQL can still
@@ -124,7 +124,7 @@ export function Layout({ children }: LayoutProps) {
124
124
  ? "flex-1 overflow-y-auto"
125
125
  : isAskRoute
126
126
  ? "flex-1 overflow-hidden p-0"
127
- : "flex-1 overflow-y-auto p-4 md:p-6 lg:p-8"
127
+ : "flex-1 overflow-y-auto p-6 pt-2"
128
128
  }
129
129
  >
130
130
  {children}