@agent-native/core 0.80.2 → 0.80.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (322) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +66 -2
  3. package/corpus/core/docs/content/locales/ar-SA/real-time-collaboration.mdx +2 -2
  4. package/corpus/core/docs/content/locales/ar-SA/template-design.mdx +1 -1
  5. package/corpus/core/docs/content/locales/de-DE/real-time-collaboration.mdx +3 -3
  6. package/corpus/core/docs/content/locales/de-DE/template-design.mdx +1 -1
  7. package/corpus/core/docs/content/locales/es-ES/real-time-collaboration.mdx +2 -2
  8. package/corpus/core/docs/content/locales/es-ES/template-design.mdx +1 -1
  9. package/corpus/core/docs/content/locales/fr-FR/real-time-collaboration.mdx +2 -2
  10. package/corpus/core/docs/content/locales/fr-FR/template-design.mdx +1 -1
  11. package/corpus/core/docs/content/locales/hi-IN/template-design.mdx +1 -1
  12. package/corpus/core/docs/content/locales/ja-JP/real-time-collaboration.mdx +2 -2
  13. package/corpus/core/docs/content/locales/ja-JP/template-design.mdx +1 -1
  14. package/corpus/core/docs/content/locales/ko-KR/real-time-collaboration.mdx +2 -2
  15. package/corpus/core/docs/content/locales/ko-KR/template-design.mdx +1 -1
  16. package/corpus/core/docs/content/locales/pt-BR/real-time-collaboration.mdx +2 -2
  17. package/corpus/core/docs/content/locales/pt-BR/template-design.mdx +1 -1
  18. package/corpus/core/docs/content/locales/zh-CN/real-time-collaboration.mdx +2 -2
  19. package/corpus/core/docs/content/locales/zh-CN/template-design.mdx +1 -1
  20. package/corpus/core/docs/content/locales/zh-TW/real-time-collaboration.mdx +2 -2
  21. package/corpus/core/docs/content/locales/zh-TW/template-design.mdx +1 -1
  22. package/corpus/core/docs/content/real-time-collaboration.mdx +2 -2
  23. package/corpus/core/docs/content/template-design.mdx +1 -1
  24. package/corpus/core/package.json +3 -7
  25. package/corpus/core/src/action.ts +32 -0
  26. package/corpus/core/src/agent/durable-background.ts +32 -11
  27. package/corpus/core/src/agent/production-agent.ts +14 -1
  28. package/corpus/core/src/agent/run-loop-with-resume.ts +3 -1
  29. package/corpus/core/src/brand-kit/fig/index.ts +17 -37
  30. package/corpus/core/src/cli/index.ts +1 -1
  31. package/corpus/core/src/cli/mcp-config-writers.ts +187 -51
  32. package/corpus/core/src/cli/plan-local.ts +445 -108
  33. package/corpus/core/src/cli/skills.ts +32 -8
  34. package/corpus/core/src/client/AssistantChat.tsx +11 -1
  35. package/corpus/core/src/client/agent-chat.ts +12 -1
  36. package/corpus/core/src/client/composer/PromptComposer.tsx +100 -41
  37. package/corpus/core/src/client/org/OrgSwitcher.tsx +1 -1
  38. package/corpus/core/src/client/sharing/ShareButton.tsx +3 -27
  39. package/corpus/core/src/collab/presence.ts +1 -1
  40. package/corpus/core/src/mcp/connect-route.ts +34 -5
  41. package/corpus/core/src/server/action-discovery.ts +4 -0
  42. package/corpus/core/src/server/action-routes.ts +14 -0
  43. package/corpus/core/src/server/agent-chat-plugin.ts +20 -0
  44. package/corpus/core/src/vite/client.ts +15 -1
  45. package/corpus/templates/analytics/actions/dashboard-mutation-api.ts +2 -0
  46. package/corpus/templates/analytics/actions/update-dashboard.ts +8 -0
  47. package/corpus/templates/analytics/app/components/layout/Layout.tsx +1 -1
  48. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +117 -33
  49. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +4 -0
  50. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/types.ts +7 -0
  51. package/corpus/templates/analytics/changelog/2026-06-27-dashboards-can-now-nest-under-a-parent-in-the-sidebar-via-a-.md +6 -0
  52. package/corpus/templates/analytics/changelog/2026-06-29-analytics-pages-now-sit-closer-under-the-header-with-tighter.md +6 -0
  53. package/corpus/templates/assets/actions/generate-image-batch.ts +3 -0
  54. package/corpus/templates/assets/actions/generate-image.ts +3 -0
  55. package/corpus/templates/assets/changelog/2026-06-29-longer-agent-generation-window.md +6 -0
  56. package/corpus/templates/assets/netlify.toml +3 -3
  57. package/corpus/templates/assets/server/plugins/agent-chat.ts +4 -1
  58. package/corpus/templates/clips/app/components/capture-install-options.tsx +7 -8
  59. package/corpus/templates/clips/app/components/player/timestamped-comment-button.tsx +162 -0
  60. package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +1 -1
  61. package/corpus/templates/clips/app/i18n/ar-SA.ts +4 -0
  62. package/corpus/templates/clips/app/i18n/de-DE.ts +4 -0
  63. package/corpus/templates/clips/app/i18n/en-US.ts +4 -0
  64. package/corpus/templates/clips/app/i18n/es-ES.ts +4 -0
  65. package/corpus/templates/clips/app/i18n/fr-FR.ts +4 -0
  66. package/corpus/templates/clips/app/i18n/hi-IN.ts +4 -0
  67. package/corpus/templates/clips/app/i18n/ja-JP.ts +4 -0
  68. package/corpus/templates/clips/app/i18n/ko-KR.ts +4 -0
  69. package/corpus/templates/clips/app/i18n/pt-BR.ts +4 -0
  70. package/corpus/templates/clips/app/i18n/zh-CN.ts +4 -0
  71. package/corpus/templates/clips/app/i18n/zh-TW.ts +4 -0
  72. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +42 -18
  73. package/corpus/templates/content/AGENTS.md +12 -0
  74. package/corpus/templates/content/app/blocks/BuilderDocsBlocks.tsx +10 -0
  75. package/corpus/templates/content/app/components/editor/BubbleToolbar.tsx +1 -0
  76. package/corpus/templates/content/app/components/editor/ContentReferencePreview.tsx +185 -0
  77. package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +3 -0
  78. package/corpus/templates/content/app/components/editor/VisualEditor.tsx +19 -0
  79. package/corpus/templates/content/app/components/editor/extensions/ContentReferenceNode.tsx +82 -0
  80. package/corpus/templates/content/app/global.css +9 -0
  81. package/corpus/templates/content/app/i18n/zh-TW.ts +12 -0
  82. package/corpus/templates/content/app/i18n-data.ts +140 -0
  83. package/corpus/templates/content/changelog/2026-06-29-reusable-mdx-references-now-preview-linked-local-documents-i.md +6 -0
  84. package/corpus/templates/content/shared/builder-docs-blocks.ts +8 -0
  85. package/corpus/templates/content/shared/builder-mdx.ts +141 -4
  86. package/corpus/templates/content/shared/nfm.ts +62 -0
  87. package/corpus/templates/design/.agents/skills/design-systems/SKILL.md +10 -11
  88. package/corpus/templates/design/AGENTS.md +5 -0
  89. package/corpus/templates/design/_gitignore +7 -0
  90. package/corpus/templates/design/actions/apply-visual-edit.ts +22 -12
  91. package/corpus/templates/design/actions/create-design-system.ts +15 -4
  92. package/corpus/templates/design/actions/create-file.ts +20 -1
  93. package/corpus/templates/design/actions/delete-design-system.ts +2 -2
  94. package/corpus/templates/design/actions/duplicate-design.ts +35 -9
  95. package/corpus/templates/design/actions/generate-design.ts +146 -69
  96. package/corpus/templates/design/actions/generate-screens.ts +51 -19
  97. package/corpus/templates/design/actions/get-design-snapshot.ts +5 -1
  98. package/corpus/templates/design/actions/get-design.ts +2 -0
  99. package/corpus/templates/design/actions/import-design-project.ts +28 -9
  100. package/corpus/templates/design/actions/import-document.ts +22 -8
  101. package/corpus/templates/design/actions/index-design-system-with-builder.ts +6 -153
  102. package/corpus/templates/design/actions/navigate.ts +105 -54
  103. package/corpus/templates/design/actions/set-default-design-system.ts +17 -3
  104. package/corpus/templates/design/actions/show-design-questions.ts +2 -0
  105. package/corpus/templates/design/actions/update-design.ts +2 -1
  106. package/corpus/templates/design/actions/view-screen.ts +12 -6
  107. package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +4 -4
  108. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +159 -41
  109. package/corpus/templates/design/app/components/design/DesignExtensionsPanel.tsx +8 -4
  110. package/corpus/templates/design/app/components/design/DrawOverlay.tsx +37 -42
  111. package/corpus/templates/design/app/components/design/EditPanel.tsx +336 -183
  112. package/corpus/templates/design/app/components/design/LayersPanel.tsx +153 -34
  113. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +135 -33
  114. package/corpus/templates/design/app/components/design/QuestionFlow.tsx +6 -0
  115. package/corpus/templates/design/app/components/design/TweaksPanel.tsx +2 -1
  116. package/corpus/templates/design/app/components/design/inspector/AlignmentMatrix.tsx +4 -10
  117. package/corpus/templates/design/app/components/design/inspector/AutoLayoutMatrix.tsx +84 -43
  118. package/corpus/templates/design/app/components/design/inspector/ConstraintsWidget.tsx +4 -4
  119. package/corpus/templates/design/app/components/design/inspector/{FigmaColorPicker.tsx → DesignColorPicker.tsx} +89 -62
  120. package/corpus/templates/design/app/components/design/inspector/ExportSettingsPanel.tsx +14 -26
  121. package/corpus/templates/design/app/components/design/inspector/GradientEditor.tsx +40 -12
  122. package/corpus/templates/design/app/components/design/inspector/ImageFillControls.tsx +13 -4
  123. package/corpus/templates/design/app/components/design/inspector/SHADER_INTEGRATION.md +13 -13
  124. package/corpus/templates/design/app/components/design/inspector/ScrubInput.tsx +13 -9
  125. package/corpus/templates/design/app/components/design/inspector/ShaderControls.tsx +13 -4
  126. package/corpus/templates/design/app/components/design/inspector/ShaderFillsPanel.tsx +6 -6
  127. package/corpus/templates/design/app/components/design/inspector/{figma-icons.tsx → design-icons.tsx} +2 -2
  128. package/corpus/templates/design/app/components/design/inspector/index.ts +12 -12
  129. package/corpus/templates/design/app/components/design/inspector/scrub-input-utils.ts +5 -2
  130. package/corpus/templates/design/app/components/editor/PromptDialog.tsx +3 -3
  131. package/corpus/templates/design/app/components/layout/Layout.tsx +5 -2
  132. package/corpus/templates/design/app/components/layout/Sidebar.tsx +1 -1
  133. package/corpus/templates/design/app/components/visual-editor/CanvasCommentPins.tsx +167 -91
  134. package/corpus/templates/design/app/components/visual-editor/DrawOverlay.tsx +16 -3
  135. package/corpus/templates/design/app/components/visual-editor/SaveStatusIndicator.tsx +15 -0
  136. package/corpus/templates/design/app/global.css +4 -0
  137. package/corpus/templates/design/app/hooks/use-design-system.ts +4 -1
  138. package/corpus/templates/design/app/hooks/use-navigation-state.ts +38 -3
  139. package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +9 -2
  140. package/corpus/templates/design/app/i18n/zh-TW.ts +22 -0
  141. package/corpus/templates/design/app/i18n-data.ts +527 -0
  142. package/corpus/templates/design/app/lib/design-systems.ts +6 -4
  143. package/corpus/templates/design/app/lib/design-templates.ts +15 -3
  144. package/corpus/templates/design/app/pages/DesignEditor.tsx +641 -158
  145. package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +42 -34
  146. package/corpus/templates/design/app/pages/VisualEdit.tsx +100 -0
  147. package/corpus/templates/design/app/root.tsx +42 -9
  148. package/corpus/templates/design/app/routes/visual-edit.tsx +7 -0
  149. package/corpus/templates/design/changelog/2026-06-28-live-cursors-now-keep-names-beside-a-cleaner-pointer-marker.md +1 -1
  150. package/corpus/templates/design/changelog/2026-06-28-mode-switching-now-lives-in-a-compact-bottom-right-icon-dock.md +1 -1
  151. package/corpus/templates/design/changelog/2026-06-28-visual-code-design-mode.md +6 -0
  152. package/corpus/templates/design/changelog/2026-06-29-design-generation-prompts-now-show-connect-ai-before-sending.md +6 -0
  153. package/corpus/templates/design/changelog/2026-06-29-design-mode-top-chrome-now-groups-collaborators-preview-shar.md +1 -1
  154. package/corpus/templates/design/changelog/2026-06-29-fixed-design-editor-exports-and-gradient-edits-so-multi-scre.md +6 -0
  155. package/corpus/templates/design/changelog/2026-06-29-longer-hosted-agent-turns.md +6 -0
  156. package/corpus/templates/design/changelog/2026-06-29-png-export-handles-modern-css-color-functions-more-reliably.md +6 -0
  157. package/corpus/templates/design/changelog/2026-06-29-png-export-now-ignores-duplicate-clicks-while-a-download-is-.md +6 -0
  158. package/corpus/templates/design/changelog/2026-06-29-public-visual-edit-and-shared-design-links-now-invite-visito.md +6 -0
  159. package/corpus/templates/design/changelog/2026-06-29-visual-edit-actions-now-reject-missing-design-targets-before.md +6 -0
  160. package/corpus/templates/design/e2e/README.md +71 -0
  161. package/corpus/templates/design/e2e/global-setup.ts +157 -0
  162. package/corpus/templates/design/e2e/helpers.ts +148 -0
  163. package/corpus/templates/design/netlify.toml +3 -4
  164. package/corpus/templates/design/package.json +5 -1
  165. package/corpus/templates/design/playwright.config.ts +51 -0
  166. package/corpus/templates/design/server/handlers/index-design-system-with-builder.ts +121 -0
  167. package/corpus/templates/design/server/handlers/uploads.ts +89 -38
  168. package/corpus/templates/design/server/lib/builder-design-system-proxy.ts +181 -0
  169. package/corpus/templates/design/server/lib/coding-handoff.ts +33 -4
  170. package/corpus/templates/design/server/lib/design-export.ts +35 -8
  171. package/corpus/templates/design/server/plugins/agent-chat.ts +4 -0
  172. package/corpus/templates/design/server/plugins/auth.ts +10 -1
  173. package/corpus/templates/design/server/routes/api/index-design-system-with-builder.post.ts +1 -0
  174. package/corpus/templates/design/shared/api.ts +2 -0
  175. package/corpus/templates/design/shared/apply-edits.ts +12 -8
  176. package/corpus/templates/design/shared/canvas-math.ts +19 -1
  177. package/corpus/templates/design/shared/code-layer.ts +87 -28
  178. package/corpus/templates/design/shared/generation-session.ts +1 -0
  179. package/corpus/templates/design/shared/resolve-tweaks.ts +4 -3
  180. package/corpus/templates/design/shared/shader-presets.ts +10 -0
  181. package/corpus/templates/design/shared/source-mode.ts +9 -0
  182. package/corpus/templates/design/vitest.config.ts +2 -1
  183. package/corpus/templates/mail/app/components/layout/AppLayout.tsx +1 -1
  184. package/corpus/templates/plan/.agents/skills/visual-plan/references/canvas.md +1 -1
  185. package/corpus/templates/plan/.agents/skills/visual-plan/references/local-files.md +14 -5
  186. package/corpus/templates/plan/.agents/skills/visual-recap/references/local-files.md +14 -5
  187. package/corpus/templates/plan/AGENTS.md +1 -1
  188. package/corpus/templates/plan/actions/create-plan-design.ts +1 -1
  189. package/corpus/templates/plan/actions/validate-local-plan-source.ts +110 -0
  190. package/corpus/templates/plan/app/pages/PlansPage.tsx +1 -0
  191. package/corpus/templates/plan/docs/commenting-ux-plan.md +2 -2
  192. package/corpus/templates/plan/server/lib/plan-connector-catalog.ts +1 -0
  193. package/corpus/templates/plan/server/lib/public-action-paths.ts +1 -0
  194. package/corpus/templates/plan/server/plan-content.ts +1 -1
  195. package/corpus/templates/plan/server/ui-plan-html.ts +2 -2
  196. package/corpus/templates/slides/actions/index-design-system-with-builder.ts +6 -153
  197. package/corpus/templates/slides/app/components/design-system/DesignSystemSetup.tsx +53 -38
  198. package/corpus/templates/slides/app/components/design-system/{fig-import-response.ts → builder-index-response.ts} +9 -6
  199. package/corpus/templates/slides/app/components/visual-editor/MultiSelectChip.tsx +1 -1
  200. package/corpus/templates/slides/changelog/2026-06-29-design-system-setup-now-indexes-uploaded-design-files-throug.md +6 -0
  201. package/corpus/templates/slides/changelog/2026-06-29-longer-hosted-agent-turns.md +6 -0
  202. package/corpus/templates/slides/netlify.toml +3 -6
  203. package/corpus/templates/slides/server/handlers/index-design-system-with-builder.ts +116 -0
  204. package/corpus/templates/slides/server/lib/builder-design-system-proxy.ts +179 -0
  205. package/corpus/templates/slides/server/plugins/agent-chat.ts +4 -1
  206. package/corpus/templates/slides/server/routes/api/index-design-system-with-builder.post.ts +1 -0
  207. package/dist/action.d.ts +23 -0
  208. package/dist/action.d.ts.map +1 -1
  209. package/dist/action.js +9 -0
  210. package/dist/action.js.map +1 -1
  211. package/dist/agent/durable-background.d.ts +9 -7
  212. package/dist/agent/durable-background.d.ts.map +1 -1
  213. package/dist/agent/durable-background.js +27 -11
  214. package/dist/agent/durable-background.js.map +1 -1
  215. package/dist/agent/production-agent.d.ts +10 -0
  216. package/dist/agent/production-agent.d.ts.map +1 -1
  217. package/dist/agent/production-agent.js +4 -1
  218. package/dist/agent/production-agent.js.map +1 -1
  219. package/dist/agent/run-loop-with-resume.d.ts +2 -1
  220. package/dist/agent/run-loop-with-resume.d.ts.map +1 -1
  221. package/dist/agent/run-loop-with-resume.js +2 -2
  222. package/dist/agent/run-loop-with-resume.js.map +1 -1
  223. package/dist/brand-kit/fig/index.d.ts +4 -4
  224. package/dist/brand-kit/fig/index.d.ts.map +1 -1
  225. package/dist/brand-kit/fig/index.js +14 -27
  226. package/dist/brand-kit/fig/index.js.map +1 -1
  227. package/dist/cli/index.js +1 -1
  228. package/dist/cli/index.js.map +1 -1
  229. package/dist/cli/mcp-config-writers.d.ts +15 -7
  230. package/dist/cli/mcp-config-writers.d.ts.map +1 -1
  231. package/dist/cli/mcp-config-writers.js +198 -45
  232. package/dist/cli/mcp-config-writers.js.map +1 -1
  233. package/dist/cli/plan-local.d.ts +30 -0
  234. package/dist/cli/plan-local.d.ts.map +1 -1
  235. package/dist/cli/plan-local.js +281 -56
  236. package/dist/cli/plan-local.js.map +1 -1
  237. package/dist/cli/skills.d.ts +2 -2
  238. package/dist/cli/skills.d.ts.map +1 -1
  239. package/dist/cli/skills.js +32 -8
  240. package/dist/cli/skills.js.map +1 -1
  241. package/dist/client/AssistantChat.d.ts.map +1 -1
  242. package/dist/client/AssistantChat.js +11 -1
  243. package/dist/client/AssistantChat.js.map +1 -1
  244. package/dist/client/agent-chat.d.ts.map +1 -1
  245. package/dist/client/agent-chat.js +15 -2
  246. package/dist/client/agent-chat.js.map +1 -1
  247. package/dist/client/composer/PromptComposer.d.ts.map +1 -1
  248. package/dist/client/composer/PromptComposer.js +35 -1
  249. package/dist/client/composer/PromptComposer.js.map +1 -1
  250. package/dist/client/org/OrgSwitcher.js +1 -1
  251. package/dist/client/org/OrgSwitcher.js.map +1 -1
  252. package/dist/client/sharing/ShareButton.d.ts +1 -1
  253. package/dist/client/sharing/ShareButton.d.ts.map +1 -1
  254. package/dist/client/sharing/ShareButton.js +2 -15
  255. package/dist/client/sharing/ShareButton.js.map +1 -1
  256. package/dist/collab/presence.d.ts +1 -1
  257. package/dist/collab/presence.js +1 -1
  258. package/dist/collab/presence.js.map +1 -1
  259. package/dist/collab/routes.d.ts +1 -1
  260. package/dist/file-upload/actions/upload-image.d.ts +2 -2
  261. package/dist/mcp/connect-route.d.ts.map +1 -1
  262. package/dist/mcp/connect-route.js +34 -5
  263. package/dist/mcp/connect-route.js.map +1 -1
  264. package/dist/observability/routes.d.ts +2 -2
  265. package/dist/progress/routes.d.ts +1 -1
  266. package/dist/resources/handlers.d.ts +1 -1
  267. package/dist/server/action-discovery.d.ts.map +1 -1
  268. package/dist/server/action-discovery.js +5 -0
  269. package/dist/server/action-discovery.js.map +1 -1
  270. package/dist/server/action-routes.d.ts.map +1 -1
  271. package/dist/server/action-routes.js +14 -0
  272. package/dist/server/action-routes.js.map +1 -1
  273. package/dist/server/agent-chat-plugin.d.ts +6 -0
  274. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  275. package/dist/server/agent-chat-plugin.js +12 -3
  276. package/dist/server/agent-chat-plugin.js.map +1 -1
  277. package/dist/vite/client.d.ts.map +1 -1
  278. package/dist/vite/client.js +12 -1
  279. package/dist/vite/client.js.map +1 -1
  280. package/docs/content/locales/ar-SA/real-time-collaboration.mdx +2 -2
  281. package/docs/content/locales/ar-SA/template-design.mdx +1 -1
  282. package/docs/content/locales/de-DE/real-time-collaboration.mdx +3 -3
  283. package/docs/content/locales/de-DE/template-design.mdx +1 -1
  284. package/docs/content/locales/es-ES/real-time-collaboration.mdx +2 -2
  285. package/docs/content/locales/es-ES/template-design.mdx +1 -1
  286. package/docs/content/locales/fr-FR/real-time-collaboration.mdx +2 -2
  287. package/docs/content/locales/fr-FR/template-design.mdx +1 -1
  288. package/docs/content/locales/hi-IN/template-design.mdx +1 -1
  289. package/docs/content/locales/ja-JP/real-time-collaboration.mdx +2 -2
  290. package/docs/content/locales/ja-JP/template-design.mdx +1 -1
  291. package/docs/content/locales/ko-KR/real-time-collaboration.mdx +2 -2
  292. package/docs/content/locales/ko-KR/template-design.mdx +1 -1
  293. package/docs/content/locales/pt-BR/real-time-collaboration.mdx +2 -2
  294. package/docs/content/locales/pt-BR/template-design.mdx +1 -1
  295. package/docs/content/locales/zh-CN/real-time-collaboration.mdx +2 -2
  296. package/docs/content/locales/zh-CN/template-design.mdx +1 -1
  297. package/docs/content/locales/zh-TW/real-time-collaboration.mdx +2 -2
  298. package/docs/content/locales/zh-TW/template-design.mdx +1 -1
  299. package/docs/content/real-time-collaboration.mdx +2 -2
  300. package/docs/content/template-design.mdx +1 -1
  301. package/package.json +3 -7
  302. package/corpus/core/src/brand-kit/fig/decode.ts +0 -410
  303. package/corpus/core/src/brand-kit/fig/extract-design-system.ts +0 -947
  304. package/corpus/core/src/brand-kit/fig/fig-to-html.ts +0 -1906
  305. package/corpus/templates/design/actions/import-figma.ts +0 -55
  306. package/corpus/templates/design/changelog/2026-06-28-figma-style-code-design-mode.md +0 -6
  307. package/corpus/templates/design/server/handlers/import-figma-system.ts +0 -86
  308. package/corpus/templates/design/server/routes/api/import-figma-system.post.ts +0 -1
  309. package/corpus/templates/slides/server/handlers/import-figma-system.ts +0 -101
  310. package/corpus/templates/slides/server/routes/api/import-figma-system.post.ts +0 -1
  311. package/dist/brand-kit/fig/decode.d.ts +0 -33
  312. package/dist/brand-kit/fig/decode.d.ts.map +0 -1
  313. package/dist/brand-kit/fig/decode.js +0 -358
  314. package/dist/brand-kit/fig/decode.js.map +0 -1
  315. package/dist/brand-kit/fig/extract-design-system.d.ts +0 -44
  316. package/dist/brand-kit/fig/extract-design-system.d.ts.map +0 -1
  317. package/dist/brand-kit/fig/extract-design-system.js +0 -752
  318. package/dist/brand-kit/fig/extract-design-system.js.map +0 -1
  319. package/dist/brand-kit/fig/fig-to-html.d.ts +0 -246
  320. package/dist/brand-kit/fig/fig-to-html.d.ts.map +0 -1
  321. package/dist/brand-kit/fig/fig-to-html.js +0 -1506
  322. package/dist/brand-kit/fig/fig-to-html.js.map +0 -1
@@ -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,
@@ -1,4 +1,9 @@
1
1
  import { defineAction, embedApp } from "@agent-native/core";
2
+ import {
3
+ deleteAppState,
4
+ readAppState,
5
+ writeAppState,
6
+ } from "@agent-native/core/application-state";
2
7
  import {
3
8
  hasCollabState,
4
9
  applyText,
@@ -18,6 +23,10 @@ import {
18
23
  mergeCanvasFramePlacements,
19
24
  type CanvasFramePlacement,
20
25
  } from "../shared/canvas-frames.js";
26
+ import {
27
+ designGenerationSessionKey,
28
+ type DesignGenerationSession,
29
+ } from "../shared/generation-session.js";
21
30
 
22
31
  /** Editor deep link so external agents can surface "Open design". */
23
32
  function designDeepLink(designId: string): string {
@@ -28,6 +37,50 @@ function designDeepLink(designId: string): string {
28
37
  });
29
38
  }
30
39
 
40
+ function isRenderableDesignFile(file: {
41
+ fileType?: string | null;
42
+ content?: string | null;
43
+ }): boolean {
44
+ const fileType = file.fileType ?? "html";
45
+ return (
46
+ (fileType === "html" || fileType === "jsx") && Boolean(file.content?.trim())
47
+ );
48
+ }
49
+
50
+ async function updateGenerationSessionForSavedFiles(
51
+ designId: string,
52
+ savedFilenames: string[],
53
+ ) {
54
+ const key = designGenerationSessionKey(designId);
55
+ const rawSession = await readAppState(key).catch(() => null);
56
+ if (!rawSession || typeof rawSession !== "object") return;
57
+ const session = rawSession as unknown as DesignGenerationSession;
58
+ if (session.designId !== designId || !Array.isArray(session.frames)) return;
59
+
60
+ const saved = new Set(savedFilenames);
61
+ const frames = session.frames.map((frame) =>
62
+ frame.filename && saved.has(frame.filename)
63
+ ? {
64
+ ...frame,
65
+ status: "done" as const,
66
+ step: "Saved",
67
+ progress: 1,
68
+ }
69
+ : frame,
70
+ );
71
+ const allDone = frames.every((frame) => frame.status === "done");
72
+ if (allDone) {
73
+ await deleteAppState(key);
74
+ return;
75
+ }
76
+
77
+ await writeAppState(key, {
78
+ ...session,
79
+ status: "generating",
80
+ frames,
81
+ } as unknown as Record<string, unknown>);
82
+ }
83
+
31
84
  export default defineAction({
32
85
  description:
33
86
  "Save generated design content to a design project. " +
@@ -181,19 +234,6 @@ export default defineAction({
181
234
  }
182
235
  }
183
236
 
184
- const hasRenderableFile = files.some((file) => {
185
- const fileType = file.fileType ?? "html";
186
- return (
187
- (fileType === "html" || fileType === "jsx") &&
188
- file.content.trim().length > 0
189
- );
190
- });
191
- if (!hasRenderableFile) {
192
- throw new Error(
193
- "generate-design requires at least one non-empty HTML or JSX file before the design can be reported as ready",
194
- );
195
- }
196
-
197
237
  const savedFiles: Array<{
198
238
  id: string;
199
239
  filename: string;
@@ -206,6 +246,15 @@ export default defineAction({
206
246
  .from(schema.designFiles)
207
247
  .where(eq(schema.designFiles.designId, designId));
208
248
 
249
+ const hasRenderableFile =
250
+ files.some(isRenderableDesignFile) ||
251
+ existingFiles.some(isRenderableDesignFile);
252
+ if (!hasRenderableFile) {
253
+ throw new Error(
254
+ "generate-design requires at least one non-empty HTML or JSX file before the design can be reported as ready",
255
+ );
256
+ }
257
+
209
258
  const existingByName = new Map(existingFiles.map((f) => [f.filename, f]));
210
259
 
211
260
  for (const file of files) {
@@ -270,6 +319,19 @@ export default defineAction({
270
319
  agentLeaveDocument(fileId);
271
320
  }
272
321
 
322
+ // Update the in-memory map so a second entry with the same filename
323
+ // in the same `files` array hits the UPDATE branch instead of
324
+ // inserting a duplicate row.
325
+ existingByName.set(file.filename, {
326
+ id: fileId,
327
+ designId,
328
+ filename: file.filename,
329
+ fileType: file.fileType ?? "html",
330
+ content: file.content,
331
+ createdAt: now,
332
+ updatedAt: now,
333
+ });
334
+
273
335
  savedFiles.push({
274
336
  id: fileId,
275
337
  filename: file.filename,
@@ -290,31 +352,12 @@ export default defineAction({
290
352
  // Merge with existing data so tweak definitions survive content updates.
291
353
  // The data column is a free-form JSON blob; we own these keys here and
292
354
  // leave anything else intact.
293
- const [existingDesign] = await db
294
- .select({ data: schema.designs.data })
295
- .from(schema.designs)
296
- .where(eq(schema.designs.id, designId));
297
- let prevData: Record<string, unknown> = {};
298
- if (existingDesign?.data) {
299
- try {
300
- const parsed = JSON.parse(existingDesign.data);
301
- if (parsed && typeof parsed === "object") prevData = parsed;
302
- } catch {
303
- // Stale or invalid JSON — start fresh.
304
- }
305
- }
306
- const mergedData: Record<string, unknown> = {
307
- ...prevData,
308
- lastPrompt: prompt,
309
- generatedAt: now,
310
- fileCount: files.length,
311
- };
312
- if (tweaks !== undefined) {
313
- mergedData.tweaks = tweaks.map((tweak) => ({
314
- ...tweak,
315
- type: tweak.type === "color-swatches" ? "color-swatch" : tweak.type,
316
- }));
317
- }
355
+ //
356
+ // Wrapped in a transaction so that concurrent generate-design calls for the
357
+ // same design (e.g. the parallel fan-out from generate-screens) each read
358
+ // the latest canvasFrames and merge their own placement on top, rather than
359
+ // all reading the same stale snapshot and the last writer silently
360
+ // discarding the others' frame coordinates.
318
361
  let placedFrames:
319
362
  | Array<{
320
363
  fileId: string;
@@ -322,39 +365,73 @@ export default defineAction({
322
365
  frame: CanvasFramePlacement;
323
366
  }>
324
367
  | undefined;
325
- if (canvasFrames !== undefined) {
326
- const savedByFileId = new Map(savedFiles.map((file) => [file.id, file]));
327
- const savedByFilename = new Map(
328
- savedFiles.map((file) => [file.filename, file]),
329
- );
330
- const existingByFileId = new Map(
331
- existingFiles.map((file) => [file.id, file]),
332
- );
333
- const merged = mergeCanvasFramePlacements({
334
- existing: prevData.canvasFrames,
335
- placements: canvasFrames,
336
- resolveFileId: (placement) => {
337
- if (placement.fileId) {
338
- return savedByFileId.has(placement.fileId) ||
339
- existingByFileId.has(placement.fileId)
340
- ? placement.fileId
368
+ await db.transaction(async (tx) => {
369
+ const [existingDesign] = await tx
370
+ .select({ data: schema.designs.data })
371
+ .from(schema.designs)
372
+ .where(eq(schema.designs.id, designId));
373
+ let prevData: Record<string, unknown> = {};
374
+ if (existingDesign?.data) {
375
+ try {
376
+ const parsed = JSON.parse(existingDesign.data);
377
+ if (parsed && typeof parsed === "object") prevData = parsed;
378
+ } catch {
379
+ // Stale or invalid JSON — start fresh.
380
+ }
381
+ }
382
+ const mergedData: Record<string, unknown> = {
383
+ ...prevData,
384
+ lastPrompt: prompt,
385
+ generatedAt: now,
386
+ fileCount: files.length,
387
+ };
388
+ if (tweaks !== undefined) {
389
+ mergedData.tweaks = tweaks.map((tweak) => ({
390
+ ...tweak,
391
+ type: tweak.type === "color-swatches" ? "color-swatch" : tweak.type,
392
+ }));
393
+ }
394
+ if (canvasFrames !== undefined) {
395
+ const savedByFileId = new Map(
396
+ savedFiles.map((file) => [file.id, file]),
397
+ );
398
+ const savedByFilename = new Map(
399
+ savedFiles.map((file) => [file.filename, file]),
400
+ );
401
+ const existingByFileId = new Map(
402
+ existingFiles.map((file) => [file.id, file]),
403
+ );
404
+ const merged = mergeCanvasFramePlacements({
405
+ existing: prevData.canvasFrames,
406
+ placements: canvasFrames,
407
+ resolveFileId: (placement) => {
408
+ if (placement.fileId) {
409
+ return savedByFileId.has(placement.fileId) ||
410
+ existingByFileId.has(placement.fileId)
411
+ ? placement.fileId
412
+ : undefined;
413
+ }
414
+ return placement.filename
415
+ ? (savedByFilename.get(placement.filename)?.id ??
416
+ existingByName.get(placement.filename)?.id)
341
417
  : undefined;
342
- }
343
- return placement.filename
344
- ? (savedByFilename.get(placement.filename)?.id ??
345
- existingByName.get(placement.filename)?.id)
346
- : undefined;
347
- },
348
- });
349
- mergedData.canvasFrames = merged.canvasFrames;
350
- placedFrames = merged.placedFrames;
351
- }
352
- designUpdates.data = JSON.stringify(mergedData);
418
+ },
419
+ });
420
+ mergedData.canvasFrames = merged.canvasFrames;
421
+ placedFrames = merged.placedFrames;
422
+ }
423
+ designUpdates.data = JSON.stringify(mergedData);
353
424
 
354
- await db
355
- .update(schema.designs)
356
- .set(designUpdates)
357
- .where(eq(schema.designs.id, designId));
425
+ await tx
426
+ .update(schema.designs)
427
+ .set(designUpdates)
428
+ .where(eq(schema.designs.id, designId));
429
+ });
430
+
431
+ await updateGenerationSessionForSavedFiles(
432
+ designId,
433
+ savedFiles.map((file) => file.filename),
434
+ );
358
435
 
359
436
  return {
360
437
  designId,
@@ -42,16 +42,27 @@ function designDeepLink(designId: string): string {
42
42
  });
43
43
  }
44
44
 
45
- const requestedScreenSchema = z.object({
46
- frameId: z.string().optional(),
47
- title: z.string().min(1),
48
- filename: z
49
- .string()
50
- .optional()
51
- .describe("Target filename for this screen, such as onboarding.html"),
52
- role: z.enum(["screen", "variant"]).optional().default("screen"),
53
- variantOf: z.string().optional(),
54
- });
45
+ const requestedScreenSchema = z
46
+ .object({
47
+ frameId: z.string().optional(),
48
+ title: z.string().min(1),
49
+ filename: z
50
+ .string()
51
+ .optional()
52
+ .describe("Target filename for this screen, such as onboarding.html"),
53
+ role: z.enum(["screen", "variant"]).optional().default("screen"),
54
+ variantOf: z.string().optional(),
55
+ })
56
+ .superRefine((screen, ctx) => {
57
+ if (screen.role === "variant" && !screen.variantOf) {
58
+ ctx.addIssue({
59
+ code: z.ZodIssueCode.custom,
60
+ path: ["variantOf"],
61
+ message:
62
+ "variant screens require variantOf to identify the base screen",
63
+ });
64
+ }
65
+ });
55
66
 
56
67
  export default defineAction({
57
68
  description:
@@ -101,10 +112,39 @@ export default defineAction({
101
112
  origin: { x: 0, y: 0 },
102
113
  columns: screens.length <= 3 ? screens.length : 3,
103
114
  });
115
+
116
+ const seenFilenames = new Map<string, number>();
117
+ // Dedupe any filename (explicit or auto-generated) so two screens can never
118
+ // resolve to the same target file — otherwise generate-design silently
119
+ // overwrites the first screen's output with the second's.
120
+ const dedupeFilename = (base: string): string => {
121
+ if (!seenFilenames.has(base)) {
122
+ seenFilenames.set(base, 1);
123
+ return base;
124
+ }
125
+ const count = seenFilenames.get(base)! + 1;
126
+ seenFilenames.set(base, count);
127
+ const dot = base.lastIndexOf(".");
128
+ return dot > 0
129
+ ? `${base.slice(0, dot)}-${count}${base.slice(dot)}`
130
+ : `${base}-${count}`;
131
+ };
132
+ const requestedTargets = screens.map((screen, index) => {
133
+ if (screen.filename) return dedupeFilename(screen.filename);
134
+ const slug =
135
+ screen.title
136
+ .toLowerCase()
137
+ .replace(/[^a-z0-9]+/g, "-")
138
+ .replace(/^-+|-+$/g, "")
139
+ .slice(0, 48) || `screen-${index + 1}`;
140
+ return dedupeFilename(`${slug}.html`);
141
+ });
142
+
104
143
  const frames: DesignGenerationFrame[] = screens.map((screen, index) => {
105
144
  const frameId = screen.frameId ?? nanoid();
106
145
  return {
107
146
  frameId,
147
+ filename: requestedTargets[index],
108
148
  agentId: `agent-${frameId}`,
109
149
  agentName: AGENT_NAMES[index % AGENT_NAMES.length] ?? "Agent",
110
150
  agentColor:
@@ -142,15 +182,7 @@ export default defineAction({
142
182
 
143
183
  const targets = frames.map((frame, index) => {
144
184
  const requested = screens[index]!;
145
- const filename =
146
- requested.filename ??
147
- `${
148
- requested.title
149
- .toLowerCase()
150
- .replace(/[^a-z0-9]+/g, "-")
151
- .replace(/^-+|-+$/g, "")
152
- .slice(0, 48) || `screen-${index + 1}`
153
- }.html`;
185
+ const filename = requestedTargets[index]!;
154
186
  return {
155
187
  frameId: frame.frameId,
156
188
  title: requested.title,
@@ -43,7 +43,11 @@ export default defineAction({
43
43
  run: async ({ designId }) => {
44
44
  const access = await resolveAccess("design", designId);
45
45
  if (!access) {
46
- throw new Error("Design not found");
46
+ const err = new Error("Design not found") as Error & {
47
+ statusCode: number;
48
+ };
49
+ err.statusCode = 404;
50
+ throw err;
47
51
  }
48
52
  const design = access.resource as typeof schema.designs.$inferSelect;
49
53
 
@@ -13,6 +13,7 @@ export default defineAction({
13
13
  id: z.string().describe("Design ID"),
14
14
  }),
15
15
  readOnly: true,
16
+ requiresAuth: false,
16
17
  http: { method: "GET" },
17
18
  run: async ({ id }) => {
18
19
  const access = await resolveAccess("design", id);
@@ -39,6 +40,7 @@ export default defineAction({
39
40
  visibility: row.visibility,
40
41
  createdAt: row.createdAt,
41
42
  updatedAt: row.updatedAt,
43
+ accessRole: access.role,
42
44
  files: files.map((f) => ({
43
45
  id: f.id,
44
46
  filename: f.filename,
@@ -12,15 +12,28 @@ export default defineAction({
12
12
  "has good styling (CSS custom properties, fonts, colors), this extracts those " +
13
13
  "into reusable design tokens. Alternatively, import from an existing design system " +
14
14
  "for cloning/forking. Returns extracted tokens plus raw CSS for agent refinement.",
15
- schema: z.object({
16
- designId: z.string().describe("Design project ID to extract tokens from"),
17
- designSystemId: z
18
- .string()
19
- .optional()
20
- .describe(
21
- "If provided, import from this existing design system instead of extracting from the design project",
22
- ),
23
- }),
15
+ schema: z
16
+ .object({
17
+ designId: z
18
+ .string()
19
+ .optional()
20
+ .describe("Design project ID to extract tokens from"),
21
+ designSystemId: z
22
+ .string()
23
+ .optional()
24
+ .describe(
25
+ "If provided, import from this existing design system instead of extracting from the design project",
26
+ ),
27
+ })
28
+ .superRefine((args, ctx) => {
29
+ if (!args.designId && !args.designSystemId) {
30
+ ctx.addIssue({
31
+ code: z.ZodIssueCode.custom,
32
+ path: ["designId"],
33
+ message: "designId or designSystemId is required",
34
+ });
35
+ }
36
+ }),
24
37
  readOnly: true,
25
38
  http: { method: "GET" },
26
39
  run: async ({ designId, designSystemId }) => {
@@ -55,6 +68,12 @@ export default defineAction({
55
68
  };
56
69
  }
57
70
 
71
+ if (!designId) {
72
+ throw new Error(
73
+ "designId is required when designSystemId is not provided",
74
+ );
75
+ }
76
+
58
77
  // Extract tokens from the design project
59
78
  await assertAccess("design", designId, "viewer");
60
79
 
@@ -8,6 +8,9 @@ import {
8
8
  } from "@agent-native/core/server/design-token-utils";
9
9
  import { z } from "zod";
10
10
 
11
+ const DOC_MAX_FILES = 20;
12
+ const DOC_MAX_TEXT_BYTES = 500 * 1024;
13
+
11
14
  export default defineAction({
12
15
  description:
13
16
  "Process uploaded document metadata (DOCX, PPTX, PDF, XLSX) and return " +
@@ -44,16 +47,29 @@ export default defineAction({
44
47
  }),
45
48
  readOnly: true,
46
49
  run: async ({ files }) => {
47
- const processedFiles = files.map((file) => {
50
+ const capped = files.slice(0, DOC_MAX_FILES);
51
+ const processedFiles = capped.map((file) => {
48
52
  const contentType = classifyFile(file.fileType);
49
- const hasText = !!file.textContent && file.textContent.trim().length > 0;
53
+
54
+ // Truncate textContent before regex scanning to bound CPU/memory usage.
55
+ let text = file.textContent;
56
+ if (text) {
57
+ const encoded = new TextEncoder().encode(text);
58
+ if (encoded.byteLength > DOC_MAX_TEXT_BYTES) {
59
+ text = new TextDecoder().decode(
60
+ encoded.subarray(0, DOC_MAX_TEXT_BYTES),
61
+ );
62
+ }
63
+ }
64
+
65
+ const hasText = !!text && text.trim().length > 0;
50
66
 
51
67
  let likelyColors: string[] = [];
52
68
  let likelyFonts: string[] = [];
53
69
 
54
- if (file.textContent) {
55
- likelyColors = extractDocumentColors(file.textContent);
56
- likelyFonts = extractDocumentFonts(file.textContent);
70
+ if (text) {
71
+ likelyColors = extractDocumentColors(text);
72
+ likelyFonts = extractDocumentFonts(text);
57
73
  }
58
74
 
59
75
  if (file.metadata) {
@@ -80,9 +96,7 @@ export default defineAction({
80
96
  likelyColors,
81
97
  likelyFonts,
82
98
  contentType,
83
- extractedText: file.textContent
84
- ? file.textContent.slice(0, 2000)
85
- : undefined,
99
+ extractedText: text ? text.slice(0, 2000) : undefined,
86
100
  suggestions,
87
101
  },
88
102
  };