@agent-native/core 0.79.27 → 0.80.0

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 (346) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +26 -0
  3. package/corpus/core/docs/content/locales/ar-SA/template-design.mdx +41 -0
  4. package/corpus/core/docs/content/locales/de-DE/template-design.mdx +51 -0
  5. package/corpus/core/docs/content/locales/es-ES/template-design.mdx +50 -0
  6. package/corpus/core/docs/content/locales/fr-FR/template-design.mdx +49 -0
  7. package/corpus/core/docs/content/locales/hi-IN/template-design.mdx +44 -0
  8. package/corpus/core/docs/content/locales/ja-JP/template-design.mdx +46 -0
  9. package/corpus/core/docs/content/locales/ko-KR/template-design.mdx +44 -0
  10. package/corpus/core/docs/content/locales/pt-BR/template-design.mdx +48 -0
  11. package/corpus/core/docs/content/locales/zh-CN/template-design.mdx +36 -0
  12. package/corpus/core/docs/content/locales/zh-TW/template-design.mdx +38 -0
  13. package/corpus/core/docs/content/template-design.mdx +45 -0
  14. package/corpus/core/package.json +2 -1
  15. package/corpus/core/src/agent/engine/index.ts +1 -0
  16. package/corpus/core/src/agent/engine/registry.ts +40 -0
  17. package/corpus/core/src/agent/production-agent.ts +6 -2
  18. package/corpus/core/src/cli/design-connect.ts +490 -0
  19. package/corpus/core/src/cli/index.ts +16 -0
  20. package/corpus/core/src/cli/skills.ts +126 -3
  21. package/corpus/core/src/client/AssistantChat.tsx +43 -7
  22. package/corpus/core/src/client/agent-chat.ts +27 -3
  23. package/corpus/core/src/client/blocks/library/MermaidBlock.tsx +1 -1
  24. package/corpus/core/src/client/blocks/library/diagram.tsx +2 -2
  25. package/corpus/core/src/client/blocks/library/wireframe.tsx +1 -1
  26. package/corpus/core/src/client/chat/message-components.tsx +1 -1
  27. package/corpus/core/src/client/chat-model-groups.ts +1 -2
  28. package/corpus/core/src/client/components/LiveCursorOverlay.tsx +33 -66
  29. package/corpus/core/src/client/composer/TiptapComposer.tsx +99 -24
  30. package/corpus/core/src/client/composer/useVoiceDictation.ts +429 -260
  31. package/corpus/core/src/client/frame-protocol.ts +17 -2
  32. package/corpus/core/src/client/rich-markdown-editor/RegistryBlockNode.tsx +2 -2
  33. package/corpus/core/src/client/sharing/ShareButton.tsx +20 -15
  34. package/corpus/core/src/client/use-agent-engine-configured.ts +80 -28
  35. package/corpus/core/src/server/transcribe-voice.ts +57 -22
  36. package/corpus/core/src/shared/mcp-embed-headers.ts +23 -1
  37. package/corpus/core/src/styles/agent-native.css +56 -7
  38. package/corpus/core/src/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +10 -0
  39. package/corpus/core/src/vite/client.ts +2 -0
  40. package/corpus/core/src/voice/index.ts +18 -0
  41. package/corpus/core/src/voice/voice-cleanup-prompt.ts +38 -0
  42. package/corpus/core/src/voice/voice-context.ts +217 -0
  43. package/corpus/core/src/voice/voice-replacements.ts +75 -0
  44. package/corpus/templates/analytics/AGENTS.md +4 -3
  45. package/corpus/templates/analytics/actions/list-session-recordings.ts +6 -1
  46. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +557 -400
  47. package/corpus/templates/analytics/app/global.css +0 -4
  48. package/corpus/templates/analytics/app/i18n/zh-TW.ts +2 -0
  49. package/corpus/templates/analytics/app/i18n-data.ts +20 -0
  50. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +33 -8
  51. package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +7 -0
  52. package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +7 -0
  53. package/corpus/templates/analytics/changelog/2026-06-28-ask-tab-now-matches-the-darker-app-background.md +6 -0
  54. package/corpus/templates/analytics/changelog/2026-06-28-dashboard-email-reports-now-use-cleaner-light-mode-snapshots.md +6 -0
  55. package/corpus/templates/analytics/changelog/2026-06-28-left-sidebar-collapses-into-an-animated-icon-rail.md +6 -0
  56. package/corpus/templates/analytics/changelog/2026-06-28-sessions-now-show-only-signed-in-recordings-with-playable-re.md +6 -0
  57. package/corpus/templates/analytics/seeds/dashboards/agent-native-templates-first-party.json +3 -3
  58. package/corpus/templates/analytics/server/lib/dashboard-report.ts +29 -7
  59. package/corpus/templates/analytics/server/lib/first-party-metric-catalog.ts +5 -2
  60. package/corpus/templates/analytics/server/lib/session-replay.ts +24 -4
  61. package/corpus/templates/assets/app/components/layout/Sidebar.tsx +4 -4
  62. package/corpus/templates/assets/changelog/2026-06-28-left-sidebar-collapse-motion-and-footer-chrome-are-quieter.md +6 -0
  63. package/corpus/templates/brain/app/components/layout/Layout.tsx +29 -2
  64. package/corpus/templates/brain/app/components/layout/Sidebar.tsx +131 -42
  65. package/corpus/templates/brain/app/i18n/zh-TW.ts +2 -0
  66. package/corpus/templates/brain/app/i18n-data.ts +20 -0
  67. package/corpus/templates/brain/changelog/2026-06-28-left-sidebar-collapses-into-an-animated-icon-rail.md +6 -0
  68. package/corpus/templates/calendar/app/components/layout/AppLayout.tsx +29 -1
  69. package/corpus/templates/calendar/app/components/layout/Sidebar.tsx +417 -299
  70. package/corpus/templates/calendar/app/i18n/zh-TW.ts +2 -0
  71. package/corpus/templates/calendar/app/i18n-data.ts +20 -0
  72. package/corpus/templates/calendar/changelog/2026-06-28-left-sidebar-collapses-into-an-animated-icon-rail.md +6 -0
  73. package/corpus/templates/chat/app/components/layout/Sidebar.tsx +6 -19
  74. package/corpus/templates/chat/changelog/2026-06-28-left-sidebar-collapse-motion-and-footer-chrome-are-quieter.md +6 -0
  75. package/corpus/templates/clips/AGENTS.md +4 -0
  76. package/corpus/templates/clips/actions/cleanup-transcript.ts +39 -9
  77. package/corpus/templates/clips/actions/finalize-meeting.ts +81 -12
  78. package/corpus/templates/clips/actions/lib/agents-md-context.ts +4 -1
  79. package/corpus/templates/clips/app/components/library/library-layout.tsx +3 -3
  80. package/corpus/templates/clips/app/components/meetings/share-meeting-dialog.tsx +1 -1
  81. package/corpus/templates/clips/app/components/player/share-dialog.tsx +2 -2
  82. package/corpus/templates/clips/changelog/2026-06-28-left-sidebar-footer-controls-use-less-divider-chrome.md +6 -0
  83. package/corpus/templates/clips/desktop/src/lib/personal-vocabulary.ts +13 -8
  84. package/corpus/templates/clips/desktop/src/lib/voice-dictation.ts +60 -1
  85. package/corpus/templates/content/app/components/editor/DocumentDatabase.tsx +1 -1
  86. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +1 -1
  87. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +5 -5
  88. package/corpus/templates/content/changelog/2026-06-28-left-sidebar-collapse-motion-and-footer-chrome-are-quieter.md +6 -0
  89. package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +137 -0
  90. package/corpus/templates/design/AGENTS.md +95 -5
  91. package/corpus/templates/design/DESIGN.md +82 -0
  92. package/corpus/templates/design/DEVELOPING.md +43 -0
  93. package/corpus/templates/design/actions/add-localhost-screens.ts +426 -0
  94. package/corpus/templates/design/actions/apply-shader.ts +277 -0
  95. package/corpus/templates/design/actions/apply-visual-edit.ts +303 -0
  96. package/corpus/templates/design/actions/connect-localhost.ts +183 -0
  97. package/corpus/templates/design/actions/edit-design.ts +195 -42
  98. package/corpus/templates/design/actions/generate-design.ts +71 -1
  99. package/corpus/templates/design/actions/generate-screens.ts +193 -0
  100. package/corpus/templates/design/actions/get-code-layer-projection.ts +191 -0
  101. package/corpus/templates/design/actions/get-shader.ts +119 -0
  102. package/corpus/templates/design/actions/list-localhost-connections.ts +95 -0
  103. package/corpus/templates/design/actions/navigate.ts +55 -2
  104. package/corpus/templates/design/actions/view-screen.ts +68 -1
  105. package/corpus/templates/design/agent-native.app-skill.json +10 -0
  106. package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +761 -0
  107. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +2057 -103
  108. package/corpus/templates/design/app/components/design/DesignEditorSkeleton.tsx +74 -38
  109. package/corpus/templates/design/app/components/design/DesignExtensionsPanel.tsx +399 -0
  110. package/corpus/templates/design/app/components/design/EditPanel.tsx +3185 -439
  111. package/corpus/templates/design/app/components/design/LayersPanel.tsx +1124 -0
  112. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +3116 -147
  113. package/corpus/templates/design/app/components/design/QuestionFlow.tsx +700 -13
  114. package/corpus/templates/design/app/components/design/TweaksPanel.tsx +107 -63
  115. package/corpus/templates/design/app/components/design/index.ts +0 -5
  116. package/corpus/templates/design/app/components/design/inspector/AlignmentMatrix.tsx +286 -0
  117. package/corpus/templates/design/app/components/design/inspector/AutoLayoutMatrix.tsx +699 -0
  118. package/corpus/templates/design/app/components/design/inspector/ConstraintsWidget.tsx +461 -0
  119. package/corpus/templates/design/app/components/design/inspector/ExportSettingsPanel.tsx +166 -0
  120. package/corpus/templates/design/app/components/design/inspector/FigmaColorPicker.tsx +1420 -0
  121. package/corpus/templates/design/app/components/design/inspector/SHADER_INTEGRATION.md +420 -0
  122. package/corpus/templates/design/app/components/design/inspector/ScrubInput.tsx +215 -0
  123. package/corpus/templates/design/app/components/design/inspector/ShaderControls.stories.tsx +71 -0
  124. package/corpus/templates/design/app/components/design/inspector/ShaderControls.tsx +518 -0
  125. package/corpus/templates/design/app/components/design/inspector/ShaderEffectRow.tsx +106 -0
  126. package/corpus/templates/design/app/components/design/inspector/figma-icons.tsx +361 -0
  127. package/corpus/templates/design/app/components/design/inspector/index.ts +60 -0
  128. package/corpus/templates/design/app/components/design/inspector/scrub-input-utils.ts +201 -0
  129. package/corpus/templates/design/app/components/design/types.ts +23 -0
  130. package/corpus/templates/design/app/components/layout/Layout.tsx +24 -13
  131. package/corpus/templates/design/app/components/layout/Sidebar.tsx +4 -4
  132. package/corpus/templates/design/app/components/visual-editor/CanvasCommentPins.tsx +474 -36
  133. package/corpus/templates/design/app/components/visual-editor/DrawOverlay.tsx +22 -5
  134. package/corpus/templates/design/app/components/visual-editor/SaveStatusIndicator.tsx +24 -11
  135. package/corpus/templates/design/app/global.css +121 -3
  136. package/corpus/templates/design/app/hooks/use-agent-generating.ts +4 -0
  137. package/corpus/templates/design/app/hooks/use-navigation-state.ts +130 -8
  138. package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +329 -0
  139. package/corpus/templates/design/app/i18n/zh-TW.ts +264 -0
  140. package/corpus/templates/design/app/i18n-data.ts +2790 -1
  141. package/corpus/templates/design/app/pages/DesignEditor.tsx +5108 -851
  142. package/corpus/templates/design/changelog/2026-06-28-annotate-mode-now-combines-drawing-and-comment-pins-in-one-c.md +6 -0
  143. package/corpus/templates/design/changelog/2026-06-28-design-editor-panel-borders-are-cleaner-so-the-canvas-edge-s.md +6 -0
  144. package/corpus/templates/design/changelog/2026-06-28-drawing-prompts-now-reliably-open-and-submit-to-the-design-a.md +6 -0
  145. package/corpus/templates/design/changelog/2026-06-28-editor-app-menus-now-use-an-outline-agent-native-mark-with-b.md +6 -0
  146. package/corpus/templates/design/changelog/2026-06-28-figma-style-code-design-mode.md +6 -0
  147. package/corpus/templates/design/changelog/2026-06-28-layer-selection-now-updates-chat-context-without-opening-the.md +6 -0
  148. package/corpus/templates/design/changelog/2026-06-28-layer-selections-now-preserve-hidden-and-locked-canvas-state.md +6 -0
  149. package/corpus/templates/design/changelog/2026-06-28-left-sidebar-collapse-motion-and-footer-chrome-are-quieter.md +6 -0
  150. package/corpus/templates/design/changelog/2026-06-28-live-cursors-now-keep-names-beside-a-cleaner-pointer-marker.md +6 -0
  151. package/corpus/templates/design/changelog/2026-06-28-mode-switching-now-lives-in-a-compact-bottom-right-icon-dock.md +6 -0
  152. package/corpus/templates/design/changelog/2026-06-28-screen-overview-now-handles-zooming-drawing-opening-and-dele.md +6 -0
  153. package/corpus/templates/design/changelog/2026-06-28-screen-overview-now-selects-screens-on-click-and-opens-them-.md +6 -0
  154. package/corpus/templates/design/changelog/2026-06-28-screen-overview-zooms-into-the-active-screen-with-smoother-e.md +6 -0
  155. package/corpus/templates/design/changelog/2026-06-28-selected-element-chips-in-chat-are-shorter-and-easier-to-sca.md +6 -0
  156. package/corpus/templates/design/changelog/2026-06-28-the-design-editor-toolbar-is-more-compact-and-the-app-menu-m.md +6 -0
  157. package/corpus/templates/design/changelog/2026-06-28-tweaks-now-live-at-the-top-of-the-design-sidebar-instead-of-.md +6 -0
  158. package/corpus/templates/design/changelog/2026-06-28-tweaks-now-live-in-the-right-inspector-beside-the-design-tab.md +6 -0
  159. package/corpus/templates/design/changelog/2026-06-29-active-sidebar-rows-use-soft-highlights.md +6 -0
  160. package/corpus/templates/design/changelog/2026-06-29-agents-can-now-open-screen-overview-focus-screens-and-add.md +6 -0
  161. package/corpus/templates/design/changelog/2026-06-29-design-agents-now-edit-broad-copy-changes-more-reliably.md +6 -0
  162. package/corpus/templates/design/changelog/2026-06-29-design-editor-extensions-now-run-inline-beside-the-artboard.md +6 -0
  163. package/corpus/templates/design/changelog/2026-06-29-sidebars-use-darker-chrome-and-chat-warns-immediately.md +6 -0
  164. package/corpus/templates/design/changelog/2026-06-29-visual-edit-can-open-localhost-routes-as-url-backed-screens.md +6 -0
  165. package/corpus/templates/design/package.json +1 -0
  166. package/corpus/templates/design/server/db/schema.ts +26 -0
  167. package/corpus/templates/design/server/lib/design-snapshot.ts +1 -1
  168. package/corpus/templates/design/server/plugins/agent-chat.ts +3 -0
  169. package/corpus/templates/design/shared/api.ts +27 -0
  170. package/corpus/templates/design/shared/canvas-frames.ts +103 -0
  171. package/corpus/templates/design/shared/canvas-math.ts +1058 -0
  172. package/corpus/templates/design/shared/code-layer.ts +2212 -0
  173. package/corpus/templates/design/shared/color-utils.ts +180 -0
  174. package/corpus/templates/design/shared/generation-session.ts +61 -0
  175. package/corpus/templates/design/shared/shader-presets.ts +782 -0
  176. package/corpus/templates/design/shared/shader-safety.ts +137 -0
  177. package/corpus/templates/design/shared/source-mode.ts +237 -0
  178. package/corpus/templates/forms/app/components/layout/Sidebar.tsx +149 -6
  179. package/corpus/templates/forms/app/i18n/ar-SA.ts +2 -0
  180. package/corpus/templates/forms/app/i18n/de-DE.ts +2 -0
  181. package/corpus/templates/forms/app/i18n/en-US.ts +2 -0
  182. package/corpus/templates/forms/app/i18n/es-ES.ts +2 -0
  183. package/corpus/templates/forms/app/i18n/fr-FR.ts +2 -0
  184. package/corpus/templates/forms/app/i18n/hi-IN.ts +2 -0
  185. package/corpus/templates/forms/app/i18n/ja-JP.ts +2 -0
  186. package/corpus/templates/forms/app/i18n/ko-KR.ts +2 -0
  187. package/corpus/templates/forms/app/i18n/pt-BR.ts +2 -0
  188. package/corpus/templates/forms/app/i18n/zh-CN.ts +2 -0
  189. package/corpus/templates/forms/app/i18n/zh-TW.ts +2 -0
  190. package/corpus/templates/forms/changelog/2026-06-28-left-sidebar-collapses-into-an-animated-icon-rail.md +6 -0
  191. package/corpus/templates/macros/app/components/layout/AppLayout.tsx +2 -2
  192. package/corpus/templates/macros/changelog/2026-06-28-left-sidebar-footer-controls-use-less-divider-chrome.md +6 -0
  193. package/corpus/templates/mail/app/components/layout/AppLayout.tsx +408 -247
  194. package/corpus/templates/mail/app/i18n/ar-SA.ts +4 -0
  195. package/corpus/templates/mail/app/i18n/de-DE.ts +4 -0
  196. package/corpus/templates/mail/app/i18n/en-US.ts +4 -0
  197. package/corpus/templates/mail/app/i18n/es-ES.ts +4 -0
  198. package/corpus/templates/mail/app/i18n/fr-FR.ts +4 -0
  199. package/corpus/templates/mail/app/i18n/hi-IN.ts +4 -0
  200. package/corpus/templates/mail/app/i18n/ja-JP.ts +4 -0
  201. package/corpus/templates/mail/app/i18n/ko-KR.ts +4 -0
  202. package/corpus/templates/mail/app/i18n/pt-BR.ts +4 -0
  203. package/corpus/templates/mail/app/i18n/zh-CN.ts +4 -0
  204. package/corpus/templates/mail/app/i18n/zh-TW.ts +4 -0
  205. package/corpus/templates/mail/changelog/2026-06-28-pinned-sidebar-collapses-into-an-animated-icon-rail.md +6 -0
  206. package/corpus/templates/plan/app/components/layout/Sidebar.tsx +6 -8
  207. package/corpus/templates/plan/app/components/plan/wireframe/Wireframe.tsx +1 -1
  208. package/corpus/templates/plan/app/global.css +61 -78
  209. package/corpus/templates/plan/app/pages/PlansPage.tsx +8 -0
  210. package/corpus/templates/plan/changelog/2026-06-28-left-sidebar-collapse-motion-and-footer-chrome-are-quieter.md +6 -0
  211. package/corpus/templates/plan/changelog/2026-06-28-plans-use-the-shared-neutral-light-and-dark-theme.md +6 -0
  212. package/corpus/templates/plan/changelog/2026-06-28-sending-open-feedback-from-a-plan-now-opens-the-inline-plan-.md +6 -0
  213. package/corpus/templates/slides/app/components/layout/Sidebar.tsx +5 -5
  214. package/corpus/templates/slides/changelog/2026-06-28-left-sidebar-collapse-motion-and-footer-chrome-are-quieter.md +6 -0
  215. package/corpus/templates/videos/app/components/Sidebar.tsx +2 -2
  216. package/corpus/templates/videos/app/components/layout/Layout.tsx +29 -2
  217. package/corpus/templates/videos/app/components/layout/NavSidebar.tsx +113 -30
  218. package/corpus/templates/videos/app/i18n/ar-SA.ts +2 -0
  219. package/corpus/templates/videos/app/i18n/de-DE.ts +2 -0
  220. package/corpus/templates/videos/app/i18n/en-US.ts +2 -0
  221. package/corpus/templates/videos/app/i18n/es-ES.ts +2 -0
  222. package/corpus/templates/videos/app/i18n/fr-FR.ts +2 -0
  223. package/corpus/templates/videos/app/i18n/hi-IN.ts +2 -0
  224. package/corpus/templates/videos/app/i18n/ja-JP.ts +2 -0
  225. package/corpus/templates/videos/app/i18n/ko-KR.ts +2 -0
  226. package/corpus/templates/videos/app/i18n/pt-BR.ts +2 -0
  227. package/corpus/templates/videos/app/i18n/zh-CN.ts +2 -0
  228. package/corpus/templates/videos/app/i18n/zh-TW.ts +2 -0
  229. package/corpus/templates/videos/changelog/2026-06-28-left-sidebar-collapses-into-an-animated-icon-rail.md +6 -0
  230. package/dist/agent/engine/index.d.ts +1 -1
  231. package/dist/agent/engine/index.d.ts.map +1 -1
  232. package/dist/agent/engine/index.js +1 -1
  233. package/dist/agent/engine/index.js.map +1 -1
  234. package/dist/agent/engine/registry.d.ts +9 -0
  235. package/dist/agent/engine/registry.d.ts.map +1 -1
  236. package/dist/agent/engine/registry.js +37 -0
  237. package/dist/agent/engine/registry.js.map +1 -1
  238. package/dist/agent/production-agent.d.ts.map +1 -1
  239. package/dist/agent/production-agent.js +4 -3
  240. package/dist/agent/production-agent.js.map +1 -1
  241. package/dist/cli/design-connect.d.ts +52 -0
  242. package/dist/cli/design-connect.d.ts.map +1 -0
  243. package/dist/cli/design-connect.js +409 -0
  244. package/dist/cli/design-connect.js.map +1 -0
  245. package/dist/cli/index.js +15 -0
  246. package/dist/cli/index.js.map +1 -1
  247. package/dist/cli/skills.d.ts +3 -0
  248. package/dist/cli/skills.d.ts.map +1 -1
  249. package/dist/cli/skills.js +121 -3
  250. package/dist/cli/skills.js.map +1 -1
  251. package/dist/client/AssistantChat.d.ts.map +1 -1
  252. package/dist/client/AssistantChat.js +38 -8
  253. package/dist/client/AssistantChat.js.map +1 -1
  254. package/dist/client/agent-chat.d.ts +6 -0
  255. package/dist/client/agent-chat.d.ts.map +1 -1
  256. package/dist/client/agent-chat.js +17 -3
  257. package/dist/client/agent-chat.js.map +1 -1
  258. package/dist/client/blocks/library/MermaidBlock.js +1 -1
  259. package/dist/client/blocks/library/MermaidBlock.js.map +1 -1
  260. package/dist/client/blocks/library/diagram.js +1 -1
  261. package/dist/client/blocks/library/diagram.js.map +1 -1
  262. package/dist/client/blocks/library/wireframe.js +1 -1
  263. package/dist/client/blocks/library/wireframe.js.map +1 -1
  264. package/dist/client/chat/message-components.js +1 -1
  265. package/dist/client/chat/message-components.js.map +1 -1
  266. package/dist/client/chat-model-groups.d.ts.map +1 -1
  267. package/dist/client/chat-model-groups.js +1 -2
  268. package/dist/client/chat-model-groups.js.map +1 -1
  269. package/dist/client/components/LiveCursorOverlay.d.ts +1 -2
  270. package/dist/client/components/LiveCursorOverlay.d.ts.map +1 -1
  271. package/dist/client/components/LiveCursorOverlay.js +19 -40
  272. package/dist/client/components/LiveCursorOverlay.js.map +1 -1
  273. package/dist/client/composer/TiptapComposer.d.ts +3 -1
  274. package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
  275. package/dist/client/composer/TiptapComposer.js +86 -24
  276. package/dist/client/composer/TiptapComposer.js.map +1 -1
  277. package/dist/client/composer/useVoiceDictation.d.ts +9 -0
  278. package/dist/client/composer/useVoiceDictation.d.ts.map +1 -1
  279. package/dist/client/composer/useVoiceDictation.js +154 -32
  280. package/dist/client/composer/useVoiceDictation.js.map +1 -1
  281. package/dist/client/frame-protocol.d.ts +17 -2
  282. package/dist/client/frame-protocol.d.ts.map +1 -1
  283. package/dist/client/frame-protocol.js.map +1 -1
  284. package/dist/client/rich-markdown-editor/RegistryBlockNode.js +2 -2
  285. package/dist/client/rich-markdown-editor/RegistryBlockNode.js.map +1 -1
  286. package/dist/client/sharing/ShareButton.d.ts +2 -0
  287. package/dist/client/sharing/ShareButton.d.ts.map +1 -1
  288. package/dist/client/sharing/ShareButton.js +7 -6
  289. package/dist/client/sharing/ShareButton.js.map +1 -1
  290. package/dist/client/use-agent-engine-configured.d.ts +5 -0
  291. package/dist/client/use-agent-engine-configured.d.ts.map +1 -1
  292. package/dist/client/use-agent-engine-configured.js +51 -25
  293. package/dist/client/use-agent-engine-configured.js.map +1 -1
  294. package/dist/collab/awareness.d.ts +2 -2
  295. package/dist/collab/awareness.d.ts.map +1 -1
  296. package/dist/collab/routes.d.ts +1 -1
  297. package/dist/file-upload/actions/upload-image.d.ts +2 -2
  298. package/dist/notifications/routes.d.ts +3 -3
  299. package/dist/observability/routes.d.ts +8 -8
  300. package/dist/progress/routes.d.ts +1 -1
  301. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  302. package/dist/server/transcribe-voice.d.ts.map +1 -1
  303. package/dist/server/transcribe-voice.js +40 -24
  304. package/dist/server/transcribe-voice.js.map +1 -1
  305. package/dist/shared/mcp-embed-headers.d.ts +1 -0
  306. package/dist/shared/mcp-embed-headers.d.ts.map +1 -1
  307. package/dist/shared/mcp-embed-headers.js +20 -1
  308. package/dist/shared/mcp-embed-headers.js.map +1 -1
  309. package/dist/styles/agent-native.css +56 -7
  310. package/dist/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +10 -0
  311. package/dist/vite/client.d.ts.map +1 -1
  312. package/dist/vite/client.js +2 -0
  313. package/dist/vite/client.js.map +1 -1
  314. package/dist/voice/index.d.ts +5 -0
  315. package/dist/voice/index.d.ts.map +1 -0
  316. package/dist/voice/index.js +4 -0
  317. package/dist/voice/index.js.map +1 -0
  318. package/dist/voice/voice-cleanup-prompt.d.ts +6 -0
  319. package/dist/voice/voice-cleanup-prompt.d.ts.map +1 -0
  320. package/dist/voice/voice-cleanup-prompt.js +26 -0
  321. package/dist/voice/voice-cleanup-prompt.js.map +1 -0
  322. package/dist/voice/voice-context.d.ts +25 -0
  323. package/dist/voice/voice-context.d.ts.map +1 -0
  324. package/dist/voice/voice-context.js +156 -0
  325. package/dist/voice/voice-context.js.map +1 -0
  326. package/dist/voice/voice-replacements.d.ts +4 -0
  327. package/dist/voice/voice-replacements.d.ts.map +1 -0
  328. package/dist/voice/voice-replacements.js +52 -0
  329. package/dist/voice/voice-replacements.js.map +1 -0
  330. package/docs/content/locales/ar-SA/template-design.mdx +41 -0
  331. package/docs/content/locales/de-DE/template-design.mdx +51 -0
  332. package/docs/content/locales/es-ES/template-design.mdx +50 -0
  333. package/docs/content/locales/fr-FR/template-design.mdx +49 -0
  334. package/docs/content/locales/hi-IN/template-design.mdx +44 -0
  335. package/docs/content/locales/ja-JP/template-design.mdx +46 -0
  336. package/docs/content/locales/ko-KR/template-design.mdx +44 -0
  337. package/docs/content/locales/pt-BR/template-design.mdx +48 -0
  338. package/docs/content/locales/zh-CN/template-design.mdx +36 -0
  339. package/docs/content/locales/zh-TW/template-design.mdx +38 -0
  340. package/docs/content/template-design.mdx +45 -0
  341. package/package.json +2 -1
  342. package/src/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +10 -0
  343. package/corpus/templates/design/app/components/design/DesignToolbar.tsx +0 -339
  344. package/corpus/templates/design/app/components/design/PresentMode.tsx +0 -68
  345. package/corpus/templates/design/app/components/design/ViewportTabs.tsx +0 -149
  346. package/corpus/templates/design/app/components/design/ZoomControls.tsx +0 -157
@@ -13,53 +13,192 @@ import { and, eq } from "drizzle-orm";
13
13
  import { z } from "zod";
14
14
 
15
15
  import { getDb, schema } from "../server/db/index.js";
16
- import { applyEdits } from "../shared/apply-edits.js";
16
+ import {
17
+ applyOneEdit,
18
+ type ApplyEditsResult,
19
+ type DesignEdit,
20
+ } from "../shared/apply-edits.js";
21
+
22
+ const editBlocksSchema = z.preprocess(
23
+ (v) => {
24
+ if (typeof v !== "string") return v;
25
+ // Don't let malformed JSON throw an uncaught SyntaxError — return the
26
+ // raw value so Zod produces a clean validation error instead.
27
+ try {
28
+ return JSON.parse(v);
29
+ } catch {
30
+ return v;
31
+ }
32
+ },
33
+ z
34
+ .array(
35
+ z.object({
36
+ search: z
37
+ .string()
38
+ .min(1)
39
+ .describe(
40
+ "Exact text to find, with enough surrounding context to be unique",
41
+ ),
42
+ replace: z.string().describe("Replacement text"),
43
+ }),
44
+ )
45
+ .min(1),
46
+ );
47
+
48
+ function stripStableNodeIdAttributes(value: string): {
49
+ content: string;
50
+ indexMap: number[];
51
+ } {
52
+ const stableIdPattern =
53
+ /\sdata-agent-native-node-id\s*=\s*(?:"[^"]*"|'[^']*'|[^\s/>]+)/gi;
54
+ let content = "";
55
+ const indexMap: number[] = [];
56
+ let cursor = 0;
57
+ let match: RegExpExecArray | null;
58
+ while ((match = stableIdPattern.exec(value))) {
59
+ const chunk = value.slice(cursor, match.index);
60
+ for (let i = 0; i < chunk.length; i += 1) {
61
+ content += chunk[i];
62
+ indexMap.push(cursor + i);
63
+ }
64
+ cursor = match.index + match[0].length;
65
+ }
66
+ const tail = value.slice(cursor);
67
+ for (let i = 0; i < tail.length; i += 1) {
68
+ content += tail[i];
69
+ indexMap.push(cursor + i);
70
+ }
71
+ indexMap.push(value.length);
72
+ return { content, indexMap };
73
+ }
74
+
75
+ function findUniqueStableIdAgnosticSpan(
76
+ content: string,
77
+ search: string,
78
+ ): { start: number; end: number } | null {
79
+ const strippedContent = stripStableNodeIdAttributes(content);
80
+ const strippedSearch = stripStableNodeIdAttributes(search).content;
81
+ if (!strippedSearch) return null;
82
+
83
+ let count = 0;
84
+ let onlyIndex = -1;
85
+ let index = strippedContent.content.indexOf(strippedSearch);
86
+ while (index !== -1) {
87
+ count += 1;
88
+ onlyIndex = index;
89
+ if (count > 1) return null;
90
+ index = strippedContent.content.indexOf(strippedSearch, index + 1);
91
+ }
92
+ if (count !== 1) return null;
93
+
94
+ return {
95
+ start: strippedContent.indexMap[onlyIndex] ?? 0,
96
+ end:
97
+ strippedContent.indexMap[onlyIndex + strippedSearch.length] ??
98
+ content.length,
99
+ };
100
+ }
101
+
102
+ function applyOneEditWithStableIdFallback(
103
+ content: string,
104
+ edit: DesignEdit,
105
+ index: number,
106
+ ): string {
107
+ try {
108
+ return applyOneEdit(content, edit, index);
109
+ } catch (error) {
110
+ const span = findUniqueStableIdAgnosticSpan(content, edit.search);
111
+ if (!span) throw error;
112
+ return `${content.slice(0, span.start)}${edit.replace}${content.slice(span.end)}`;
113
+ }
114
+ }
115
+
116
+ export function applySearchReplaceEdits(
117
+ content: string,
118
+ edits: DesignEdit[],
119
+ ): ApplyEditsResult {
120
+ let next = content;
121
+ edits.forEach((edit, index) => {
122
+ next = applyOneEditWithStableIdFallback(next, edit, index);
123
+ });
124
+ return { content: next, applied: edits.length };
125
+ }
17
126
 
18
127
  export default defineAction({
19
128
  description:
20
- "Apply small, surgical search/replace edits to ONE file in a design the " +
129
+ "Edit ONE file in a design after reading it with get-design-snapshot. " +
130
+ "For small localized refinements, apply surgical search/replace edits — the " +
21
131
  "preferred way to refine an existing design without regenerating the whole " +
22
132
  "file (cheaper, faster, and it preserves everything you don't touch). Each " +
23
133
  "edit's `search` must match the current file exactly and uniquely, so " +
24
134
  "include enough surrounding context. Read the file first with " +
25
135
  "`get-design-snapshot`. Wrapping an element is just a search/replace whose " +
26
- "`replace` adds the wrapper around the original text. Use `generate-design` " +
136
+ "`replace` adds the wrapper around the original text. For broad copy-only " +
137
+ 'changes such as translating all visible text, use `mode: "replace-file"` ' +
138
+ "with `replacementContent`: the complete updated file content copied from " +
139
+ "the snapshot with only the requested copy changed. Use `generate-design` " +
27
140
  "instead only for brand-new files or large structural rewrites.",
28
- schema: z.object({
29
- designId: z.string().describe("Design project ID"),
30
- filename: z
31
- .string()
32
- .default("index.html")
33
- .describe("File to edit (e.g. 'index.html')"),
34
- edits: z
35
- .preprocess(
36
- (v) => {
37
- if (typeof v !== "string") return v;
38
- // Don't let malformed JSON throw an uncaught SyntaxError — return the
39
- // raw value so Zod produces a clean validation error instead.
40
- try {
41
- return JSON.parse(v);
42
- } catch {
43
- return v;
44
- }
45
- },
46
- z
47
- .array(
48
- z.object({
49
- search: z
50
- .string()
51
- .min(1)
52
- .describe(
53
- "Exact text to find, with enough surrounding context to be unique",
54
- ),
55
- replace: z.string().describe("Replacement text"),
56
- }),
57
- )
58
- .min(1),
59
- )
60
- .describe("Search/replace blocks, applied in order"),
61
- }),
62
- run: async ({ designId, filename, edits }) => {
141
+ schema: z
142
+ .object({
143
+ designId: z.string().describe("Design project ID"),
144
+ filename: z
145
+ .string()
146
+ .default("index.html")
147
+ .describe("File to edit (e.g. 'index.html')"),
148
+ mode: z
149
+ .enum(["search-replace", "replace-file"])
150
+ .optional()
151
+ .describe(
152
+ "Defaults to search-replace. Use replace-file for broad copy-only edits like translating the whole page after reading get-design-snapshot.",
153
+ ),
154
+ edits: editBlocksSchema
155
+ .optional()
156
+ .describe(
157
+ "Search/replace blocks, applied in order. Use for small localized edits.",
158
+ ),
159
+ replacementContent: z
160
+ .string()
161
+ .min(1)
162
+ .optional()
163
+ .describe(
164
+ "Complete updated file content. Use only with mode=replace-file for broad copy-only changes; preserve all HTML structure, CSS, scripts, and tweaks from get-design-snapshot.",
165
+ ),
166
+ })
167
+ .superRefine((value, ctx) => {
168
+ const mode =
169
+ value.mode ??
170
+ (value.replacementContent !== undefined
171
+ ? "replace-file"
172
+ : "search-replace");
173
+
174
+ if (value.edits && value.replacementContent !== undefined) {
175
+ ctx.addIssue({
176
+ code: z.ZodIssueCode.custom,
177
+ message:
178
+ "Use either edits or replacementContent in one edit-design call, not both.",
179
+ path: ["replacementContent"],
180
+ });
181
+ }
182
+
183
+ if (mode === "search-replace" && !value.edits) {
184
+ ctx.addIssue({
185
+ code: z.ZodIssueCode.custom,
186
+ message:
187
+ "search-replace mode requires at least one edit block in edits.",
188
+ path: ["edits"],
189
+ });
190
+ }
191
+
192
+ if (mode === "replace-file" && value.replacementContent === undefined) {
193
+ ctx.addIssue({
194
+ code: z.ZodIssueCode.custom,
195
+ message:
196
+ "replace-file mode requires replacementContent with the complete updated file.",
197
+ path: ["replacementContent"],
198
+ });
199
+ }
200
+ }),
201
+ run: async ({ designId, filename, edits, mode, replacementContent }) => {
63
202
  await assertAccess("design", designId, "editor");
64
203
 
65
204
  const db = getDb();
@@ -104,21 +243,34 @@ export default defineAction({
104
243
  // Collab read is best-effort; fall back to stored content.
105
244
  }
106
245
 
107
- const { content: nextContent, applied } = applyEdits(base, edits);
246
+ const resolvedMode =
247
+ mode ??
248
+ (replacementContent !== undefined ? "replace-file" : "search-replace");
249
+ const { content: nextContent, applied } =
250
+ resolvedMode === "replace-file"
251
+ ? { content: replacementContent ?? "", applied: 0 }
252
+ : applySearchReplaceEdits(base, edits ?? []);
108
253
  const changed = nextContent !== base;
109
254
 
110
255
  if (changed) {
111
256
  // Mark agent presence + selection so live viewers can see where the
112
257
  // agent is working before the update arrives via collab.
113
258
  agentEnterDocument(file.id);
114
- if (applied > 0) {
259
+ if (resolvedMode === "search-replace" && applied > 0) {
260
+ const firstSearch = edits?.[0]?.search;
115
261
  agentUpdateSelection(file.id, {
116
- selection: edits[0]?.search
117
- ? `[data-edit-target="${edits[0].search.slice(0, 40)}"]`
262
+ selection: firstSearch
263
+ ? `[data-edit-target="${firstSearch.slice(0, 40)}"]`
118
264
  : null,
119
265
  editingFile: filename,
120
266
  designId,
121
267
  });
268
+ } else {
269
+ agentUpdateSelection(file.id, {
270
+ selection: null,
271
+ editingFile: filename,
272
+ designId,
273
+ });
122
274
  }
123
275
 
124
276
  try {
@@ -148,6 +300,7 @@ export default defineAction({
148
300
  designId,
149
301
  filename,
150
302
  fileId: file.id,
303
+ mode: resolvedMode,
151
304
  editsApplied: applied,
152
305
  changed,
153
306
  bytesBefore: base.length,
@@ -14,6 +14,10 @@ import { nanoid } from "nanoid";
14
14
  import { z } from "zod";
15
15
 
16
16
  import { getDb, schema } from "../server/db/index.js";
17
+ import {
18
+ mergeCanvasFramePlacements,
19
+ type CanvasFramePlacement,
20
+ } from "../shared/canvas-frames.js";
17
21
 
18
22
  /** Editor deep link so external agents can surface "Open design". */
19
23
  function designDeepLink(designId: string): string {
@@ -34,7 +38,9 @@ export default defineAction({
34
38
  "version then refine individual files with `edit-design` (search/replace) rather " +
35
39
  "than resending a big multi-file payload — a single oversized payload can get cut " +
36
40
  "off mid-stream and stall the turn. " +
37
- "Do not report a design as ready until this action succeeds.",
41
+ "Do not report a design as ready until this action succeeds. " +
42
+ "When adding multiple screens or states, pass canvasFrames with filenames " +
43
+ "and x/y/width/height so the new screens appear placed on the overview canvas.",
38
44
  schema: z.object({
39
45
  designId: z.string().describe("Design project ID to save content to"),
40
46
  prompt: z.string().describe("The generation prompt (stored for reference)"),
@@ -106,6 +112,34 @@ export default defineAction({
106
112
  "radius, dark mode, font choice). Each must reference a CSS var " +
107
113
  "the design's `:root` block actually uses.",
108
114
  ),
115
+ canvasFrames: z
116
+ .preprocess(
117
+ (v) => (typeof v === "string" ? JSON.parse(v) : v),
118
+ z
119
+ .array(
120
+ z
121
+ .object({
122
+ fileId: z.string().optional(),
123
+ filename: z.string().optional(),
124
+ x: z.number().optional(),
125
+ y: z.number().optional(),
126
+ width: z.number().optional(),
127
+ height: z.number().optional(),
128
+ rotation: z.number().optional(),
129
+ z: z.number().optional(),
130
+ })
131
+ .refine((frame) => frame.fileId || frame.filename, {
132
+ message: "canvasFrames entries require fileId or filename",
133
+ }),
134
+ )
135
+ .optional(),
136
+ )
137
+ .optional()
138
+ .describe(
139
+ "Optional overview-canvas placements for generated screens. " +
140
+ "Reference each screen by filename or fileId and include x/y/width/height " +
141
+ "from generate-screens regions or your planned canvas layout.",
142
+ ),
109
143
  }),
110
144
  mcpApp: {
111
145
  compactCatalog: true,
@@ -124,6 +158,7 @@ export default defineAction({
124
158
  designSystemId,
125
159
  projectType,
126
160
  tweaks,
161
+ canvasFrames,
127
162
  }) => {
128
163
  await assertAccess("design", designId, "editor");
129
164
  if (designSystemId) {
@@ -280,6 +315,40 @@ export default defineAction({
280
315
  type: tweak.type === "color-swatches" ? "color-swatch" : tweak.type,
281
316
  }));
282
317
  }
318
+ let placedFrames:
319
+ | Array<{
320
+ fileId: string;
321
+ filename?: string;
322
+ frame: CanvasFramePlacement;
323
+ }>
324
+ | 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
341
+ : 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
+ }
283
352
  designUpdates.data = JSON.stringify(mergedData);
284
353
 
285
354
  await db
@@ -292,6 +361,7 @@ export default defineAction({
292
361
  urlPath: `/design/${designId}`,
293
362
  renderable: true,
294
363
  savedFiles,
364
+ placedFrames,
295
365
  fileCount: savedFiles.length,
296
366
  };
297
367
  },
@@ -0,0 +1,193 @@
1
+ import { defineAction, embedApp } from "@agent-native/core";
2
+ import { writeAppState } from "@agent-native/core/application-state";
3
+ import { buildDeepLink } from "@agent-native/core/server";
4
+ import { assertAccess } from "@agent-native/core/sharing";
5
+ import { nanoid } from "nanoid";
6
+ import { z } from "zod";
7
+
8
+ import "../server/db/index.js";
9
+ import { assignRegions } from "../shared/canvas-math.js";
10
+ import {
11
+ designGenerationSessionKey,
12
+ type DesignGenerationFrame,
13
+ type DesignGenerationSession,
14
+ } from "../shared/generation-session.js";
15
+
16
+ const AGENT_NAMES = [
17
+ "Atlas",
18
+ "Nova",
19
+ "Kai",
20
+ "Mira",
21
+ "Sol",
22
+ "Vega",
23
+ "Rune",
24
+ "Iris",
25
+ ];
26
+
27
+ const AGENT_COLORS = [
28
+ "var(--design-editor-accent-color)",
29
+ "hsl(var(--chart-2))",
30
+ "hsl(var(--chart-3))",
31
+ "hsl(var(--chart-4))",
32
+ "hsl(var(--chart-5))",
33
+ ];
34
+
35
+ function designDeepLink(designId: string): string {
36
+ const path = `/design/${encodeURIComponent(designId)}?view=overview`;
37
+ return buildDeepLink({
38
+ app: "design",
39
+ view: "editor",
40
+ params: { designId },
41
+ to: path,
42
+ });
43
+ }
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
+ });
55
+
56
+ export default defineAction({
57
+ description:
58
+ "Start a visible multi-agent generation session on the Design canvas. " +
59
+ "Use this before generating multiple screens or variations in parallel: it " +
60
+ "assigns non-overlapping canvas regions, publishes named agent/frame " +
61
+ "status to application state, and returns per-frame generation instructions. " +
62
+ "After this action, fan out calls to generate-design for each returned " +
63
+ "frame, passing the returned canvasFrame values to generate-design so " +
64
+ "screens appear in the infinite overview canvas.",
65
+ schema: z.object({
66
+ designId: z.string().describe("Design project ID to generate into"),
67
+ prompt: z.string().min(1).describe("Overall generation prompt"),
68
+ screens: z
69
+ .preprocess(
70
+ (value) => (typeof value === "string" ? JSON.parse(value) : value),
71
+ z.array(requestedScreenSchema).min(1).max(8),
72
+ )
73
+ .describe("Screens or variants that should be generated on the canvas"),
74
+ designSystemId: z
75
+ .string()
76
+ .optional()
77
+ .describe("Locked design system/token set for every worker"),
78
+ contextRefs: z
79
+ .array(z.string())
80
+ .optional()
81
+ .default([])
82
+ .describe("Selected frame/image/reference ids attached as context"),
83
+ }),
84
+ mcpApp: {
85
+ compactCatalog: true,
86
+ resource: embedApp({
87
+ title: "Design generation session",
88
+ description: "Open the Design editor with agent generation visible.",
89
+ iframeTitle: "Agent-Native Design",
90
+ openLabel: "Open generation session",
91
+ height: 720,
92
+ }),
93
+ },
94
+ run: async ({ designId, prompt, screens, designSystemId, contextRefs }) => {
95
+ await assertAccess("design", designId, "editor");
96
+ if (designSystemId) {
97
+ await assertAccess("design-system", designSystemId, "viewer");
98
+ }
99
+
100
+ const regions = assignRegions(screens.length, {
101
+ origin: { x: 0, y: 0 },
102
+ columns: screens.length <= 3 ? screens.length : 3,
103
+ });
104
+ const frames: DesignGenerationFrame[] = screens.map((screen, index) => {
105
+ const frameId = screen.frameId ?? nanoid();
106
+ return {
107
+ frameId,
108
+ agentId: `agent-${frameId}`,
109
+ agentName: AGENT_NAMES[index % AGENT_NAMES.length] ?? "Agent",
110
+ agentColor:
111
+ AGENT_COLORS[index % AGENT_COLORS.length] ??
112
+ "var(--design-editor-accent-color)",
113
+ region: regions[index]!,
114
+ role: screen.role,
115
+ variantOf: screen.variantOf,
116
+ status: "queued",
117
+ step: "Queued",
118
+ progress: 0,
119
+ };
120
+ });
121
+
122
+ const session: DesignGenerationSession = {
123
+ id: nanoid(),
124
+ designId,
125
+ status: "planning",
126
+ designSystemId,
127
+ prompt,
128
+ contextRefs,
129
+ frames,
130
+ };
131
+
132
+ await writeAppState(
133
+ designGenerationSessionKey(designId),
134
+ session as unknown as Record<string, unknown>,
135
+ );
136
+ await writeAppState("navigate", {
137
+ view: "editor",
138
+ designId,
139
+ editorView: "overview",
140
+ path: `/design/${encodeURIComponent(designId)}?view=overview`,
141
+ });
142
+
143
+ const targets = frames.map((frame, index) => {
144
+ 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`;
154
+ return {
155
+ frameId: frame.frameId,
156
+ title: requested.title,
157
+ filename,
158
+ role: frame.role,
159
+ variantOf: frame.variantOf,
160
+ canvasFrame: {
161
+ filename,
162
+ x: frame.region.x,
163
+ y: frame.region.y,
164
+ width: frame.region.width,
165
+ height: frame.region.height,
166
+ z: index,
167
+ },
168
+ };
169
+ });
170
+
171
+ return {
172
+ designId,
173
+ sessionId: session.id,
174
+ status: session.status,
175
+ frames,
176
+ targets,
177
+ path: `/design/${encodeURIComponent(designId)}?view=overview`,
178
+ embed: true,
179
+ nextRequiredAction:
180
+ "Generate each target with generate-design, using the target filename and canvasFrame placement, the same designSystemId, and contextRefs for coherence.",
181
+ };
182
+ },
183
+ link: ({ result }) => {
184
+ if (!result || typeof result !== "object") return null;
185
+ const designId = (result as { designId?: string }).designId;
186
+ if (!designId) return null;
187
+ return {
188
+ url: designDeepLink(designId),
189
+ label: "Open generation session",
190
+ view: "editor",
191
+ };
192
+ },
193
+ });