@agent-native/core 0.80.4 → 0.80.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (292) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +21 -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/index.ts +1 -1
  31. package/corpus/core/src/cli/mcp-config-writers.ts +187 -51
  32. package/corpus/core/src/cli/skills.ts +18 -3
  33. package/corpus/core/src/client/AssistantChat.tsx +11 -1
  34. package/corpus/core/src/client/agent-chat.ts +12 -1
  35. package/corpus/core/src/client/composer/PromptComposer.tsx +100 -41
  36. package/corpus/core/src/client/org/OrgSwitcher.tsx +1 -1
  37. package/corpus/core/src/client/sharing/ShareButton.tsx +3 -27
  38. package/corpus/core/src/collab/presence.ts +1 -1
  39. package/corpus/core/src/mcp/connect-route.ts +34 -5
  40. package/corpus/core/src/server/action-discovery.ts +4 -0
  41. package/corpus/core/src/server/agent-chat-plugin.ts +20 -0
  42. package/corpus/templates/analytics/actions/dashboard-mutation-api.ts +2 -0
  43. package/corpus/templates/analytics/actions/update-dashboard.ts +8 -0
  44. package/corpus/templates/analytics/app/components/layout/Layout.tsx +1 -1
  45. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +117 -33
  46. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +4 -0
  47. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/types.ts +7 -0
  48. package/corpus/templates/analytics/changelog/2026-06-27-dashboards-can-now-nest-under-a-parent-in-the-sidebar-via-a-.md +6 -0
  49. package/corpus/templates/analytics/changelog/2026-06-29-analytics-pages-now-sit-closer-under-the-header-with-tighter.md +6 -0
  50. package/corpus/templates/assets/actions/generate-image-batch.ts +3 -0
  51. package/corpus/templates/assets/actions/generate-image.ts +3 -0
  52. package/corpus/templates/assets/changelog/2026-06-29-longer-agent-generation-window.md +6 -0
  53. package/corpus/templates/assets/netlify.toml +3 -3
  54. package/corpus/templates/assets/server/plugins/agent-chat.ts +4 -1
  55. package/corpus/templates/clips/app/components/capture-install-options.tsx +7 -8
  56. package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +1 -1
  57. package/corpus/templates/content/AGENTS.md +12 -0
  58. package/corpus/templates/content/app/blocks/BuilderDocsBlocks.tsx +10 -0
  59. package/corpus/templates/content/app/components/editor/BubbleToolbar.tsx +1 -0
  60. package/corpus/templates/content/app/components/editor/ContentReferencePreview.tsx +185 -0
  61. package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +3 -0
  62. package/corpus/templates/content/app/components/editor/VisualEditor.tsx +19 -0
  63. package/corpus/templates/content/app/components/editor/extensions/ContentReferenceNode.tsx +82 -0
  64. package/corpus/templates/content/app/global.css +9 -0
  65. package/corpus/templates/content/app/i18n/zh-TW.ts +12 -0
  66. package/corpus/templates/content/app/i18n-data.ts +140 -0
  67. package/corpus/templates/content/changelog/2026-06-29-reusable-mdx-references-now-preview-linked-local-documents-i.md +6 -0
  68. package/corpus/templates/content/shared/builder-docs-blocks.ts +8 -0
  69. package/corpus/templates/content/shared/builder-mdx.ts +141 -4
  70. package/corpus/templates/content/shared/nfm.ts +62 -0
  71. package/corpus/templates/design/.agents/skills/design-systems/SKILL.md +10 -11
  72. package/corpus/templates/design/AGENTS.md +5 -0
  73. package/corpus/templates/design/_gitignore +7 -0
  74. package/corpus/templates/design/actions/apply-visual-edit.ts +22 -12
  75. package/corpus/templates/design/actions/create-design-system.ts +15 -4
  76. package/corpus/templates/design/actions/create-file.ts +20 -1
  77. package/corpus/templates/design/actions/delete-design-system.ts +2 -2
  78. package/corpus/templates/design/actions/duplicate-design.ts +35 -9
  79. package/corpus/templates/design/actions/generate-design.ts +146 -69
  80. package/corpus/templates/design/actions/generate-screens.ts +51 -19
  81. package/corpus/templates/design/actions/get-design-snapshot.ts +5 -1
  82. package/corpus/templates/design/actions/get-design.ts +2 -0
  83. package/corpus/templates/design/actions/import-design-project.ts +28 -9
  84. package/corpus/templates/design/actions/import-document.ts +22 -8
  85. package/corpus/templates/design/actions/index-design-system-with-builder.ts +6 -153
  86. package/corpus/templates/design/actions/navigate.ts +105 -54
  87. package/corpus/templates/design/actions/set-default-design-system.ts +17 -3
  88. package/corpus/templates/design/actions/show-design-questions.ts +2 -0
  89. package/corpus/templates/design/actions/update-design.ts +2 -1
  90. package/corpus/templates/design/actions/view-screen.ts +12 -6
  91. package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +4 -4
  92. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +159 -41
  93. package/corpus/templates/design/app/components/design/DesignExtensionsPanel.tsx +8 -4
  94. package/corpus/templates/design/app/components/design/DrawOverlay.tsx +37 -42
  95. package/corpus/templates/design/app/components/design/EditPanel.tsx +336 -183
  96. package/corpus/templates/design/app/components/design/LayersPanel.tsx +153 -34
  97. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +135 -33
  98. package/corpus/templates/design/app/components/design/QuestionFlow.tsx +6 -0
  99. package/corpus/templates/design/app/components/design/TweaksPanel.tsx +2 -1
  100. package/corpus/templates/design/app/components/design/inspector/AlignmentMatrix.tsx +4 -10
  101. package/corpus/templates/design/app/components/design/inspector/AutoLayoutMatrix.tsx +84 -43
  102. package/corpus/templates/design/app/components/design/inspector/ConstraintsWidget.tsx +4 -4
  103. package/corpus/templates/design/app/components/design/inspector/{FigmaColorPicker.tsx → DesignColorPicker.tsx} +89 -62
  104. package/corpus/templates/design/app/components/design/inspector/ExportSettingsPanel.tsx +14 -26
  105. package/corpus/templates/design/app/components/design/inspector/GradientEditor.tsx +40 -12
  106. package/corpus/templates/design/app/components/design/inspector/ImageFillControls.tsx +13 -4
  107. package/corpus/templates/design/app/components/design/inspector/SHADER_INTEGRATION.md +13 -13
  108. package/corpus/templates/design/app/components/design/inspector/ScrubInput.tsx +13 -9
  109. package/corpus/templates/design/app/components/design/inspector/ShaderControls.tsx +13 -4
  110. package/corpus/templates/design/app/components/design/inspector/ShaderFillsPanel.tsx +6 -6
  111. package/corpus/templates/design/app/components/design/inspector/{figma-icons.tsx → design-icons.tsx} +2 -2
  112. package/corpus/templates/design/app/components/design/inspector/index.ts +12 -12
  113. package/corpus/templates/design/app/components/design/inspector/scrub-input-utils.ts +5 -2
  114. package/corpus/templates/design/app/components/editor/PromptDialog.tsx +3 -3
  115. package/corpus/templates/design/app/components/layout/Layout.tsx +5 -2
  116. package/corpus/templates/design/app/components/layout/Sidebar.tsx +1 -1
  117. package/corpus/templates/design/app/components/visual-editor/CanvasCommentPins.tsx +167 -91
  118. package/corpus/templates/design/app/components/visual-editor/DrawOverlay.tsx +16 -3
  119. package/corpus/templates/design/app/components/visual-editor/SaveStatusIndicator.tsx +15 -0
  120. package/corpus/templates/design/app/global.css +4 -0
  121. package/corpus/templates/design/app/hooks/use-design-system.ts +4 -1
  122. package/corpus/templates/design/app/hooks/use-navigation-state.ts +38 -3
  123. package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +9 -2
  124. package/corpus/templates/design/app/i18n/zh-TW.ts +22 -0
  125. package/corpus/templates/design/app/i18n-data.ts +527 -0
  126. package/corpus/templates/design/app/lib/design-systems.ts +6 -4
  127. package/corpus/templates/design/app/lib/design-templates.ts +15 -3
  128. package/corpus/templates/design/app/pages/DesignEditor.tsx +641 -158
  129. package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +42 -34
  130. package/corpus/templates/design/app/pages/VisualEdit.tsx +100 -0
  131. package/corpus/templates/design/app/root.tsx +42 -9
  132. package/corpus/templates/design/app/routes/visual-edit.tsx +7 -0
  133. package/corpus/templates/design/changelog/2026-06-28-live-cursors-now-keep-names-beside-a-cleaner-pointer-marker.md +1 -1
  134. package/corpus/templates/design/changelog/2026-06-28-mode-switching-now-lives-in-a-compact-bottom-right-icon-dock.md +1 -1
  135. package/corpus/templates/design/changelog/2026-06-28-visual-code-design-mode.md +6 -0
  136. package/corpus/templates/design/changelog/2026-06-29-design-generation-prompts-now-show-connect-ai-before-sending.md +6 -0
  137. package/corpus/templates/design/changelog/2026-06-29-design-mode-top-chrome-now-groups-collaborators-preview-shar.md +1 -1
  138. package/corpus/templates/design/changelog/2026-06-29-fixed-design-editor-exports-and-gradient-edits-so-multi-scre.md +6 -0
  139. package/corpus/templates/design/changelog/2026-06-29-longer-hosted-agent-turns.md +6 -0
  140. package/corpus/templates/design/changelog/2026-06-29-png-export-handles-modern-css-color-functions-more-reliably.md +6 -0
  141. package/corpus/templates/design/changelog/2026-06-29-png-export-now-ignores-duplicate-clicks-while-a-download-is-.md +6 -0
  142. package/corpus/templates/design/changelog/2026-06-29-public-visual-edit-and-shared-design-links-now-invite-visito.md +6 -0
  143. package/corpus/templates/design/changelog/2026-06-29-visual-edit-actions-now-reject-missing-design-targets-before.md +6 -0
  144. package/corpus/templates/design/e2e/README.md +71 -0
  145. package/corpus/templates/design/e2e/global-setup.ts +157 -0
  146. package/corpus/templates/design/e2e/helpers.ts +148 -0
  147. package/corpus/templates/design/netlify.toml +3 -4
  148. package/corpus/templates/design/package.json +5 -1
  149. package/corpus/templates/design/playwright.config.ts +51 -0
  150. package/corpus/templates/design/server/handlers/index-design-system-with-builder.ts +121 -0
  151. package/corpus/templates/design/server/handlers/uploads.ts +89 -38
  152. package/corpus/templates/design/server/lib/builder-design-system-proxy.ts +181 -0
  153. package/corpus/templates/design/server/lib/coding-handoff.ts +33 -4
  154. package/corpus/templates/design/server/lib/design-export.ts +35 -8
  155. package/corpus/templates/design/server/plugins/agent-chat.ts +4 -0
  156. package/corpus/templates/design/server/plugins/auth.ts +10 -1
  157. package/corpus/templates/design/server/routes/api/index-design-system-with-builder.post.ts +1 -0
  158. package/corpus/templates/design/shared/api.ts +2 -0
  159. package/corpus/templates/design/shared/apply-edits.ts +12 -8
  160. package/corpus/templates/design/shared/canvas-math.ts +19 -1
  161. package/corpus/templates/design/shared/code-layer.ts +87 -28
  162. package/corpus/templates/design/shared/generation-session.ts +1 -0
  163. package/corpus/templates/design/shared/resolve-tweaks.ts +4 -3
  164. package/corpus/templates/design/shared/shader-presets.ts +10 -0
  165. package/corpus/templates/design/shared/source-mode.ts +9 -0
  166. package/corpus/templates/design/vitest.config.ts +2 -1
  167. package/corpus/templates/mail/app/components/layout/AppLayout.tsx +1 -1
  168. package/corpus/templates/plan/.agents/skills/visual-plan/references/canvas.md +1 -1
  169. package/corpus/templates/plan/AGENTS.md +1 -1
  170. package/corpus/templates/plan/actions/create-plan-design.ts +1 -1
  171. package/corpus/templates/plan/actions/validate-local-plan-source.ts +2 -10
  172. package/corpus/templates/plan/app/pages/PlansPage.tsx +1 -0
  173. package/corpus/templates/plan/docs/commenting-ux-plan.md +2 -2
  174. package/corpus/templates/plan/server/plan-content.ts +1 -1
  175. package/corpus/templates/plan/server/ui-plan-html.ts +2 -2
  176. package/corpus/templates/slides/actions/index-design-system-with-builder.ts +6 -153
  177. package/corpus/templates/slides/app/components/design-system/DesignSystemSetup.tsx +53 -38
  178. package/corpus/templates/slides/app/components/design-system/{fig-import-response.ts → builder-index-response.ts} +9 -6
  179. package/corpus/templates/slides/app/components/visual-editor/MultiSelectChip.tsx +1 -1
  180. package/corpus/templates/slides/changelog/2026-06-29-design-system-setup-now-indexes-uploaded-design-files-throug.md +6 -0
  181. package/corpus/templates/slides/changelog/2026-06-29-longer-hosted-agent-turns.md +6 -0
  182. package/corpus/templates/slides/netlify.toml +3 -6
  183. package/corpus/templates/slides/server/handlers/index-design-system-with-builder.ts +116 -0
  184. package/corpus/templates/slides/server/lib/builder-design-system-proxy.ts +179 -0
  185. package/corpus/templates/slides/server/plugins/agent-chat.ts +4 -1
  186. package/corpus/templates/slides/server/routes/api/index-design-system-with-builder.post.ts +1 -0
  187. package/dist/action.d.ts +15 -0
  188. package/dist/action.d.ts.map +1 -1
  189. package/dist/action.js +6 -0
  190. package/dist/action.js.map +1 -1
  191. package/dist/agent/durable-background.d.ts +9 -7
  192. package/dist/agent/durable-background.d.ts.map +1 -1
  193. package/dist/agent/durable-background.js +27 -11
  194. package/dist/agent/durable-background.js.map +1 -1
  195. package/dist/agent/production-agent.d.ts +7 -0
  196. package/dist/agent/production-agent.d.ts.map +1 -1
  197. package/dist/agent/production-agent.js +4 -1
  198. package/dist/agent/production-agent.js.map +1 -1
  199. package/dist/agent/run-loop-with-resume.d.ts +2 -1
  200. package/dist/agent/run-loop-with-resume.d.ts.map +1 -1
  201. package/dist/agent/run-loop-with-resume.js +2 -2
  202. package/dist/agent/run-loop-with-resume.js.map +1 -1
  203. package/dist/brand-kit/fig/index.d.ts +4 -4
  204. package/dist/brand-kit/fig/index.d.ts.map +1 -1
  205. package/dist/brand-kit/fig/index.js +14 -27
  206. package/dist/brand-kit/fig/index.js.map +1 -1
  207. package/dist/cli/index.js +1 -1
  208. package/dist/cli/index.js.map +1 -1
  209. package/dist/cli/mcp-config-writers.d.ts +15 -7
  210. package/dist/cli/mcp-config-writers.d.ts.map +1 -1
  211. package/dist/cli/mcp-config-writers.js +198 -45
  212. package/dist/cli/mcp-config-writers.js.map +1 -1
  213. package/dist/cli/skills.d.ts +1 -1
  214. package/dist/cli/skills.d.ts.map +1 -1
  215. package/dist/cli/skills.js +18 -3
  216. package/dist/cli/skills.js.map +1 -1
  217. package/dist/client/AssistantChat.d.ts.map +1 -1
  218. package/dist/client/AssistantChat.js +11 -1
  219. package/dist/client/AssistantChat.js.map +1 -1
  220. package/dist/client/agent-chat.d.ts.map +1 -1
  221. package/dist/client/agent-chat.js +15 -2
  222. package/dist/client/agent-chat.js.map +1 -1
  223. package/dist/client/composer/PromptComposer.d.ts.map +1 -1
  224. package/dist/client/composer/PromptComposer.js +35 -1
  225. package/dist/client/composer/PromptComposer.js.map +1 -1
  226. package/dist/client/org/OrgSwitcher.js +1 -1
  227. package/dist/client/org/OrgSwitcher.js.map +1 -1
  228. package/dist/client/sharing/ShareButton.d.ts +1 -1
  229. package/dist/client/sharing/ShareButton.d.ts.map +1 -1
  230. package/dist/client/sharing/ShareButton.js +2 -15
  231. package/dist/client/sharing/ShareButton.js.map +1 -1
  232. package/dist/collab/presence.d.ts +1 -1
  233. package/dist/collab/presence.js +1 -1
  234. package/dist/collab/presence.js.map +1 -1
  235. package/dist/collab/routes.d.ts +1 -1
  236. package/dist/mcp/connect-route.d.ts.map +1 -1
  237. package/dist/mcp/connect-route.js +34 -5
  238. package/dist/mcp/connect-route.js.map +1 -1
  239. package/dist/notifications/routes.d.ts +3 -3
  240. package/dist/observability/routes.d.ts +3 -3
  241. package/dist/resources/handlers.d.ts +1 -1
  242. package/dist/server/action-discovery.d.ts.map +1 -1
  243. package/dist/server/action-discovery.js +5 -0
  244. package/dist/server/action-discovery.js.map +1 -1
  245. package/dist/server/agent-chat-plugin.d.ts +6 -0
  246. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  247. package/dist/server/agent-chat-plugin.js +12 -3
  248. package/dist/server/agent-chat-plugin.js.map +1 -1
  249. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  250. package/docs/content/locales/ar-SA/real-time-collaboration.mdx +2 -2
  251. package/docs/content/locales/ar-SA/template-design.mdx +1 -1
  252. package/docs/content/locales/de-DE/real-time-collaboration.mdx +3 -3
  253. package/docs/content/locales/de-DE/template-design.mdx +1 -1
  254. package/docs/content/locales/es-ES/real-time-collaboration.mdx +2 -2
  255. package/docs/content/locales/es-ES/template-design.mdx +1 -1
  256. package/docs/content/locales/fr-FR/real-time-collaboration.mdx +2 -2
  257. package/docs/content/locales/fr-FR/template-design.mdx +1 -1
  258. package/docs/content/locales/hi-IN/template-design.mdx +1 -1
  259. package/docs/content/locales/ja-JP/real-time-collaboration.mdx +2 -2
  260. package/docs/content/locales/ja-JP/template-design.mdx +1 -1
  261. package/docs/content/locales/ko-KR/real-time-collaboration.mdx +2 -2
  262. package/docs/content/locales/ko-KR/template-design.mdx +1 -1
  263. package/docs/content/locales/pt-BR/real-time-collaboration.mdx +2 -2
  264. package/docs/content/locales/pt-BR/template-design.mdx +1 -1
  265. package/docs/content/locales/zh-CN/real-time-collaboration.mdx +2 -2
  266. package/docs/content/locales/zh-CN/template-design.mdx +1 -1
  267. package/docs/content/locales/zh-TW/real-time-collaboration.mdx +2 -2
  268. package/docs/content/locales/zh-TW/template-design.mdx +1 -1
  269. package/docs/content/real-time-collaboration.mdx +2 -2
  270. package/docs/content/template-design.mdx +1 -1
  271. package/package.json +3 -7
  272. package/corpus/core/src/brand-kit/fig/decode.ts +0 -410
  273. package/corpus/core/src/brand-kit/fig/extract-design-system.ts +0 -947
  274. package/corpus/core/src/brand-kit/fig/fig-to-html.ts +0 -1906
  275. package/corpus/templates/design/actions/import-figma.ts +0 -55
  276. package/corpus/templates/design/changelog/2026-06-28-figma-style-code-design-mode.md +0 -6
  277. package/corpus/templates/design/server/handlers/import-figma-system.ts +0 -86
  278. package/corpus/templates/design/server/routes/api/import-figma-system.post.ts +0 -1
  279. package/corpus/templates/slides/server/handlers/import-figma-system.ts +0 -101
  280. package/corpus/templates/slides/server/routes/api/import-figma-system.post.ts +0 -1
  281. package/dist/brand-kit/fig/decode.d.ts +0 -33
  282. package/dist/brand-kit/fig/decode.d.ts.map +0 -1
  283. package/dist/brand-kit/fig/decode.js +0 -358
  284. package/dist/brand-kit/fig/decode.js.map +0 -1
  285. package/dist/brand-kit/fig/extract-design-system.d.ts +0 -44
  286. package/dist/brand-kit/fig/extract-design-system.d.ts.map +0 -1
  287. package/dist/brand-kit/fig/extract-design-system.js +0 -752
  288. package/dist/brand-kit/fig/extract-design-system.js.map +0 -1
  289. package/dist/brand-kit/fig/fig-to-html.d.ts +0 -246
  290. package/dist/brand-kit/fig/fig-to-html.d.ts.map +0 -1
  291. package/dist/brand-kit/fig/fig-to-html.js +0 -1506
  292. package/dist/brand-kit/fig/fig-to-html.js.map +0 -1
@@ -20,6 +20,7 @@ export const BUILDER_DOCS_MODELS = [
20
20
  "docs-content",
21
21
  "blog-article",
22
22
  "agent-native-blog-article-test",
23
+ "symbol",
23
24
  ] as const;
24
25
 
25
26
  export type BuilderDocsModel = (typeof BUILDER_DOCS_MODELS)[number] | string;
@@ -175,6 +176,7 @@ export function builderRawRootForEntry(model: string, entryId: string) {
175
176
  function modelDirectory(model: string) {
176
177
  if (model === "docs-content") return "docs";
177
178
  if (model === "blog-article") return "blog";
179
+ if (model === "symbol") return "symbols";
178
180
  return safePathPart(model);
179
181
  }
180
182
 
@@ -194,6 +196,23 @@ export function builderMdxPathForEntry(entry: BuilderContentEntry) {
194
196
  )}/${slug}${BUILDER_DOCS_MDX_EXTENSION}`;
195
197
  }
196
198
 
199
+ function builderSymbolMdxPathForEntry(entry: BuilderContentEntry) {
200
+ const data = entry.data ?? {};
201
+ const title = builderEntryTitle(entry);
202
+ const handle = stringFromRecord(data, [
203
+ "handle",
204
+ "slug",
205
+ "urlPath",
206
+ "url",
207
+ "path",
208
+ ]);
209
+ const slug = slugify(handle?.replace(/^\/+|\/+$/g, "") || title, entry.id);
210
+ return `${BUILDER_DOCS_CONTENT_ROOT}/symbols/${safePathPart(
211
+ entry.model,
212
+ "symbol",
213
+ )}/${slug}${BUILDER_DOCS_MDX_EXTENSION}`;
214
+ }
215
+
197
216
  function stringFromRecord(
198
217
  record: Record<string, unknown>,
199
218
  keys: string[],
@@ -357,6 +376,50 @@ function childBlocks(block: unknown): unknown[] {
357
376
  return Array.isArray(block.children) ? block.children : [];
358
377
  }
359
378
 
379
+ function symbolContentEntry(
380
+ symbol: Record<string, unknown>,
381
+ ): BuilderContentEntry | null {
382
+ const content = isRecord(symbol.content) ? symbol.content : null;
383
+ if (!content) return null;
384
+ const rawModel = stringFromRecord(symbol, ["model"]);
385
+ const rawEntry = stringFromRecord(symbol, ["entry"]);
386
+ const id = stringFromRecord(content, ["id", "entry", "uid"]) ?? rawEntry;
387
+ if (!id) return null;
388
+
389
+ const model =
390
+ stringFromRecord(content, ["model", "modelName", "queryModel"]) ??
391
+ rawModel ??
392
+ "symbol";
393
+ const data = isRecord(content.data)
394
+ ? (JSON.parse(JSON.stringify(content.data)) as Record<string, unknown>)
395
+ : {};
396
+ if (!Array.isArray(data.blocks) && Array.isArray(content.blocks)) {
397
+ data.blocks = content.blocks;
398
+ }
399
+ if (!data.blocks) return null;
400
+
401
+ return {
402
+ ...content,
403
+ id,
404
+ model,
405
+ name:
406
+ stringFromRecord(content, ["name"]) ??
407
+ stringFromRecord(data, ["title", "pageTitle", "name"]) ??
408
+ id,
409
+ published:
410
+ typeof content.published === "string" ? content.published : undefined,
411
+ lastUpdated:
412
+ typeof content.lastUpdated === "string" ||
413
+ typeof content.lastUpdated === "number"
414
+ ? content.lastUpdated
415
+ : typeof content.updatedDate === "string" ||
416
+ typeof content.updatedDate === "number"
417
+ ? content.updatedDate
418
+ : undefined,
419
+ data,
420
+ };
421
+ }
422
+
360
423
  function blockSummary(block: unknown) {
361
424
  const name = componentName(block);
362
425
  const options = componentOptions(block);
@@ -382,6 +445,7 @@ interface BlocksToMdxContext {
382
445
  rawRoot: string;
383
446
  files: Record<string, string>;
384
447
  warnings: string[];
448
+ emitReferencedEntry: (entry: BuilderContentEntry) => Promise<string>;
385
449
  }
386
450
 
387
451
  async function builderBlocksToMdxBody(
@@ -493,10 +557,19 @@ async function builderBlockToMdx(
493
557
 
494
558
  if (name === "Symbol") {
495
559
  const symbol = isRecord(options.symbol) ? options.symbol : {};
560
+ const contentEntry = symbolContentEntry(symbol);
561
+ const source = contentEntry
562
+ ? await ctx.emitReferencedEntry(contentEntry)
563
+ : undefined;
496
564
  const data: BuilderSymbolData = {
497
565
  ...raw,
498
566
  entry: typeof symbol.entry === "string" ? symbol.entry : undefined,
499
567
  model: typeof symbol.model === "string" ? symbol.model : undefined,
568
+ source,
569
+ dynamic:
570
+ boolFromRecord(symbol, "dynamic") ??
571
+ boolFromRecord(symbol, "isDynamic") ??
572
+ boolFromRecord(options, "dynamicSymbol"),
500
573
  data: isRecord(symbol.data) ? symbol.data : undefined,
501
574
  };
502
575
  return serializeRegistryBlockToMdx("builder-symbol", {
@@ -525,12 +598,76 @@ async function builderBlockToMdx(
525
598
  export async function builderEntryToMdxBundle(
526
599
  entry: BuilderContentEntry,
527
600
  ): Promise<BuilderMdxBundle> {
601
+ const files: Record<string, string> = {};
602
+ const warnings: string[] = [];
603
+ const emitted = new Set<string>();
604
+ const mdx = await emitBuilderEntryToMdxFile({
605
+ entry,
606
+ files,
607
+ warnings,
608
+ emitted,
609
+ symbolPath: false,
610
+ });
611
+ return { mdx, files, blocks: builderEntryBlocks(entry) };
612
+ }
613
+
614
+ async function emitBuilderEntryToMdxFile({
615
+ entry,
616
+ files,
617
+ warnings,
618
+ emitted,
619
+ symbolPath,
620
+ }: {
621
+ entry: BuilderContentEntry;
622
+ files: Record<string, string>;
623
+ warnings: string[];
624
+ emitted: Set<string>;
625
+ symbolPath: boolean;
626
+ }): Promise<BuilderMdxFile> {
627
+ const path = symbolPath
628
+ ? builderSymbolMdxPathForEntry(entry)
629
+ : builderMdxPathForEntry(entry);
630
+ const key = `${entry.model}:${entry.id}:${path}`;
631
+ if (emitted.has(key)) {
632
+ return {
633
+ path,
634
+ documentId: builderDocumentId(entry.model, entry.id),
635
+ title: builderEntryTitle(entry),
636
+ metadata: {
637
+ model: entry.model,
638
+ entryId: entry.id,
639
+ lastUpdated: normalizeRemoteUpdatedAt(entry),
640
+ published: entry.published,
641
+ sourceHash: builderSourceHash(entry),
642
+ blocksHash: builderBlocksHash(builderEntryBlocks(entry)),
643
+ rawRoot: builderRawRootForEntry(entry.model, entry.id),
644
+ path,
645
+ },
646
+ frontmatter: {},
647
+ body: "",
648
+ source: files[path] ?? "",
649
+ };
650
+ }
651
+ emitted.add(key);
652
+
528
653
  const blocks = builderEntryBlocks(entry);
529
654
  const rawRoot = builderRawRootForEntry(entry.model, entry.id);
530
- const files: Record<string, string> = {};
531
- const ctx: BlocksToMdxContext = { rawRoot, files, warnings: [] };
655
+ const ctx: BlocksToMdxContext = {
656
+ rawRoot,
657
+ files,
658
+ warnings,
659
+ emitReferencedEntry: async (referencedEntry) => {
660
+ const nested = await emitBuilderEntryToMdxFile({
661
+ entry: referencedEntry,
662
+ files,
663
+ warnings,
664
+ emitted,
665
+ symbolPath: true,
666
+ });
667
+ return nested.path;
668
+ },
669
+ };
532
670
  const body = await builderBlocksToMdxBody(blocks, ctx);
533
- const path = builderMdxPathForEntry(entry);
534
671
  const blocksHash = builderBlocksHash(blocks);
535
672
  const sourceHash = builderSourceHash(entry);
536
673
  const frontmatter = frontmatterForEntry({
@@ -552,7 +689,7 @@ export async function builderEntryToMdxBundle(
552
689
  source,
553
690
  };
554
691
  files[path] = source;
555
- return { mdx, files, blocks };
692
+ return mdx;
556
693
  }
557
694
 
558
695
  function parseFrontmatterValue(value: string): unknown {
@@ -673,6 +673,7 @@ function serializeBlock(node: PMNode, indent: number): string[] {
673
673
  return serializeBlockAtom(node, ind);
674
674
  case "registryBlock":
675
675
  return serializeRegistryBlock(node, ind);
676
+ case "contentReference":
676
677
  case "localMdxComponent":
677
678
  return serializeRawSourceBlock(node, ind);
678
679
  default: {
@@ -1199,6 +1200,19 @@ function parseSingleBlock(
1199
1200
  return { nodes: [withIndentAttr(node)], end: childRes.end };
1200
1201
  }
1201
1202
 
1203
+ // Content reference (Notion-style reusable MDX transclusion). The source
1204
+ // owns the reference; the editor resolves and previews it from local files.
1205
+ const contentReferenceTag = matchContentReferenceOpen(dedent);
1206
+ if (contentReferenceTag) {
1207
+ return parseContentReference(
1208
+ lines,
1209
+ start,
1210
+ indent,
1211
+ rel,
1212
+ contentReferenceTag,
1213
+ );
1214
+ }
1215
+
1202
1216
  // Registry block (PascalCase MDX element: <Endpoint .../>, <Checklist .../>,
1203
1217
  // <DataModel …>…</DataModel>, …). These are the dev-doc / OpenAPI library
1204
1218
  // blocks shared with plan, encoded inline. They are recognized by the content
@@ -1288,6 +1302,12 @@ function matchRegistryBlockOpen(dedent: string): string | null {
1288
1302
  return registryBlockSpecByTag(tag) ? tag : null;
1289
1303
  }
1290
1304
 
1305
+ function matchContentReferenceOpen(dedent: string): string | null {
1306
+ return /^<ContentReference(?:[\s/>]|$)/.test(dedent)
1307
+ ? "ContentReference"
1308
+ : null;
1309
+ }
1310
+
1291
1311
  function matchLocalMdxComponentOpen(dedent: string): string | null {
1292
1312
  const m = dedent.match(/^<([A-Z][\w-]*)(?:[\s/>]|$)/);
1293
1313
  if (!m) return null;
@@ -1424,6 +1444,48 @@ function parseRegistryBlock(
1424
1444
  return { nodes: [withIndentAttr(node)], end };
1425
1445
  }
1426
1446
 
1447
+ function parseContentReference(
1448
+ lines: string[],
1449
+ start: number,
1450
+ indent: number,
1451
+ rel: number,
1452
+ _tag: string,
1453
+ ): ParseResult {
1454
+ const withIndentAttr = (node: PMNode): PMNode => {
1455
+ if (rel > 0) node.attrs = { ...(node.attrs || {}), indent: rel };
1456
+ return node;
1457
+ };
1458
+ const dedented = lines.map((l) => stripTabs(l, indent));
1459
+
1460
+ let openEndLine = start;
1461
+ {
1462
+ let joined = "";
1463
+ for (let i = start; i < lines.length; i++) {
1464
+ joined += (i === start ? "" : "\n") + dedented[i];
1465
+ const res = scanOpenTagEnd(joined);
1466
+ if (res) {
1467
+ openEndLine = i;
1468
+ break;
1469
+ }
1470
+ openEndLine = i;
1471
+ }
1472
+ }
1473
+
1474
+ const rawLines = dedented.slice(start, openEndLine + 1);
1475
+ const raw = rawLines.join("\n");
1476
+ const props = parseAttrs(raw);
1477
+ const node: PMNode = {
1478
+ type: "contentReference",
1479
+ attrs: {
1480
+ sourcePath:
1481
+ props.sourcePath ?? props.path ?? props.source ?? props.href ?? "",
1482
+ title: props.title ?? null,
1483
+ __raw: raw,
1484
+ },
1485
+ };
1486
+ return { nodes: [withIndentAttr(node)], end: openEndLine + 1 };
1487
+ }
1488
+
1427
1489
  function parseLocalMdxComponent(
1428
1490
  lines: string[],
1429
1491
  start: number,
@@ -178,19 +178,18 @@ Extracts CSS tokens from a project's generated HTML, or clones an existing desig
178
178
  ### Source: Figma file
179
179
 
180
180
  ```bash
181
- pnpm action import-figma --figmaUrl "https://figma.com/design/<key>/..." \
182
- --description "<extracted tokens / styles summary>"
181
+ pnpm action index-design-system-with-builder \
182
+ --projectName "Acme Figma system" \
183
+ --codeFiles '[{"filename":"figma-summary.md","content":"<extracted tokens / styles summary>"}]'
183
184
  ```
184
185
 
185
- **Prefer the connected Figma MCP** when available (tools like
186
- `get_variable_defs`, `get_design_context`, `get_metadata`, `get_screenshot`).
187
- Call those on the file/selection FIRST to pull real variables (tokens), color
188
- and text styles, and a screenshot — this sidesteps REST/Enterprise limits and
189
- returns a token map directly. Then pass that summary to `import-figma` and build
190
- the system with `create-design-system`. Convert Figma colors (0-1 RGBA) to hex,
191
- effects to CSS box-shadow, and text styles to font tokens; snap spacing to a
192
- 4/8px scale. If no Figma MCP is connected, ask the user to paste the token
193
- values or describe the file.
186
+ Builder is the required extraction/indexing path for Figma-backed design
187
+ systems. If a connected Figma MCP is available (tools like `get_variable_defs`,
188
+ `get_design_context`, `get_metadata`, `get_screenshot`), call those on the
189
+ file/selection first to pull real variables, color/text styles, and screenshot
190
+ notes, then pass that summary to `index-design-system-with-builder` as an
191
+ uploaded text context file. Do not build a local design system from the Figma
192
+ summary unless the user explicitly asks for a manual local fallback.
194
193
 
195
194
  **When the user uploads a raw `.fig` file**, send it to Builder design-system
196
195
  indexing through the setup page upload route. Do not parse `.fig` files locally
@@ -101,6 +101,11 @@ patterns live in `.agents/skills/`.
101
101
  progress. External MCP hosts should use `present-design-variants` so the same
102
102
  picker opens inline instead of writing `application_state` directly.
103
103
  - Use framework sharing actions for design and design-system visibility/grants.
104
+ - `/visual-edit` is a public entry route and public `/design/:id` links may
105
+ render read-only public designs without a session. Do not open anonymous write
106
+ actions: save, share, generation, localhost connection, and screen persistence
107
+ should send signed-out visitors through `/_agent-native/sign-in?return=...`,
108
+ then save or copy the design into the authenticated account before sharing.
104
109
  - When the user asks to download/export, use export actions or point to the
105
110
  editor download menu.
106
111
  - Design source modes are `inline`, `localhost`, and `fusion`. Inline is the
@@ -37,3 +37,10 @@ data/.sessions.json
37
37
  learnings.md
38
38
 
39
39
  .vercel/
40
+
41
+ # Playwright E2E
42
+ /test-results/
43
+ /playwright-report/
44
+ /e2e/.auth/
45
+ data/e2e.db
46
+ data/e2e.db-*
@@ -32,18 +32,28 @@ function parseJsonString(value: unknown): unknown {
32
32
 
33
33
  const sourceSchema = z.preprocess(
34
34
  parseJsonString,
35
- z.object({
36
- kind: z
37
- .enum(["design-file", "inline-html", "local-file", "remote-url"])
38
- .default("design-file"),
39
- designId: z.string().optional(),
40
- fileId: z.string().optional(),
41
- filename: z.string().optional().default("index.html"),
42
- path: z.string().optional(),
43
- url: z.string().optional(),
44
- revision: z.string().optional(),
45
- html: z.string().optional(),
46
- }),
35
+ z
36
+ .object({
37
+ kind: z
38
+ .enum(["design-file", "inline-html", "local-file", "remote-url"])
39
+ .default("design-file"),
40
+ designId: z.string().optional(),
41
+ fileId: z.string().optional(),
42
+ filename: z.string().optional().default("index.html"),
43
+ path: z.string().optional(),
44
+ url: z.string().optional(),
45
+ revision: z.string().optional(),
46
+ html: z.string().optional(),
47
+ })
48
+ .superRefine((source, ctx) => {
49
+ if (source.kind === "design-file" && !source.designId && !source.fileId) {
50
+ ctx.addIssue({
51
+ code: z.ZodIssueCode.custom,
52
+ path: ["designId"],
53
+ message: "designId or fileId is required for design-file sources",
54
+ });
55
+ }
56
+ }),
47
57
  );
48
58
 
49
59
  const targetSchema = z.object({
@@ -3,7 +3,7 @@ import {
3
3
  getRequestUserEmail,
4
4
  getRequestOrgId,
5
5
  } from "@agent-native/core/server/request-context";
6
- import { eq } from "drizzle-orm";
6
+ import { and, eq, isNull } from "drizzle-orm";
7
7
  import { nanoid } from "nanoid";
8
8
  import { z } from "zod";
9
9
 
@@ -66,12 +66,23 @@ export default defineAction({
66
66
  if (!ownerEmail) throw new Error("no authenticated user");
67
67
  const orgId = getRequestOrgId();
68
68
 
69
- // Check only this user's owned systems. Shared systems should not prevent
70
- // the first system a user creates from becoming their default.
69
+ // Check only this user's owned systems within the same org. Shared systems
70
+ // should not prevent the first system a user creates from becoming their
71
+ // default, and systems in other orgs must not suppress the default in this org.
71
72
  const existing = await db
72
73
  .select({ id: schema.designSystems.id })
73
74
  .from(schema.designSystems)
74
- .where(eq(schema.designSystems.ownerEmail, ownerEmail))
75
+ .where(
76
+ orgId
77
+ ? and(
78
+ eq(schema.designSystems.ownerEmail, ownerEmail),
79
+ eq(schema.designSystems.orgId, orgId),
80
+ )
81
+ : and(
82
+ eq(schema.designSystems.ownerEmail, ownerEmail),
83
+ isNull(schema.designSystems.orgId),
84
+ ),
85
+ )
75
86
  .limit(1);
76
87
 
77
88
  const isDefault = existing.length === 0;
@@ -1,7 +1,7 @@
1
1
  import { defineAction } from "@agent-native/core";
2
2
  import { seedFromText } from "@agent-native/core/collab";
3
3
  import { assertAccess } from "@agent-native/core/sharing";
4
- import { eq } from "drizzle-orm";
4
+ import { and, eq } from "drizzle-orm";
5
5
  import { nanoid } from "nanoid";
6
6
  import { z } from "zod";
7
7
 
@@ -34,6 +34,25 @@ export default defineAction({
34
34
  await assertAccess("design", designId, "editor");
35
35
 
36
36
  const db = getDb();
37
+
38
+ // Guard against duplicate (designId, filename) — edit-design uses .limit(1)
39
+ // which is non-deterministic when multiple rows match the same key.
40
+ const [existing] = await db
41
+ .select({ id: schema.designFiles.id })
42
+ .from(schema.designFiles)
43
+ .where(
44
+ and(
45
+ eq(schema.designFiles.designId, designId),
46
+ eq(schema.designFiles.filename, filename),
47
+ ),
48
+ )
49
+ .limit(1);
50
+ if (existing) {
51
+ throw new Error(
52
+ `File "${filename}" already exists in design ${designId} — use edit-design to modify it`,
53
+ );
54
+ }
55
+
37
56
  const id = nanoid();
38
57
  const now = new Date().toISOString();
39
58
 
@@ -7,12 +7,12 @@ import { getDb, schema } from "../server/db/index.js";
7
7
 
8
8
  export default defineAction({
9
9
  description:
10
- "Delete a design system. Requires admin access. Designs linked to it are unlinked.",
10
+ "Delete a design system. Requires owner access. Designs linked to it are unlinked.",
11
11
  schema: z.object({
12
12
  id: z.string().min(1).describe("Design system ID to delete"),
13
13
  }),
14
14
  run: async ({ id }) => {
15
- await assertAccess("design-system", id, "admin");
15
+ await assertAccess("design-system", id, "owner");
16
16
 
17
17
  const db = getDb();
18
18
 
@@ -31,14 +31,45 @@ export default defineAction({
31
31
  const now = new Date().toISOString();
32
32
  const newTitle = title || `Copy of ${source.title}`;
33
33
 
34
- // Copy the design
34
+ // Fetch source files first so we can remap canvasFrames before inserting
35
+ const files = await db
36
+ .select()
37
+ .from(schema.designFiles)
38
+ .where(eq(schema.designFiles.designId, id));
39
+
40
+ // Build old-to-new file ID mapping upfront
41
+ const idMap = new Map<string, string>(
42
+ files.map((file) => [file.id, nanoid()]),
43
+ );
44
+
45
+ // Remap canvasFrames keys in source.data from old IDs to new IDs
46
+ let newData = source.data;
47
+ try {
48
+ const parsed =
49
+ typeof source.data === "string" ? JSON.parse(source.data) : source.data;
50
+ if (parsed && typeof parsed === "object" && parsed.canvasFrames) {
51
+ const remapped: Record<string, unknown> = {};
52
+ for (const [oldId, geometry] of Object.entries(parsed.canvasFrames)) {
53
+ const newFileId = idMap.get(oldId);
54
+ remapped[newFileId ?? oldId] = geometry;
55
+ }
56
+ newData =
57
+ typeof source.data === "string"
58
+ ? JSON.stringify({ ...parsed, canvasFrames: remapped })
59
+ : { ...parsed, canvasFrames: remapped };
60
+ }
61
+ } catch {
62
+ // If data is unparseable, fall back to copying verbatim
63
+ }
64
+
65
+ // Copy the design with remapped canvasFrames
35
66
  await db.insert(schema.designs).values({
36
67
  id: newId,
37
68
  title: newTitle,
38
69
  description: source.description,
39
70
  projectType: source.projectType,
40
71
  designSystemId: source.designSystemId ?? null,
41
- data: source.data,
72
+ data: newData,
42
73
  ownerEmail: (() => {
43
74
  const e = getRequestUserEmail();
44
75
  if (!e) throw new Error("no authenticated user");
@@ -49,15 +80,10 @@ export default defineAction({
49
80
  updatedAt: now,
50
81
  });
51
82
 
52
- // Copy all associated files with new IDs
53
- const files = await db
54
- .select()
55
- .from(schema.designFiles)
56
- .where(eq(schema.designFiles.designId, id));
57
-
83
+ // Copy all associated files using the pre-generated IDs
58
84
  for (const file of files) {
59
85
  await db.insert(schema.designFiles).values({
60
- id: nanoid(),
86
+ id: idMap.get(file.id)!,
61
87
  designId: newId,
62
88
  filename: file.filename,
63
89
  fileType: file.fileType,