@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
@@ -0,0 +1,181 @@
1
+ import { eq } from "drizzle-orm";
2
+ import { nanoid } from "nanoid";
3
+
4
+ import { getDb, schema } from "../db/index.js";
5
+
6
+ type BuilderDesignSystemIndexResult = {
7
+ designSystemId: string;
8
+ jobId: string;
9
+ builderUrl: string;
10
+ };
11
+
12
+ export function localBuilderDesignSystemId(
13
+ builderDesignSystemId: string,
14
+ ): string {
15
+ const slug = builderDesignSystemId
16
+ .replace(/[^a-zA-Z0-9_-]+/g, "-")
17
+ .replace(/^-+|-+$/g, "")
18
+ .slice(0, 96);
19
+ return `builder-${slug || "design-system"}`;
20
+ }
21
+
22
+ function builderProxyData({
23
+ builderDesignSystemId,
24
+ jobId,
25
+ builderUrl,
26
+ projectName,
27
+ description,
28
+ }: {
29
+ builderDesignSystemId: string;
30
+ jobId: string;
31
+ builderUrl: string;
32
+ projectName?: string;
33
+ description?: string;
34
+ }) {
35
+ return JSON.stringify({
36
+ source: "builder",
37
+ builderDesignSystemId,
38
+ builderJobId: jobId,
39
+ builderUrl,
40
+ colors: {
41
+ primary: "var(--primary)",
42
+ secondary: "var(--secondary)",
43
+ accent: "var(--accent)",
44
+ background: "var(--background)",
45
+ surface: "var(--card)",
46
+ text: "var(--foreground)",
47
+ textMuted: "var(--muted-foreground)",
48
+ },
49
+ typography: {
50
+ headingFont: "inherit",
51
+ bodyFont: "inherit",
52
+ headingWeight: "700",
53
+ bodyWeight: "400",
54
+ headingSizes: { h1: "48px", h2: "32px", h3: "24px" },
55
+ },
56
+ spacing: { elementGap: "24px", pagePadding: "48px" },
57
+ borders: { radius: "12px", accentWidth: "1px" },
58
+ logos: [],
59
+ notes: [
60
+ "This is a local proxy for a Builder-indexed design system.",
61
+ `Builder design system id: ${builderDesignSystemId}`,
62
+ `Builder indexing job id: ${jobId}`,
63
+ `Builder URL: ${builderUrl}`,
64
+ projectName ? `Requested name: ${projectName}` : "",
65
+ description ? `Context: ${description}` : "",
66
+ "Use Builder as the source of truth for extracted tokens and guidance.",
67
+ ]
68
+ .filter(Boolean)
69
+ .join("\n"),
70
+ });
71
+ }
72
+
73
+ function builderProxyInstructions({
74
+ builderDesignSystemId,
75
+ jobId,
76
+ builderUrl,
77
+ }: {
78
+ builderDesignSystemId: string;
79
+ jobId: string;
80
+ builderUrl: string;
81
+ }) {
82
+ return [
83
+ "This design system is indexed and owned by Builder.",
84
+ `Builder design system id: ${builderDesignSystemId}`,
85
+ `Builder job id: ${jobId}`,
86
+ `Builder URL: ${builderUrl}`,
87
+ "When generating designs, treat Builder as the source of truth for the final extracted tokens, assets, and guidance.",
88
+ ].join("\n");
89
+ }
90
+
91
+ export async function upsertBuilderProxyDesignSystem({
92
+ result,
93
+ ownerEmail,
94
+ orgId,
95
+ projectName,
96
+ description,
97
+ }: {
98
+ result: BuilderDesignSystemIndexResult;
99
+ ownerEmail: string;
100
+ orgId?: string | null;
101
+ projectName?: string;
102
+ description?: string;
103
+ }) {
104
+ const db = getDb();
105
+ const now = new Date().toISOString();
106
+ const baseLocalDesignSystemId = localBuilderDesignSystemId(
107
+ result.designSystemId,
108
+ );
109
+ const title = projectName?.trim() || "Builder indexed design system";
110
+ const localData = builderProxyData({
111
+ builderDesignSystemId: result.designSystemId,
112
+ jobId: result.jobId,
113
+ builderUrl: result.builderUrl,
114
+ projectName,
115
+ description,
116
+ });
117
+ const customInstructions = builderProxyInstructions({
118
+ builderDesignSystemId: result.designSystemId,
119
+ jobId: result.jobId,
120
+ builderUrl: result.builderUrl,
121
+ });
122
+ const [existing] = await db
123
+ .select({
124
+ id: schema.designSystems.id,
125
+ ownerEmail: schema.designSystems.ownerEmail,
126
+ })
127
+ .from(schema.designSystems)
128
+ .where(eq(schema.designSystems.id, baseLocalDesignSystemId))
129
+ .limit(1);
130
+ const localDesignSystemId =
131
+ existing && existing.ownerEmail !== ownerEmail
132
+ ? `${baseLocalDesignSystemId}-${nanoid(8)}`
133
+ : baseLocalDesignSystemId;
134
+ if (existing && existing.ownerEmail === ownerEmail) {
135
+ await db
136
+ .update(schema.designSystems)
137
+ .set({
138
+ title,
139
+ description:
140
+ description ??
141
+ `Builder indexed design system ${result.designSystemId}`,
142
+ data: localData,
143
+ assets: "[]",
144
+ customInstructions,
145
+ updatedAt: now,
146
+ })
147
+ .where(eq(schema.designSystems.id, existing.id));
148
+ } else {
149
+ const [ownedSystem] = await db
150
+ .select({ id: schema.designSystems.id })
151
+ .from(schema.designSystems)
152
+ .where(eq(schema.designSystems.ownerEmail, ownerEmail))
153
+ .limit(1);
154
+ await db.insert(schema.designSystems).values({
155
+ id: localDesignSystemId,
156
+ title,
157
+ description:
158
+ description ?? `Builder indexed design system ${result.designSystemId}`,
159
+ data: localData,
160
+ assets: "[]",
161
+ customInstructions,
162
+ isDefault: !ownedSystem,
163
+ ownerEmail,
164
+ orgId: orgId ?? null,
165
+ createdAt: now,
166
+ updatedAt: now,
167
+ });
168
+ }
169
+
170
+ return {
171
+ localDesignSystemId,
172
+ instructions: [
173
+ "Builder design-system indexing has started.",
174
+ `Builder design system: ${result.designSystemId}`,
175
+ `Local selectable design system: ${localDesignSystemId}`,
176
+ `Builder job: ${result.jobId}`,
177
+ `Open: ${result.builderUrl}`,
178
+ "Use the local design system id in Design flows; Builder remains the source of truth for the indexed brand kit.",
179
+ ].join("\n"),
180
+ };
181
+ }
@@ -114,7 +114,10 @@ function injectResolvedTokensIntoHtml(
114
114
  ): string {
115
115
  const entries = Object.entries(resolvedCssVars);
116
116
  if (entries.length === 0) return content;
117
- if (/applied-design-tokens/.test(content)) return content;
117
+ if (
118
+ /data-applied-design-tokens|\/\* applied-design-tokens \*\//.test(content)
119
+ )
120
+ return content;
118
121
 
119
122
  const decls = entries
120
123
  .map(([name, value]) => ` ${name}: ${value}; /* applied-design-tokens */`)
@@ -124,9 +127,35 @@ function injectResolvedTokensIntoHtml(
124
127
  const rootOpen = content.lastIndexOf(":root");
125
128
  if (rootOpen !== -1) {
126
129
  const braceOpen = content.indexOf("{", rootOpen);
127
- const braceClose = content.indexOf("}", braceOpen);
128
- if (braceOpen !== -1 && braceClose !== -1) {
129
- return `${content.slice(0, braceClose)}\n${decls}\n${content.slice(braceClose)}`;
130
+ if (braceOpen !== -1) {
131
+ // Walk forward with a brace-depth counter so values containing `}`
132
+ // (e.g. url("}"), attr() fallbacks) don't fool us into injecting inside
133
+ // the value rather than at the end of the :root block.
134
+ let depth = 0;
135
+ let braceClose = -1;
136
+ let inSingle = false;
137
+ let inDouble = false;
138
+ for (let i = braceOpen; i < content.length; i++) {
139
+ const ch = content[i];
140
+ if (ch === "'" && !inDouble) {
141
+ inSingle = !inSingle;
142
+ } else if (ch === '"' && !inSingle) {
143
+ inDouble = !inDouble;
144
+ } else if (!inSingle && !inDouble) {
145
+ if (ch === "{") {
146
+ depth++;
147
+ } else if (ch === "}") {
148
+ depth--;
149
+ if (depth === 0) {
150
+ braceClose = i;
151
+ break;
152
+ }
153
+ }
154
+ }
155
+ }
156
+ if (braceClose !== -1) {
157
+ return `${content.slice(0, braceClose)}\n${decls}\n${content.slice(braceClose)}`;
158
+ }
130
159
  }
131
160
  }
132
161
 
@@ -17,6 +17,12 @@ function escapeHtml(str: string): string {
17
17
  .replace(/"/g, "&quot;");
18
18
  }
19
19
 
20
+ function extractRenderableHtml(content: string): string {
21
+ const bodyMatch = content.match(/<body\b[^>]*>([\s\S]*?)<\/body>/i);
22
+ if (bodyMatch) return bodyMatch[1].trim();
23
+ return content;
24
+ }
25
+
20
26
  export function safeExportBaseName(title: string | null | undefined): string {
21
27
  const safe = (title || "design")
22
28
  .replace(/[^a-zA-Z0-9_-]/g, "-")
@@ -42,7 +48,10 @@ export function buildStandaloneHtml(args: {
42
48
  const jsxFiles = files.filter((f) => f.fileType === "jsx");
43
49
  const indexHtml =
44
50
  files.find((f) => f.filename === "index.html") ?? htmlFiles[0];
45
- const combinedCss = cssFiles.map((f) => f.content ?? "").join("\n\n");
51
+ const combinedCss = cssFiles
52
+ .map((f) => f.content ?? "")
53
+ .join("\n\n")
54
+ .replace(/<\/style/gi, "<\\/style");
46
55
 
47
56
  if (
48
57
  indexHtml?.content &&
@@ -53,7 +62,7 @@ export function buildStandaloneHtml(args: {
53
62
  // so multi-file designs still ship in one bundle.
54
63
  const extraBody = [...htmlFiles, ...jsxFiles]
55
64
  .filter((f) => f !== indexHtml)
56
- .map((f) => f.content ?? "")
65
+ .map((f) => extractRenderableHtml(f.content ?? ""))
57
66
  .join("\n\n");
58
67
  if (extraBody.trim()) {
59
68
  // Inline JS / template literals can contain `</body>` strings, so favor
@@ -85,7 +94,7 @@ export function buildStandaloneHtml(args: {
85
94
  }
86
95
 
87
96
  const combinedBody = [...htmlFiles, ...jsxFiles]
88
- .map((f) => f.content ?? "")
97
+ .map((f) => extractRenderableHtml(f.content ?? ""))
89
98
  .join("\n\n");
90
99
 
91
100
  return `<!DOCTYPE html>
@@ -128,18 +137,36 @@ function normalizeHtmlForSvg(html: string): string {
128
137
  "&amp;",
129
138
  );
130
139
 
131
- if (/<html\b[^>]*\bxmlns=/i.test(withEscapedBareAmpersands)) {
132
- return withEscapedBareAmpersands;
140
+ // Wrap <script> and <style> block content in CDATA so that JS/CSS with
141
+ // raw `<`, `>`, or `&&` survives the XML parse required by SVG foreignObject.
142
+ const withCdata = withEscapedBareAmpersands
143
+ .replace(
144
+ /(<script\b[^>]*>)([\s\S]*?)(<\/script>)/gi,
145
+ (_, open: string, content: string, close: string) => {
146
+ if (content.includes("//]]>")) return _;
147
+ return `${open}//<![CDATA[\n${content}\n//]]>${close}`;
148
+ },
149
+ )
150
+ .replace(
151
+ /(<style\b[^>]*>)([\s\S]*?)(<\/style>)/gi,
152
+ (_, open: string, content: string, close: string) => {
153
+ if (content.includes("]]>")) return _;
154
+ return `${open}<![CDATA[\n${content}\n]]>${close}`;
155
+ },
156
+ );
157
+
158
+ if (/<html\b[^>]*\bxmlns=/i.test(withCdata)) {
159
+ return withCdata;
133
160
  }
134
161
 
135
- if (/<html\b/i.test(withEscapedBareAmpersands)) {
136
- return withEscapedBareAmpersands.replace(
162
+ if (/<html\b/i.test(withCdata)) {
163
+ return withCdata.replace(
137
164
  /<html\b/i,
138
165
  '<html xmlns="http://www.w3.org/1999/xhtml"',
139
166
  );
140
167
  }
141
168
 
142
- return `<html xmlns="http://www.w3.org/1999/xhtml"><body>${withEscapedBareAmpersands}</body></html>`;
169
+ return `<html xmlns="http://www.w3.org/1999/xhtml"><body>${withCdata}</body></html>`;
143
170
  }
144
171
 
145
172
  export function buildSvgForeignObject(args: {
@@ -7,6 +7,8 @@ import {
7
7
  import actionsRegistry from "../../.generated/actions-registry.js";
8
8
  import "../register-secrets.js";
9
9
 
10
+ const DESIGN_BACKGROUND_RUN_SOFT_TIMEOUT_MS = 13 * 60_000;
11
+
10
12
  const INITIAL_TOOL_NAMES = [
11
13
  "view-screen",
12
14
  "list-designs",
@@ -37,6 +39,8 @@ export default createAgentChatPlugin({
37
39
  // paginate, and reduce provider data through providerFetch() without us
38
40
  // hardcoding one action per GitHub endpoint.
39
41
  codeExecution: { production: "sandboxed" },
42
+ durableBackgroundRuns: true,
43
+ runSoftTimeoutMs: DESIGN_BACKGROUND_RUN_SOFT_TIMEOUT_MS,
40
44
  resolveOrgId: async (event) => (await getOrgContext(event)).orgId,
41
45
  systemPrompt: `You are an AI prototyping assistant. You create and edit designs, files, design systems, variants, exports, sharing, and connected repository context through actions and shared application state.
42
46
 
@@ -1,6 +1,11 @@
1
1
  import { createAuthPlugin } from "@agent-native/core/server";
2
2
 
3
3
  export default createAuthPlugin({
4
+ workspaceAppAudience: "internal",
5
+ // The visual-edit entry route and public design editor links can load without
6
+ // a session. Creating, mutating, generating, and sharing designs still go
7
+ // through authenticated actions.
8
+ workspaceAppPublicPaths: ["/visual-edit", "/design"],
4
9
  marketing: {
5
10
  appName: "Agent-Native Design",
6
11
  tagline:
@@ -19,5 +24,9 @@ export default createAuthPlugin({
19
24
  // publicPaths uses prefix matching, so this covers
20
25
  // /api/design-handoff/<id>?token=... while keeping every other /api/* and
21
26
  // /_agent-native/* route behind auth.
22
- publicPaths: ["/api/design-handoff"],
27
+ publicPaths: [
28
+ "/api/design-handoff",
29
+ "/__manifest",
30
+ "/_agent-native/actions/get-design",
31
+ ],
23
32
  });
@@ -0,0 +1 @@
1
+ export { indexDesignSystemWithBuilder as default } from "../../handlers/index-design-system-with-builder";
@@ -81,6 +81,8 @@ export interface TweakDefinition {
81
81
  step?: number;
82
82
  defaultValue: string | number | boolean;
83
83
  cssVar?: string;
84
+ /** CSS unit to append when resolving a numeric slider value, e.g. "px" or "rem". When omitted, "px" is inferred for vars whose name contains "radius" and no unit is added for others. */
85
+ unit?: string;
84
86
  }
85
87
 
86
88
  // --- Question Flow ---
@@ -30,8 +30,9 @@ function escapeRegExp(value: string): string {
30
30
 
31
31
  function countOccurrences(haystack: string, needle: string): number {
32
32
  if (!needle) return 0;
33
- // Step by 1 (not by needle length) so self-overlapping matches e.g. "aa"
34
- // inside "aaa" are both counted and treated as ambiguous, not unique.
33
+ // Step by 1 (not by needle length) so self-overlapping matches are counted.
34
+ // A count > 1 does NOT immediately throw Strategy 2 runs first and may
35
+ // still resolve a unique non-overlapping match.
35
36
  let count = 0;
36
37
  let idx = haystack.indexOf(needle);
37
38
  while (idx !== -1) {
@@ -61,11 +62,10 @@ export function applyOneEdit(
61
62
  // Strategy 1 — exact substring.
62
63
  const exact = countOccurrences(content, search);
63
64
  if (exact === 1) return content.split(search).join(replace);
64
- if (exact > 1) {
65
- throw new Error(
66
- `Edit ${index + 1}: "search" matched ${exact} places add more surrounding context so it matches exactly one location.`,
67
- );
68
- }
65
+ // When exact > 1 (including self-overlapping matches), fall through to
66
+ // Strategy 2 before declaring ambiguity. Strategy 2 uses a non-overlapping
67
+ // regex scan, so a search string that appears self-overlapping under Strategy
68
+ // 1 may still resolve to a single unique whitespace-flexible match.
69
69
 
70
70
  // Strategy 2 — whitespace-flexible.
71
71
  const pattern = escapeRegExp(search).replace(/\s+/g, "\\s+");
@@ -77,8 +77,12 @@ export function applyOneEdit(
77
77
  return content.replace(re, () => replace);
78
78
  }
79
79
  if (flexible > 1) {
80
+ const detail =
81
+ exact > 1
82
+ ? `${exact} places (exact) and ${flexible} places (whitespace-insensitive)`
83
+ : `${flexible} places (whitespace-insensitive)`;
80
84
  throw new Error(
81
- `Edit ${index + 1}: "search" matched ${flexible} places (whitespace-insensitive) — add more surrounding context.`,
85
+ `Edit ${index + 1}: "search" matched ${detail} — add more surrounding context so it matches exactly one location.`,
82
86
  );
83
87
  }
84
88
 
@@ -346,7 +346,10 @@ export function assignRegions(
346
346
  const requestedColumns =
347
347
  options.columns == null
348
348
  ? maxColumns
349
- : getWholeNumberAtLeast(options.columns, maxColumns, 1);
349
+ : Math.min(
350
+ maxColumns,
351
+ getWholeNumberAtLeast(options.columns, maxColumns, 1),
352
+ );
350
353
  const columns = Math.min(total, requestedColumns);
351
354
 
352
355
  return Array.from({ length: total }, (_, index) => {
@@ -563,9 +566,24 @@ export function resizeFrameFromDelta(
563
566
  }
564
567
  }
565
568
 
569
+ const preClampWidth = width;
570
+ const preClampHeight = height;
566
571
  width = Math.max(options.minWidth ?? MIN_CANVAS_FRAME_WIDTH, width);
567
572
  height = Math.max(options.minHeight ?? MIN_CANVAS_FRAME_HEIGHT, height);
568
573
 
574
+ if (options.preserveAspectRatio) {
575
+ const widthClamped = width > preClampWidth;
576
+ const heightClamped = height > preClampHeight;
577
+ if (widthClamped && !heightClamped) {
578
+ height = width / ratio;
579
+ } else if (heightClamped && !widthClamped) {
580
+ width = height * ratio;
581
+ } else if (widthClamped && heightClamped) {
582
+ // Both axes hit their minimum; width wins as the primary authority
583
+ height = width / ratio;
584
+ }
585
+ }
586
+
569
587
  return {
570
588
  ...origin,
571
589
  x: getResizedAxisStart(
@@ -557,6 +557,20 @@ const NON_VISUAL_TAGS = new Set([
557
557
 
558
558
  const RAW_TEXT_VISUAL_TAGS = new Set(["textarea"]);
559
559
 
560
+ // HTML5 elements that are implicitly closed when a sibling of the same (or
561
+ // related) type opens, because their closing tags are optional per the spec.
562
+ const IMPLICIT_CLOSE_TAGS: Map<string, Set<string>> = new Map([
563
+ ["li", new Set(["li"])],
564
+ ["p", new Set(["p"])],
565
+ ["td", new Set(["td", "th"])],
566
+ ["th", new Set(["td", "th"])],
567
+ ["tr", new Set(["tr"])],
568
+ ["dt", new Set(["dt", "dd"])],
569
+ ["dd", new Set(["dt", "dd"])],
570
+ ["option", new Set(["option"])],
571
+ ["optgroup", new Set(["optgroup"])],
572
+ ]);
573
+
560
574
  const DATA_SELECTOR_PRIORITY = [
561
575
  "data-agent-native-node-id",
562
576
  "data-code-layer-id",
@@ -1017,15 +1031,36 @@ function parseHtmlElements(html: string): ParsedElement[] {
1017
1031
  const element = elements[stack[i]];
1018
1032
  if (!element) continue;
1019
1033
  stack.pop();
1020
- element.closeStart = match.index;
1021
- element.closeEnd = match.index + raw.length;
1022
- element.contentEnd = match.index;
1023
- element.end = match.index + raw.length;
1024
- if (element.tag === tag) break;
1034
+ if (element.tag === tag) {
1035
+ element.closeStart = match.index;
1036
+ element.closeEnd = match.index + raw.length;
1037
+ element.contentEnd = match.index;
1038
+ element.end = match.index + raw.length;
1039
+ break;
1040
+ } else {
1041
+ // Implicitly close optional-close-tag elements (e.g. <li>, <p>)
1042
+ // without attributing the parent's close tag to them.
1043
+ element.contentEnd = match.index;
1044
+ element.end = match.index;
1045
+ }
1025
1046
  }
1026
1047
  continue;
1027
1048
  }
1028
1049
 
1050
+ // Auto-close HTML5 optional-close-tag elements when a sibling of the same
1051
+ // type (or a related type) opens. This mirrors how browsers handle elements
1052
+ // like <li>, <p>, <td>, <th>, <tr>, <dt>, <dd>, <option>, <optgroup>.
1053
+ const stackTopTag =
1054
+ stack.length > 0 ? elements[stack[stack.length - 1]]?.tag : undefined;
1055
+ if (stackTopTag && IMPLICIT_CLOSE_TAGS.get(tag)?.has(stackTopTag)) {
1056
+ const popped = stack.pop()!;
1057
+ const poppedElement = elements[popped];
1058
+ if (poppedElement) {
1059
+ poppedElement.contentEnd = match.index;
1060
+ poppedElement.end = match.index;
1061
+ }
1062
+ }
1063
+
1029
1064
  const parentIndex = stack.length > 0 ? stack[stack.length - 1] : undefined;
1030
1065
  const parentKey = `${parentIndex ?? "root"}:${tag}`;
1031
1066
  const nthOfType = (sameTypeCounts.get(parentKey) ?? 0) + 1;
@@ -1140,7 +1175,7 @@ function pathSelector(
1140
1175
  ? undefined
1141
1176
  : elements[current.parentIndex];
1142
1177
  }
1143
- return parts.slice(-5).join(" > ");
1178
+ return parts.join(" > ");
1144
1179
  }
1145
1180
 
1146
1181
  function primarySelector(
@@ -1314,24 +1349,32 @@ function layoutFor(
1314
1349
  style.display ??
1315
1350
  (classes.has("flex")
1316
1351
  ? "flex"
1317
- : classes.has("grid")
1318
- ? "grid"
1319
- : classes.has("hidden")
1320
- ? "none"
1321
- : classes.has("block")
1322
- ? "block"
1323
- : classes.has("inline-block")
1324
- ? "inline-block"
1325
- : undefined);
1352
+ : classes.has("inline-flex")
1353
+ ? "inline-flex"
1354
+ : classes.has("grid")
1355
+ ? "grid"
1356
+ : classes.has("inline-grid")
1357
+ ? "inline-grid"
1358
+ : classes.has("hidden")
1359
+ ? "none"
1360
+ : classes.has("block")
1361
+ ? "block"
1362
+ : classes.has("inline-block")
1363
+ ? "inline-block"
1364
+ : undefined);
1326
1365
  const parentDisplay =
1327
1366
  parentStyle?.display ??
1328
1367
  (parentClasses?.has("flex")
1329
1368
  ? "flex"
1330
- : parentClasses?.has("grid")
1331
- ? "grid"
1332
- : parentClasses?.has("hidden")
1333
- ? "none"
1334
- : undefined);
1369
+ : parentClasses?.has("inline-flex")
1370
+ ? "inline-flex"
1371
+ : parentClasses?.has("grid")
1372
+ ? "grid"
1373
+ : parentClasses?.has("inline-grid")
1374
+ ? "inline-grid"
1375
+ : parentClasses?.has("hidden")
1376
+ ? "none"
1377
+ : undefined);
1335
1378
  const flexDirection =
1336
1379
  style["flex-direction"] ??
1337
1380
  (classes.has("flex-col")
@@ -1921,11 +1964,8 @@ function selectorMatches(
1921
1964
  const selectorHasDirectPath = normalizedSelector.includes(" > ");
1922
1965
  if (
1923
1966
  selectorHasDirectPath &&
1924
- normalizedNodeSelectors.some(
1925
- (candidate) =>
1926
- candidate.endsWith(` > ${normalizedSelector}`) ||
1927
- (candidate.includes(" > ") &&
1928
- normalizedSelector.endsWith(` > ${candidate}`)),
1967
+ normalizedNodeSelectors.some((candidate) =>
1968
+ candidate.endsWith(` > ${normalizedSelector}`),
1929
1969
  )
1930
1970
  ) {
1931
1971
  return true;
@@ -2180,7 +2220,7 @@ function sanitizeTextEditHtml(html: string): string {
2180
2220
  )
2181
2221
  .replace(/\s+on[A-Za-z]+\s*=\s*(?:"[^"]*"|'[^']*'|[^\s>]+)/g, "")
2182
2222
  .replace(
2183
- /\s+(href|src|xlink:href)\s*=\s*(["'])\s*javascript:[\s\S]*?\2/gi,
2223
+ /\s+(href|src|xlink:href)\s*=\s*(?:(["'])\s*(?:javascript|vbscript|data):[\s\S]*?\2|(?:javascript|vbscript|data):[^\s>]*)/gi,
2184
2224
  "",
2185
2225
  );
2186
2226
  }
@@ -2253,6 +2293,7 @@ function applyMoveNodeEdit(
2253
2293
  function findAfterNode(
2254
2294
  projection: CodeLayerProjection,
2255
2295
  before: CodeLayerNode,
2296
+ insertAt?: number,
2256
2297
  ): CodeLayerNode | undefined {
2257
2298
  return (
2258
2299
  projection.nodes.find((node) => node.id === before.id) ??
@@ -2260,7 +2301,13 @@ function findAfterNode(
2260
2301
  (node) =>
2261
2302
  node.tag === before.tag &&
2262
2303
  node.source?.openStart === before.source?.openStart,
2263
- )
2304
+ ) ??
2305
+ (insertAt !== undefined
2306
+ ? projection.nodes.find(
2307
+ (node) =>
2308
+ node.tag === before.tag && node.source?.openStart === insertAt,
2309
+ )
2310
+ : undefined)
2264
2311
  );
2265
2312
  }
2266
2313
 
@@ -2322,6 +2369,7 @@ export function applyVisualEdit(
2322
2369
  }
2323
2370
 
2324
2371
  let edit: { content: string; capability: EditCapability } | PatchResultStatus;
2372
+ let moveInsertAt: number | undefined;
2325
2373
  if (intent.kind === "style") {
2326
2374
  edit = applyStyleEdit(html, element, intent);
2327
2375
  } else if (intent.kind === "class") {
@@ -2363,6 +2411,17 @@ export function applyVisualEdit(
2363
2411
  ),
2364
2412
  };
2365
2413
  }
2414
+ // Compute the expected post-move openStart so findAfterNode can locate the
2415
+ // moved node even when its nodeId changes (position-based id).
2416
+ const rawInsertAt =
2417
+ intent.placement === "before"
2418
+ ? anchorElement.start
2419
+ : intent.placement === "after"
2420
+ ? anchorElement.end
2421
+ : anchorElement.contentEnd;
2422
+ const removedLength = element.end - element.start;
2423
+ moveInsertAt =
2424
+ element.start < rawInsertAt ? rawInsertAt - removedLength : rawInsertAt;
2366
2425
  edit = applyMoveNodeEdit(html, element, anchorElement, intent);
2367
2426
  }
2368
2427
 
@@ -2389,7 +2448,7 @@ export function applyVisualEdit(
2389
2448
  }
2390
2449
 
2391
2450
  const nextProjection = buildCodeLayerProjection(edit.content, { source });
2392
- const afterNode = findAfterNode(nextProjection, beforeNode);
2451
+ const afterNode = findAfterNode(nextProjection, beforeNode, moveInsertAt);
2393
2452
  const after = afterNode ? summarizeNode(afterNode) : undefined;
2394
2453
 
2395
2454
  return {
@@ -18,6 +18,7 @@ export type DesignGenerationFrameRole = "screen" | "variant";
18
18
 
19
19
  export interface DesignGenerationFrame {
20
20
  frameId: string;
21
+ filename?: string;
21
22
  agentId: string;
22
23
  agentName: string;
23
24
  agentColor: string;
@@ -24,8 +24,8 @@ export type TweakSelections = Record<string, string | number | boolean>;
24
24
  * assignments. Rules (must match the editor's historical inline behavior):
25
25
  *
26
26
  * - booleans -> "1" / "0"
27
- * - numbers -> `${value}` plus "px" when the CSS var name contains "radius",
28
- * otherwise unitless
27
+ * - numbers -> `${value}` plus `t.unit` when provided, falling back to "px"
28
+ * when the CSS var name contains "radius", otherwise unitless
29
29
  * - strings -> the string as-is
30
30
  *
31
31
  * Tweaks without a `cssVar` are skipped (they don't map to a property).
@@ -42,7 +42,8 @@ export function resolveTweaksToCssVars(
42
42
  if (typeof v === "boolean") {
43
43
  out[t.cssVar] = v ? "1" : "0";
44
44
  } else if (typeof v === "number") {
45
- const unit = t.cssVar.toLowerCase().includes("radius") ? "px" : "";
45
+ const unit =
46
+ t.unit ?? (t.cssVar.toLowerCase().includes("radius") ? "px" : "");
46
47
  out[t.cssVar] = `${v}${unit}`;
47
48
  } else {
48
49
  out[t.cssVar] = String(v);