@agent-native/core 0.80.4 → 0.80.6

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 (341) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +28 -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 +21 -0
  26. package/corpus/core/src/agent/durable-background.ts +32 -11
  27. package/corpus/core/src/agent/production-agent.ts +11 -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/create.ts +1 -0
  31. package/corpus/core/src/cli/index.ts +1 -1
  32. package/corpus/core/src/cli/mcp-config-writers.ts +187 -51
  33. package/corpus/core/src/cli/skills.ts +18 -3
  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/agent-chat-plugin.ts +20 -0
  43. package/corpus/core/src/sharing/registry.ts +17 -0
  44. package/corpus/core/src/templates/default/pnpm-workspace.yaml +1 -0
  45. package/corpus/core/src/templates/workspace-root/pnpm-workspace.yaml +1 -0
  46. package/corpus/templates/analytics/actions/dashboard-mutation-api.ts +2 -0
  47. package/corpus/templates/analytics/actions/update-dashboard.ts +8 -0
  48. package/corpus/templates/analytics/app/components/layout/Layout.tsx +1 -1
  49. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +117 -33
  50. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +4 -0
  51. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/types.ts +7 -0
  52. package/corpus/templates/analytics/changelog/2026-06-27-dashboards-can-now-nest-under-a-parent-in-the-sidebar-via-a-.md +6 -0
  53. package/corpus/templates/analytics/changelog/2026-06-29-analytics-pages-now-sit-closer-under-the-header-with-tighter.md +6 -0
  54. package/corpus/templates/assets/actions/generate-image-batch.ts +3 -0
  55. package/corpus/templates/assets/actions/generate-image.ts +3 -0
  56. package/corpus/templates/assets/changelog/2026-06-29-longer-agent-generation-window.md +6 -0
  57. package/corpus/templates/assets/netlify.toml +3 -3
  58. package/corpus/templates/assets/server/plugins/agent-chat.ts +4 -1
  59. package/corpus/templates/clips/app/components/capture-install-options.tsx +7 -8
  60. package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +1 -1
  61. package/corpus/templates/content/AGENTS.md +57 -44
  62. package/corpus/templates/content/README.md +16 -0
  63. package/corpus/templates/content/actions/_builder-cms-read-client.ts +125 -0
  64. package/corpus/templates/content/actions/_builder-cms-source-adapter.ts +28 -6
  65. package/corpus/templates/content/actions/_builder-cms-write-adapter.ts +238 -69
  66. package/corpus/templates/content/actions/_builder-cms-write-settings.ts +125 -43
  67. package/corpus/templates/content/actions/_database-source-utils.ts +746 -97
  68. package/corpus/templates/content/actions/_database-utils.ts +17 -14
  69. package/corpus/templates/content/actions/_federation-join.ts +14 -2
  70. package/corpus/templates/content/actions/_join-suggestion.ts +89 -14
  71. package/corpus/templates/content/actions/_local-file-documents.ts +2 -1
  72. package/corpus/templates/content/actions/attach-content-database-source.ts +124 -5
  73. package/corpus/templates/content/actions/bind-content-database-source-field.ts +256 -0
  74. package/corpus/templates/content/actions/change-content-database-source-role.ts +420 -0
  75. package/corpus/templates/content/actions/create-document.ts +8 -0
  76. package/corpus/templates/content/actions/execute-builder-source-batch.ts +282 -0
  77. package/corpus/templates/content/actions/execute-builder-source-execution.ts +220 -8
  78. package/corpus/templates/content/actions/get-content-database.ts +10 -2
  79. package/corpus/templates/content/actions/prepare-builder-source-execution.ts +19 -2
  80. package/corpus/templates/content/actions/prepare-builder-source-review.ts +47 -15
  81. package/corpus/templates/content/actions/refresh-content-database-source.ts +11 -4
  82. package/corpus/templates/content/actions/review-content-database-source-change-set.ts +6 -2
  83. package/corpus/templates/content/actions/set-content-database-source-write-mode.ts +32 -12
  84. package/corpus/templates/content/actions/stage-builder-revision.ts +14 -10
  85. package/corpus/templates/content/actions/validate-builder-source-execution.ts +25 -3
  86. package/corpus/templates/content/app/blocks/BuilderDocsBlocks.tsx +10 -0
  87. package/corpus/templates/content/app/components/editor/BubbleToolbar.tsx +1 -0
  88. package/corpus/templates/content/app/components/editor/ContentReferencePreview.tsx +185 -0
  89. package/corpus/templates/content/app/components/editor/DocumentDatabase.tsx +1520 -553
  90. package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +3 -0
  91. package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +150 -1
  92. package/corpus/templates/content/app/components/editor/VisualEditor.tsx +19 -0
  93. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +647 -66
  94. package/corpus/templates/content/app/components/editor/database-sources/BuilderSourceReviewDialog.tsx +543 -204
  95. package/corpus/templates/content/app/components/editor/extensions/ContentReferenceNode.tsx +82 -0
  96. package/corpus/templates/content/app/global.css +9 -0
  97. package/corpus/templates/content/app/hooks/use-content-database.ts +62 -0
  98. package/corpus/templates/content/app/i18n/zh-TW.ts +76 -0
  99. package/corpus/templates/content/app/i18n-data.ts +924 -0
  100. package/corpus/templates/content/changelog/2026-06-29-builder-review-checks-now-preserve-publish-and-unpublish-cho.md +6 -0
  101. package/corpus/templates/content/changelog/2026-06-29-database-sources-can-now-be-added-as-more-rows-or-matched.md +6 -0
  102. package/corpus/templates/content/changelog/2026-06-29-fixed-loading-the-final-rows-in-larger-databases-without-bre.md +6 -0
  103. package/corpus/templates/content/changelog/2026-06-29-reusable-mdx-references-now-preview-linked-local-documents-i.md +6 -0
  104. package/corpus/templates/content/shared/api.ts +91 -1
  105. package/corpus/templates/content/shared/builder-docs-blocks.ts +8 -0
  106. package/corpus/templates/content/shared/builder-mdx.ts +141 -4
  107. package/corpus/templates/content/shared/nfm.ts +62 -0
  108. package/corpus/templates/content/vite.config.ts +14 -7
  109. package/corpus/templates/design/.agents/skills/design-systems/SKILL.md +10 -11
  110. package/corpus/templates/design/AGENTS.md +5 -0
  111. package/corpus/templates/design/_gitignore +7 -0
  112. package/corpus/templates/design/actions/apply-visual-edit.ts +22 -12
  113. package/corpus/templates/design/actions/create-design-system.ts +15 -4
  114. package/corpus/templates/design/actions/create-file.ts +20 -1
  115. package/corpus/templates/design/actions/delete-design-system.ts +2 -2
  116. package/corpus/templates/design/actions/duplicate-design.ts +35 -9
  117. package/corpus/templates/design/actions/generate-design.ts +146 -69
  118. package/corpus/templates/design/actions/generate-screens.ts +51 -19
  119. package/corpus/templates/design/actions/get-design-snapshot.ts +5 -1
  120. package/corpus/templates/design/actions/get-design.ts +2 -0
  121. package/corpus/templates/design/actions/import-design-project.ts +28 -9
  122. package/corpus/templates/design/actions/import-document.ts +22 -8
  123. package/corpus/templates/design/actions/index-design-system-with-builder.ts +6 -153
  124. package/corpus/templates/design/actions/navigate.ts +105 -54
  125. package/corpus/templates/design/actions/set-default-design-system.ts +17 -3
  126. package/corpus/templates/design/actions/show-design-questions.ts +2 -0
  127. package/corpus/templates/design/actions/update-design.ts +2 -1
  128. package/corpus/templates/design/actions/view-screen.ts +12 -6
  129. package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +4 -4
  130. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +159 -41
  131. package/corpus/templates/design/app/components/design/DesignExtensionsPanel.tsx +8 -4
  132. package/corpus/templates/design/app/components/design/DrawOverlay.tsx +37 -42
  133. package/corpus/templates/design/app/components/design/EditPanel.tsx +336 -183
  134. package/corpus/templates/design/app/components/design/LayersPanel.tsx +153 -34
  135. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +135 -33
  136. package/corpus/templates/design/app/components/design/QuestionFlow.tsx +6 -0
  137. package/corpus/templates/design/app/components/design/TweaksPanel.tsx +2 -1
  138. package/corpus/templates/design/app/components/design/inspector/AlignmentMatrix.tsx +4 -10
  139. package/corpus/templates/design/app/components/design/inspector/AutoLayoutMatrix.tsx +84 -43
  140. package/corpus/templates/design/app/components/design/inspector/ConstraintsWidget.tsx +4 -4
  141. package/corpus/templates/design/app/components/design/inspector/{FigmaColorPicker.tsx → DesignColorPicker.tsx} +89 -62
  142. package/corpus/templates/design/app/components/design/inspector/ExportSettingsPanel.tsx +14 -26
  143. package/corpus/templates/design/app/components/design/inspector/GradientEditor.tsx +40 -12
  144. package/corpus/templates/design/app/components/design/inspector/ImageFillControls.tsx +13 -4
  145. package/corpus/templates/design/app/components/design/inspector/SHADER_INTEGRATION.md +13 -13
  146. package/corpus/templates/design/app/components/design/inspector/ScrubInput.tsx +13 -9
  147. package/corpus/templates/design/app/components/design/inspector/ShaderControls.tsx +13 -4
  148. package/corpus/templates/design/app/components/design/inspector/ShaderFillsPanel.tsx +6 -6
  149. package/corpus/templates/design/app/components/design/inspector/{figma-icons.tsx → design-icons.tsx} +2 -2
  150. package/corpus/templates/design/app/components/design/inspector/index.ts +12 -12
  151. package/corpus/templates/design/app/components/design/inspector/scrub-input-utils.ts +5 -2
  152. package/corpus/templates/design/app/components/editor/PromptDialog.tsx +3 -3
  153. package/corpus/templates/design/app/components/layout/Layout.tsx +5 -2
  154. package/corpus/templates/design/app/components/layout/Sidebar.tsx +1 -1
  155. package/corpus/templates/design/app/components/visual-editor/CanvasCommentPins.tsx +167 -91
  156. package/corpus/templates/design/app/components/visual-editor/DrawOverlay.tsx +16 -3
  157. package/corpus/templates/design/app/components/visual-editor/SaveStatusIndicator.tsx +15 -0
  158. package/corpus/templates/design/app/global.css +4 -0
  159. package/corpus/templates/design/app/hooks/use-design-system.ts +4 -1
  160. package/corpus/templates/design/app/hooks/use-navigation-state.ts +38 -3
  161. package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +9 -2
  162. package/corpus/templates/design/app/i18n/zh-TW.ts +22 -0
  163. package/corpus/templates/design/app/i18n-data.ts +527 -0
  164. package/corpus/templates/design/app/lib/design-systems.ts +6 -4
  165. package/corpus/templates/design/app/lib/design-templates.ts +15 -3
  166. package/corpus/templates/design/app/pages/DesignEditor.tsx +641 -158
  167. package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +42 -34
  168. package/corpus/templates/design/app/pages/VisualEdit.tsx +100 -0
  169. package/corpus/templates/design/app/root.tsx +42 -9
  170. package/corpus/templates/design/app/routes/visual-edit.tsx +7 -0
  171. package/corpus/templates/design/changelog/2026-06-28-live-cursors-now-keep-names-beside-a-cleaner-pointer-marker.md +1 -1
  172. package/corpus/templates/design/changelog/2026-06-28-mode-switching-now-lives-in-a-compact-bottom-right-icon-dock.md +1 -1
  173. package/corpus/templates/design/changelog/2026-06-28-visual-code-design-mode.md +6 -0
  174. package/corpus/templates/design/changelog/2026-06-29-design-generation-prompts-now-show-connect-ai-before-sending.md +6 -0
  175. package/corpus/templates/design/changelog/2026-06-29-design-mode-top-chrome-now-groups-collaborators-preview-shar.md +1 -1
  176. package/corpus/templates/design/changelog/2026-06-29-fixed-design-editor-exports-and-gradient-edits-so-multi-scre.md +6 -0
  177. package/corpus/templates/design/changelog/2026-06-29-longer-hosted-agent-turns.md +6 -0
  178. package/corpus/templates/design/changelog/2026-06-29-png-export-handles-modern-css-color-functions-more-reliably.md +6 -0
  179. package/corpus/templates/design/changelog/2026-06-29-png-export-now-ignores-duplicate-clicks-while-a-download-is-.md +6 -0
  180. package/corpus/templates/design/changelog/2026-06-29-public-visual-edit-and-shared-design-links-now-invite-visito.md +6 -0
  181. package/corpus/templates/design/changelog/2026-06-29-visual-edit-actions-now-reject-missing-design-targets-before.md +6 -0
  182. package/corpus/templates/design/e2e/README.md +71 -0
  183. package/corpus/templates/design/e2e/global-setup.ts +157 -0
  184. package/corpus/templates/design/e2e/helpers.ts +148 -0
  185. package/corpus/templates/design/netlify.toml +3 -4
  186. package/corpus/templates/design/package.json +5 -1
  187. package/corpus/templates/design/playwright.config.ts +51 -0
  188. package/corpus/templates/design/server/handlers/index-design-system-with-builder.ts +121 -0
  189. package/corpus/templates/design/server/handlers/uploads.ts +89 -38
  190. package/corpus/templates/design/server/lib/builder-design-system-proxy.ts +181 -0
  191. package/corpus/templates/design/server/lib/coding-handoff.ts +33 -4
  192. package/corpus/templates/design/server/lib/design-export.ts +35 -8
  193. package/corpus/templates/design/server/plugins/agent-chat.ts +4 -0
  194. package/corpus/templates/design/server/plugins/auth.ts +10 -1
  195. package/corpus/templates/design/server/routes/api/index-design-system-with-builder.post.ts +1 -0
  196. package/corpus/templates/design/shared/api.ts +2 -0
  197. package/corpus/templates/design/shared/apply-edits.ts +12 -8
  198. package/corpus/templates/design/shared/canvas-math.ts +19 -1
  199. package/corpus/templates/design/shared/code-layer.ts +87 -28
  200. package/corpus/templates/design/shared/generation-session.ts +1 -0
  201. package/corpus/templates/design/shared/resolve-tweaks.ts +4 -3
  202. package/corpus/templates/design/shared/shader-presets.ts +10 -0
  203. package/corpus/templates/design/shared/source-mode.ts +9 -0
  204. package/corpus/templates/design/vitest.config.ts +2 -1
  205. package/corpus/templates/mail/app/components/layout/AppLayout.tsx +1 -1
  206. package/corpus/templates/plan/.agents/skills/visual-plan/references/canvas.md +1 -1
  207. package/corpus/templates/plan/AGENTS.md +1 -1
  208. package/corpus/templates/plan/actions/create-plan-design.ts +1 -1
  209. package/corpus/templates/plan/actions/validate-local-plan-source.ts +2 -10
  210. package/corpus/templates/plan/app/pages/PlansPage.tsx +1 -0
  211. package/corpus/templates/plan/docs/commenting-ux-plan.md +2 -2
  212. package/corpus/templates/plan/server/plan-content.ts +1 -1
  213. package/corpus/templates/plan/server/ui-plan-html.ts +2 -2
  214. package/corpus/templates/slides/actions/index-design-system-with-builder.ts +6 -153
  215. package/corpus/templates/slides/app/components/design-system/DesignSystemSetup.tsx +53 -38
  216. package/corpus/templates/slides/app/components/design-system/{fig-import-response.ts → builder-index-response.ts} +9 -6
  217. package/corpus/templates/slides/app/components/visual-editor/MultiSelectChip.tsx +1 -1
  218. package/corpus/templates/slides/changelog/2026-06-29-design-system-setup-now-indexes-uploaded-design-files-throug.md +6 -0
  219. package/corpus/templates/slides/changelog/2026-06-29-longer-hosted-agent-turns.md +6 -0
  220. package/corpus/templates/slides/netlify.toml +3 -6
  221. package/corpus/templates/slides/server/handlers/index-design-system-with-builder.ts +116 -0
  222. package/corpus/templates/slides/server/lib/builder-design-system-proxy.ts +179 -0
  223. package/corpus/templates/slides/server/plugins/agent-chat.ts +4 -1
  224. package/corpus/templates/slides/server/routes/api/index-design-system-with-builder.post.ts +1 -0
  225. package/dist/action.d.ts +15 -0
  226. package/dist/action.d.ts.map +1 -1
  227. package/dist/action.js +6 -0
  228. package/dist/action.js.map +1 -1
  229. package/dist/agent/durable-background.d.ts +9 -7
  230. package/dist/agent/durable-background.d.ts.map +1 -1
  231. package/dist/agent/durable-background.js +27 -11
  232. package/dist/agent/durable-background.js.map +1 -1
  233. package/dist/agent/production-agent.d.ts +7 -0
  234. package/dist/agent/production-agent.d.ts.map +1 -1
  235. package/dist/agent/production-agent.js +4 -1
  236. package/dist/agent/production-agent.js.map +1 -1
  237. package/dist/agent/run-loop-with-resume.d.ts +2 -1
  238. package/dist/agent/run-loop-with-resume.d.ts.map +1 -1
  239. package/dist/agent/run-loop-with-resume.js +2 -2
  240. package/dist/agent/run-loop-with-resume.js.map +1 -1
  241. package/dist/brand-kit/fig/index.d.ts +4 -4
  242. package/dist/brand-kit/fig/index.d.ts.map +1 -1
  243. package/dist/brand-kit/fig/index.js +14 -27
  244. package/dist/brand-kit/fig/index.js.map +1 -1
  245. package/dist/cli/create.d.ts.map +1 -1
  246. package/dist/cli/create.js +1 -0
  247. package/dist/cli/create.js.map +1 -1
  248. package/dist/cli/index.js +1 -1
  249. package/dist/cli/index.js.map +1 -1
  250. package/dist/cli/mcp-config-writers.d.ts +15 -7
  251. package/dist/cli/mcp-config-writers.d.ts.map +1 -1
  252. package/dist/cli/mcp-config-writers.js +198 -45
  253. package/dist/cli/mcp-config-writers.js.map +1 -1
  254. package/dist/cli/skills.d.ts +1 -1
  255. package/dist/cli/skills.d.ts.map +1 -1
  256. package/dist/cli/skills.js +18 -3
  257. package/dist/cli/skills.js.map +1 -1
  258. package/dist/client/AssistantChat.d.ts.map +1 -1
  259. package/dist/client/AssistantChat.js +11 -1
  260. package/dist/client/AssistantChat.js.map +1 -1
  261. package/dist/client/agent-chat.d.ts.map +1 -1
  262. package/dist/client/agent-chat.js +15 -2
  263. package/dist/client/agent-chat.js.map +1 -1
  264. package/dist/client/composer/PromptComposer.d.ts.map +1 -1
  265. package/dist/client/composer/PromptComposer.js +35 -1
  266. package/dist/client/composer/PromptComposer.js.map +1 -1
  267. package/dist/client/org/OrgSwitcher.js +1 -1
  268. package/dist/client/org/OrgSwitcher.js.map +1 -1
  269. package/dist/client/sharing/ShareButton.d.ts +1 -1
  270. package/dist/client/sharing/ShareButton.d.ts.map +1 -1
  271. package/dist/client/sharing/ShareButton.js +2 -15
  272. package/dist/client/sharing/ShareButton.js.map +1 -1
  273. package/dist/collab/presence.d.ts +1 -1
  274. package/dist/collab/presence.js +1 -1
  275. package/dist/collab/presence.js.map +1 -1
  276. package/dist/collab/routes.d.ts +1 -1
  277. package/dist/file-upload/actions/upload-image.d.ts +2 -2
  278. package/dist/mcp/connect-route.d.ts.map +1 -1
  279. package/dist/mcp/connect-route.js +34 -5
  280. package/dist/mcp/connect-route.js.map +1 -1
  281. package/dist/notifications/routes.d.ts +2 -2
  282. package/dist/observability/routes.d.ts +8 -8
  283. package/dist/resources/handlers.d.ts +1 -1
  284. package/dist/server/action-discovery.d.ts.map +1 -1
  285. package/dist/server/action-discovery.js +5 -0
  286. package/dist/server/action-discovery.js.map +1 -1
  287. package/dist/server/agent-chat-plugin.d.ts +6 -0
  288. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  289. package/dist/server/agent-chat-plugin.js +12 -3
  290. package/dist/server/agent-chat-plugin.js.map +1 -1
  291. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  292. package/dist/sharing/registry.d.ts.map +1 -1
  293. package/dist/sharing/registry.js +11 -0
  294. package/dist/sharing/registry.js.map +1 -1
  295. package/dist/templates/default/pnpm-workspace.yaml +1 -0
  296. package/dist/templates/workspace-root/pnpm-workspace.yaml +1 -0
  297. package/docs/content/locales/ar-SA/real-time-collaboration.mdx +2 -2
  298. package/docs/content/locales/ar-SA/template-design.mdx +1 -1
  299. package/docs/content/locales/de-DE/real-time-collaboration.mdx +3 -3
  300. package/docs/content/locales/de-DE/template-design.mdx +1 -1
  301. package/docs/content/locales/es-ES/real-time-collaboration.mdx +2 -2
  302. package/docs/content/locales/es-ES/template-design.mdx +1 -1
  303. package/docs/content/locales/fr-FR/real-time-collaboration.mdx +2 -2
  304. package/docs/content/locales/fr-FR/template-design.mdx +1 -1
  305. package/docs/content/locales/hi-IN/template-design.mdx +1 -1
  306. package/docs/content/locales/ja-JP/real-time-collaboration.mdx +2 -2
  307. package/docs/content/locales/ja-JP/template-design.mdx +1 -1
  308. package/docs/content/locales/ko-KR/real-time-collaboration.mdx +2 -2
  309. package/docs/content/locales/ko-KR/template-design.mdx +1 -1
  310. package/docs/content/locales/pt-BR/real-time-collaboration.mdx +2 -2
  311. package/docs/content/locales/pt-BR/template-design.mdx +1 -1
  312. package/docs/content/locales/zh-CN/real-time-collaboration.mdx +2 -2
  313. package/docs/content/locales/zh-CN/template-design.mdx +1 -1
  314. package/docs/content/locales/zh-TW/real-time-collaboration.mdx +2 -2
  315. package/docs/content/locales/zh-TW/template-design.mdx +1 -1
  316. package/docs/content/real-time-collaboration.mdx +2 -2
  317. package/docs/content/template-design.mdx +1 -1
  318. package/package.json +3 -7
  319. package/src/templates/default/pnpm-workspace.yaml +1 -0
  320. package/src/templates/workspace-root/pnpm-workspace.yaml +1 -0
  321. package/corpus/core/src/brand-kit/fig/decode.ts +0 -410
  322. package/corpus/core/src/brand-kit/fig/extract-design-system.ts +0 -947
  323. package/corpus/core/src/brand-kit/fig/fig-to-html.ts +0 -1906
  324. package/corpus/templates/design/actions/import-figma.ts +0 -55
  325. package/corpus/templates/design/changelog/2026-06-28-figma-style-code-design-mode.md +0 -6
  326. package/corpus/templates/design/server/handlers/import-figma-system.ts +0 -86
  327. package/corpus/templates/design/server/routes/api/import-figma-system.post.ts +0 -1
  328. package/corpus/templates/slides/server/handlers/import-figma-system.ts +0 -101
  329. package/corpus/templates/slides/server/routes/api/import-figma-system.post.ts +0 -1
  330. package/dist/brand-kit/fig/decode.d.ts +0 -33
  331. package/dist/brand-kit/fig/decode.d.ts.map +0 -1
  332. package/dist/brand-kit/fig/decode.js +0 -358
  333. package/dist/brand-kit/fig/decode.js.map +0 -1
  334. package/dist/brand-kit/fig/extract-design-system.d.ts +0 -44
  335. package/dist/brand-kit/fig/extract-design-system.d.ts.map +0 -1
  336. package/dist/brand-kit/fig/extract-design-system.js +0 -752
  337. package/dist/brand-kit/fig/extract-design-system.js.map +0 -1
  338. package/dist/brand-kit/fig/fig-to-html.d.ts +0 -246
  339. package/dist/brand-kit/fig/fig-to-html.d.ts.map +0 -1
  340. package/dist/brand-kit/fig/fig-to-html.js +0 -1506
  341. package/dist/brand-kit/fig/fig-to-html.js.map +0 -1
@@ -1,10 +1,4 @@
1
1
  import type { BrandKitData, BrandKitDefaults } from "../types.js";
2
- import { decodeFig } from "./decode.js";
3
- import { extractDesignSystemFromFig } from "./extract-design-system.js";
4
-
5
- export * from "./decode.js";
6
- export * from "./extract-design-system.js";
7
- export * from "./fig-to-html.js";
8
2
 
9
3
  export interface FigBrandKitPreview {
10
4
  gradients: string[];
@@ -25,6 +19,12 @@ export interface FigBrandKitExtraction {
25
19
 
26
20
  export const MAX_FIG_THUMBNAIL_BYTES = 512 * 1024;
27
21
 
22
+ function unsupportedFigImport(): never {
23
+ throw new Error(
24
+ "Local .fig design-system extraction has moved to Builder indexing. Connect Builder and use the design system indexing flow instead.",
25
+ );
26
+ }
27
+
28
28
  export function looksLikeFigFile(data: Uint8Array): boolean {
29
29
  const isZip =
30
30
  data[0] === 0x50 &&
@@ -42,39 +42,19 @@ export function figThumbnailDataUrl(thumbnail: Buffer | null): string | null {
42
42
  }
43
43
 
44
44
  export function extractFigBrandKit(
45
- input: Buffer | Uint8Array,
45
+ _input: Buffer | Uint8Array,
46
46
  ): FigBrandKitExtraction {
47
- const decoded = decodeFig(Buffer.from(input));
48
- if (!decoded.document) {
49
- throw new Error(
50
- "Decoded the file but found no document. It may be a partial or corrupt export.",
51
- );
52
- }
47
+ return unsupportedFigImport();
48
+ }
53
49
 
54
- const extracted = extractDesignSystemFromFig(decoded.document);
55
- const {
56
- customInstructions,
57
- gradients,
58
- palette,
59
- namedColors,
60
- nodeCount,
61
- ...data
62
- } = extracted;
50
+ export function decodeFig(_input: Buffer | Uint8Array): never {
51
+ return unsupportedFigImport();
52
+ }
63
53
 
64
- const thumbnailDataUrl = figThumbnailDataUrl(decoded.thumbnail);
54
+ export function extractDesignSystemFromFig(_document: unknown): never {
55
+ return unsupportedFigImport();
56
+ }
65
57
 
66
- return {
67
- format: decoded.format,
68
- version: decoded.version ?? null,
69
- data,
70
- customInstructions: customInstructions ?? "",
71
- preview: {
72
- gradients: gradients ?? [],
73
- palette: palette ?? [],
74
- namedColors: namedColors ?? {},
75
- thumbnailDataUrl,
76
- nodeCount: nodeCount ?? 0,
77
- imageCount: decoded.images.length,
78
- },
79
- };
58
+ export function figToHtml(_node: unknown): never {
59
+ return unsupportedFigImport();
80
60
  }
@@ -1054,6 +1054,7 @@ function postProcessStandalone(
1054
1054
  sections.overrides = {
1055
1055
  '"@assistant-ui/store"': '">=0.2.9 <0.2.14"',
1056
1056
  '"@assistant-ui/tap"': '"^0.5.14"',
1057
+ nf3: '"0.3.17"',
1057
1058
  };
1058
1059
  }
1059
1060
  let updated = mergeWorkspaceYamlSections(existing, sections);
@@ -927,7 +927,7 @@ Usage:
927
927
  reinstalling app skills/connectors.
928
928
  agent-native app-skill <cmd> Install, launch, or package app-backed skills.
929
929
  cmds: ensure | launch | pack
930
- agent-native skills add assets|content|design-exploration|visual-plan|visual-recap|context-xray
930
+ agent-native skills add assets|content|design-exploration|visual-edit|visual-plan|visual-recap|context-xray
931
931
  Install the skill instructions, register the MCP
932
932
  connector, AND authenticate it in one step.
933
933
  --no-connect skips auth (run 'connect' later);
@@ -392,8 +392,124 @@ function codexMcpHeader(name: string): string {
392
392
  return `[mcp_servers.${tomlQuote(name)}]`;
393
393
  }
394
394
 
395
- function legacyCodexMcpHeader(name: string): string | null {
396
- return /^[A-Za-z0-9_-]+$/.test(name) ? `[mcp_servers.${name}]` : null;
395
+ /**
396
+ * Parse a TOML table-header line such as `[mcp_servers."plan".http_headers]`
397
+ * or `[mcp_servers.plan] # local note` into its decoded dotted-key components
398
+ * (`["mcp_servers", "plan", "http_headers"]`). Returns `null` when the line is
399
+ * not a single `[table]` header — blank lines, key/value pairs, comments,
400
+ * invalid trailing content, and `[[array-of-tables]]` headers all return `null`,
401
+ * so the result doubles as a reliable "is this line a table boundary?" check.
402
+ *
403
+ * Handles bare keys (`A-Za-z0-9_-`) and quoted keys (basic `"..."` with `\`
404
+ * escapes, and literal `'...'`), tolerating whitespace around the dot
405
+ * separators per the TOML spec. Quoted-key escape handling mirrors the inverse
406
+ * of `tomlQuote` (`\"` → `"`, `\\` → `\`).
407
+ */
408
+ function parseTomlTableHeader(line: string): string[] | null {
409
+ const trimmed = line.trim();
410
+ if (trimmed.length < 2 || trimmed[0] !== "[") return null;
411
+ // `[[array-of-tables]]` is a different construct — leave it untouched.
412
+ if (trimmed[1] === "[") return null;
413
+
414
+ let quote: '"' | "'" | null = null;
415
+ let escaped = false;
416
+ let closeIndex = -1;
417
+ for (let i = 1; i < trimmed.length; i++) {
418
+ const ch = trimmed[i];
419
+ if (quote === '"') {
420
+ if (escaped) {
421
+ escaped = false;
422
+ continue;
423
+ }
424
+ if (ch === "\\") {
425
+ escaped = true;
426
+ continue;
427
+ }
428
+ if (ch === '"') quote = null;
429
+ continue;
430
+ }
431
+ if (quote === "'") {
432
+ if (ch === "'") quote = null;
433
+ continue;
434
+ }
435
+ if (ch === '"' || ch === "'") {
436
+ quote = ch;
437
+ continue;
438
+ }
439
+ if (ch === "]") {
440
+ closeIndex = i;
441
+ break;
442
+ }
443
+ }
444
+ if (closeIndex < 0) return null;
445
+ const trailing = trimmed.slice(closeIndex + 1).trim();
446
+ if (trailing && !trailing.startsWith("#")) return null;
447
+
448
+ const inner = trimmed.slice(1, closeIndex);
449
+ const keys: string[] = [];
450
+ const isWs = (c: string) => c === " " || c === "\t";
451
+ const isBare = (c: string) => /[A-Za-z0-9_-]/.test(c);
452
+ let i = 0;
453
+ let expectKey = true;
454
+ while (i < inner.length) {
455
+ while (i < inner.length && isWs(inner[i])) i++;
456
+ if (i >= inner.length) break;
457
+ const ch = inner[i];
458
+ if (ch === ".") {
459
+ if (expectKey) return null; // leading or doubled dot
460
+ expectKey = true;
461
+ i++;
462
+ continue;
463
+ }
464
+ if (!expectKey) return null; // two keys with no dot between them
465
+ if (ch === '"' || ch === "'") {
466
+ const quote = ch;
467
+ i++;
468
+ let key = "";
469
+ while (i < inner.length && inner[i] !== quote) {
470
+ if (quote === '"' && inner[i] === "\\" && i + 1 < inner.length) {
471
+ const next = inner[i + 1];
472
+ key += next === '"' ? '"' : next === "\\" ? "\\" : `\\${next}`;
473
+ i += 2;
474
+ continue;
475
+ }
476
+ key += inner[i];
477
+ i++;
478
+ }
479
+ if (i >= inner.length) return null; // unterminated quote
480
+ i++; // consume the closing quote
481
+ keys.push(key);
482
+ expectKey = false;
483
+ } else if (isBare(ch)) {
484
+ let key = "";
485
+ while (i < inner.length && isBare(inner[i])) {
486
+ key += inner[i];
487
+ i++;
488
+ }
489
+ keys.push(key);
490
+ expectKey = false;
491
+ } else {
492
+ return null; // unexpected character — not a table header
493
+ }
494
+ }
495
+ if (expectKey) return null; // empty header or trailing dot
496
+ return keys.length ? keys : null;
497
+ }
498
+
499
+ /**
500
+ * The MCP server name a TOML table header belongs to, or `undefined` when the
501
+ * header is not under `[mcp_servers.*]`. The server's own table
502
+ * (`[mcp_servers.<name>]`) AND every sub-table of it
503
+ * (`[mcp_servers.<name>.http_headers]`, `[mcp_servers.<name>.env]`, …) resolve
504
+ * to the same `<name>`, so callers can treat a server and all its sub-tables as
505
+ * one removable unit. This is what prevents a re-install from orphaning a stale
506
+ * `[mcp_servers.<name>.http_headers]` sub-table that would then collide with the
507
+ * freshly written inline `http_headers` (a TOML duplicate-key error).
508
+ */
509
+ function codexServerNameOfHeader(line: string): string | undefined {
510
+ const keys = parseTomlTableHeader(line);
511
+ if (!keys || keys.length < 2 || keys[0] !== "mcp_servers") return undefined;
512
+ return keys[1];
397
513
  }
398
514
 
399
515
  /** Build a `[mcp_servers.<name>]` block for an HTTP-type MCP server. */
@@ -439,11 +555,16 @@ export function buildCodexLocalBlock(
439
555
  }
440
556
 
441
557
  /**
442
- * Replace (or append) the `[mcp_servers.<name>]` block in a TOML file
443
- * without disturbing other content. A block is the header line plus every
444
- * following line until the next top-level `[` table header or EOF. Pass
445
- * `block === null` to remove the block. Identical algorithm to `mcp.ts`'s
446
- * `writeCodexBlock` so the two never diverge.
558
+ * Replace (or append) the entire `[mcp_servers.<name>]` footprint in a TOML
559
+ * file without disturbing other content. The footprint is the server's own
560
+ * table AND every sub-table of it (`[mcp_servers.<name>.http_headers]`,
561
+ * `[mcp_servers.<name>.env]`, …), each spanning its header line plus every
562
+ * following line until the next table header or EOF. Removing the whole
563
+ * footprint — wherever the pieces sit in the file — is what keeps a re-install
564
+ * from leaving a stale sub-table that collides with the freshly written inline
565
+ * block (a TOML duplicate-key error). Matches both the canonical quoted header
566
+ * and the legacy bare header. Pass `block === null` to remove the footprint.
567
+ * Identical algorithm to `mcp.ts`'s `writeCodexBlock` so the two never diverge.
447
568
  */
448
569
  export function writeCodexBlock(
449
570
  file: string,
@@ -457,22 +578,18 @@ export function writeCodexBlock(
457
578
  content = "";
458
579
  }
459
580
 
460
- const headers = new Set(
461
- [codexMcpHeader(name), legacyCodexMcpHeader(name)].filter(
462
- Boolean,
463
- ) as string[],
464
- );
465
581
  const lines = content.split(/\r?\n/);
466
582
  const out: string[] = [];
467
583
  let i = 0;
468
584
  let removed = false;
469
585
  while (i < lines.length) {
470
586
  const line = lines[i];
471
- if (headers.has(line.trim())) {
472
- // Skip this block entirely (header + body until next table header).
587
+ if (codexServerNameOfHeader(line) === name) {
588
+ // Skip this table and its body (until the next table header), covering
589
+ // the server table itself and any of its sub-tables.
473
590
  removed = true;
474
591
  i++;
475
- while (i < lines.length && !/^\s*\[/.test(lines[i])) i++;
592
+ while (i < lines.length && parseTomlTableHeader(lines[i]) === null) i++;
476
593
  continue;
477
594
  }
478
595
  out.push(line);
@@ -496,12 +613,9 @@ export function writeCodexBlock(
496
613
  export function codexHasBlock(file: string, name: string): boolean {
497
614
  try {
498
615
  const content = fs.readFileSync(file, "utf-8");
499
- const headers = new Set(
500
- [codexMcpHeader(name), legacyCodexMcpHeader(name)].filter(
501
- Boolean,
502
- ) as string[],
503
- );
504
- return content.split(/\r?\n/).some((line) => headers.has(line.trim()));
616
+ return content
617
+ .split(/\r?\n/)
618
+ .some((line) => codexServerNameOfHeader(line) === name);
505
619
  } catch {
506
620
  return false;
507
621
  }
@@ -620,8 +734,11 @@ export function removeJsonSameUrlDuplicates(
620
734
 
621
735
  /**
622
736
  * After writing the canonical `keepName` Codex block, remove any OTHER
623
- * `[mcp_servers.*]` blocks in the same TOML file whose `url =` line
624
- * normalises to the same value as `mcpUrl`. Returns removed entry names.
737
+ * `[mcp_servers.*]` servers in the same TOML file whose `url =` line normalises
738
+ * to the same value as `mcpUrl`. A server's entire footprint is removed its
739
+ * own table AND any sub-tables (`.http_headers`, `.env`, …), even when they are
740
+ * not contiguous — so cleanup never leaves an orphaned sub-table behind.
741
+ * Returns removed entry names in first-seen order.
625
742
  */
626
743
  export function removeCodexSameUrlDuplicates(
627
744
  file: string,
@@ -638,52 +755,71 @@ export function removeCodexSameUrlDuplicates(
638
755
  if (!targetCanonical) return [];
639
756
 
640
757
  const lines = content.split(/\r?\n/);
641
- const out: string[] = [];
642
- const removed: string[] = [];
758
+
759
+ // Pass 1: map each server name to the canonical URL declared on its own
760
+ // table, preserving first-seen order. Sub-tables don't carry the URL, so they
761
+ // only register the name.
762
+ const serverUrls = new Map<string, string | undefined>();
643
763
  let i = 0;
644
764
  while (i < lines.length) {
645
- const line = lines[i];
646
- const trimmed = line.trim();
647
- const quoted = trimmed.match(/^\[mcp_servers\."((?:\\.|[^"])*)"\]$/);
648
- const bare = trimmed.match(/^\[mcp_servers\.([A-Za-z0-9_-]+)\]$/);
649
- const serverName = quoted
650
- ? quoted[1].replace(/\\"/g, '"').replace(/\\\\/g, "\\")
651
- : bare?.[1];
652
- if (serverName !== undefined && serverName !== keepName) {
653
- // Collect the block
654
- const block: string[] = [line];
765
+ const keys = parseTomlTableHeader(lines[i]);
766
+ const name =
767
+ keys && keys.length >= 2 && keys[0] === "mcp_servers"
768
+ ? keys[1]
769
+ : undefined;
770
+ if (name === undefined) {
655
771
  i++;
656
- while (i < lines.length && !/^\s*\[/.test(lines[i])) {
657
- block.push(lines[i]);
658
- i++;
659
- }
660
- // Check url in block
661
- const urlMatch = block
772
+ continue;
773
+ }
774
+ const isServerTable = keys!.length === 2;
775
+ const body: string[] = [];
776
+ i++;
777
+ while (i < lines.length && parseTomlTableHeader(lines[i]) === null) {
778
+ body.push(lines[i]);
779
+ i++;
780
+ }
781
+ if (isServerTable) {
782
+ const urlMatch = body
662
783
  .join("\n")
663
784
  .match(/^\s*url\s*=\s*"((?:\\.|[^"])*)"/m);
664
785
  const blockUrl = urlMatch
665
786
  ? urlMatch[1].replace(/\\"/g, '"').replace(/\\\\/g, "\\")
666
787
  : undefined;
667
- if (canonicalUrl(blockUrl) === targetCanonical) {
668
- removed.push(serverName);
669
- // Skip this block (don't push to out)
670
- continue;
671
- }
672
- // Not a duplicate — keep it
673
- for (const l of block) out.push(l);
788
+ serverUrls.set(name, canonicalUrl(blockUrl));
789
+ } else if (!serverUrls.has(name)) {
790
+ serverUrls.set(name, undefined);
791
+ }
792
+ }
793
+
794
+ const removeSet = new Set<string>();
795
+ for (const [name, canonical] of serverUrls) {
796
+ if (name !== keepName && canonical && canonical === targetCanonical) {
797
+ removeSet.add(name);
798
+ }
799
+ }
800
+ if (removeSet.size === 0) return [];
801
+
802
+ // Pass 2: rebuild, dropping every table/sub-table belonging to a removed
803
+ // server.
804
+ const out: string[] = [];
805
+ i = 0;
806
+ while (i < lines.length) {
807
+ const name = codexServerNameOfHeader(lines[i]);
808
+ if (name !== undefined && removeSet.has(name)) {
809
+ i++;
810
+ while (i < lines.length && parseTomlTableHeader(lines[i]) === null) i++;
674
811
  continue;
675
812
  }
676
- out.push(line);
813
+ out.push(lines[i]);
677
814
  i++;
678
815
  }
679
816
 
680
- if (removed.length === 0) return [];
681
817
  const next = out
682
818
  .join("\n")
683
819
  .replace(/\n{3,}/g, "\n\n")
684
820
  .replace(/\n*$/, "\n");
685
821
  writeFileAtomic(file, next);
686
- return removed;
822
+ return [...removeSet];
687
823
  }
688
824
 
689
825
  /**
@@ -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
@@ -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>