@agent-native/core 0.80.8 → 0.80.9

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 (281) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +12 -0
  3. package/corpus/core/docs/content/locales/ar-SA/template-design.mdx +6 -0
  4. package/corpus/core/docs/content/locales/de-DE/template-design.mdx +8 -0
  5. package/corpus/core/docs/content/locales/es-ES/template-design.mdx +10 -2
  6. package/corpus/core/docs/content/locales/fr-FR/template-design.mdx +10 -2
  7. package/corpus/core/docs/content/locales/hi-IN/template-design.mdx +7 -0
  8. package/corpus/core/docs/content/locales/ja-JP/template-design.mdx +7 -0
  9. package/corpus/core/docs/content/locales/ko-KR/template-design.mdx +7 -0
  10. package/corpus/core/docs/content/locales/pt-BR/template-design.mdx +9 -2
  11. package/corpus/core/docs/content/locales/zh-CN/template-design.mdx +6 -0
  12. package/corpus/core/docs/content/locales/zh-TW/template-design.mdx +6 -0
  13. package/corpus/core/docs/content/template-design.mdx +9 -2
  14. package/corpus/core/package.json +1 -1
  15. package/corpus/core/src/cli/mcp.ts +10 -0
  16. package/corpus/core/src/cli/skills.ts +58 -12
  17. package/corpus/core/src/client/error-format.ts +25 -0
  18. package/corpus/core/src/client/extensions/ExtensionViewer.tsx +13 -11
  19. package/corpus/core/src/client/guided-questions.tsx +32 -4
  20. package/corpus/core/src/client/onboarding/OnboardingPanel.tsx +33 -1
  21. package/corpus/core/src/client/resources/BuiltinCapabilityDetail.tsx +8 -0
  22. package/corpus/core/src/client/resources/use-builtin-capabilities.ts +4 -2
  23. package/corpus/core/src/client/session-replay.ts +34 -0
  24. package/corpus/core/src/client/sharing/ShareButton.tsx +106 -21
  25. package/corpus/core/src/coding-tools/index.ts +1 -1
  26. package/corpus/core/src/mcp/index.ts +2 -0
  27. package/corpus/core/src/mcp/screen-memory-stdio.ts +290 -0
  28. package/corpus/core/src/mcp-client/builtin-capabilities.ts +13 -1
  29. package/corpus/core/src/mcp-client/index.ts +9 -0
  30. package/corpus/core/src/mcp-client/screen-memory-local.ts +461 -0
  31. package/corpus/core/src/onboarding/types.ts +7 -0
  32. package/corpus/core/src/server/agent-chat-plugin.ts +25 -0
  33. package/corpus/core/src/server/agents-bundle.ts +35 -7
  34. package/corpus/core/src/styles/agent-native.css +5 -0
  35. package/corpus/core/src/templates/default/app/global.css +35 -35
  36. package/corpus/templates/analytics/AGENTS.md +6 -0
  37. package/corpus/templates/analytics/actions/github-repo-files.ts +9 -0
  38. package/corpus/templates/analytics/app/components/layout/Layout.tsx +4 -4
  39. package/corpus/templates/analytics/app/global.css +144 -40
  40. package/corpus/templates/analytics/app/pages/adhoc/explorer/index.tsx +1 -1
  41. package/corpus/templates/analytics/app/pages/adhoc/explorer-dashboard/ChartCard.tsx +1 -1
  42. package/corpus/templates/analytics/app/pages/adhoc/explorer-dashboard/index.tsx +1 -1
  43. package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +4 -4
  44. package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +9 -9
  45. package/corpus/templates/analytics/changelog/2026-06-29-agents-can-search-and-read-connected-github-repositories-whe.md +6 -0
  46. package/corpus/templates/analytics/changelog/2026-06-29-sessions-and-explorer-layouts-adapt-when-the-agent-sidebar-is.md +6 -0
  47. package/corpus/templates/assets/app/components/layout/Layout.tsx +3 -1
  48. package/corpus/templates/assets/app/components/library/LibraryPresetGrid.tsx +1 -1
  49. package/corpus/templates/assets/app/global.css +99 -35
  50. package/corpus/templates/assets/app/routes/asset.$id.tsx +2 -2
  51. package/corpus/templates/assets/app/routes/brand-kits.$id.tsx +4 -4
  52. package/corpus/templates/assets/app/routes/library.tsx +4 -4
  53. package/corpus/templates/assets/changelog/2026-06-29-asset-library-and-detail-layouts-adapt-when-the-agent-sidebar.md +6 -0
  54. package/corpus/templates/brain/app/components/layout/Layout.tsx +1 -1
  55. package/corpus/templates/brain/app/global.css +63 -35
  56. package/corpus/templates/brain/app/routes/search.tsx +1 -1
  57. package/corpus/templates/brain/app/routes/settings.tsx +1 -1
  58. package/corpus/templates/brain/app/routes/sources.tsx +2 -2
  59. package/corpus/templates/brain/changelog/2026-06-29-search-settings-and-source-layouts-adapt-when-the-agent-sidebar.md +6 -0
  60. package/corpus/templates/calendar/app/components/calendar/EventDetailPanel.tsx +4 -4
  61. package/corpus/templates/calendar/app/components/calendar/FindTimePanel.tsx +3 -2
  62. package/corpus/templates/calendar/app/components/layout/AppLayout.tsx +4 -2
  63. package/corpus/templates/calendar/app/global.css +69 -35
  64. package/corpus/templates/calendar/changelog/2026-06-29-event-and-find-time-layouts-adapt-when-the-agent-sidebar-is.md +6 -0
  65. package/corpus/templates/chat/app/components/layout/Layout.tsx +1 -1
  66. package/corpus/templates/chat/app/global.css +35 -35
  67. package/corpus/templates/chat/changelog/2026-06-29-chat-layouts-adapt-when-the-agent-sidebar-is-open.md +6 -0
  68. package/corpus/templates/clips/AGENTS.md +13 -0
  69. package/corpus/templates/clips/actions/get-screen-memory-status.ts +12 -0
  70. package/corpus/templates/clips/actions/query-screen-memory-context.ts +29 -0
  71. package/corpus/templates/clips/actions/view-screen.ts +2 -2
  72. package/corpus/templates/clips/app/components/library/library-layout.tsx +1 -1
  73. package/corpus/templates/clips/app/global.css +47 -35
  74. package/corpus/templates/clips/app/routes/_app.meetings.$meetingId.tsx +3 -3
  75. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +45 -18
  76. package/corpus/templates/clips/changelog/2026-06-29-meeting-detail-layouts-adapt-when-the-agent-sidebar-is-open.md +6 -0
  77. package/corpus/templates/clips/changelog/2026-06-29-screen-memory-keeps-a-local-rolling-screen-buffer-for-agent-context.md +5 -0
  78. package/corpus/templates/clips/changelog/2026-06-29-video-chat-is-easier-to-find-on-recording-pages-and-s3-setup.md +6 -0
  79. package/corpus/templates/clips/chrome-extension/src/styles.css +39 -39
  80. package/corpus/templates/clips/desktop/src/app.tsx +290 -1
  81. package/corpus/templates/clips/desktop/src/shared/config.ts +83 -0
  82. package/corpus/templates/clips/desktop/src/styles.css +67 -52
  83. package/corpus/templates/clips/desktop/src-tauri/src/config.rs +50 -0
  84. package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +17 -0
  85. package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +13 -13
  86. package/corpus/templates/clips/desktop/src-tauri/src/screen_memory.rs +990 -0
  87. package/corpus/templates/clips/server/plugins/onboarding.ts +2 -0
  88. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +3 -3
  89. package/corpus/templates/content/app/components/layout/Layout.tsx +1 -1
  90. package/corpus/templates/content/app/global.css +29 -15
  91. package/corpus/templates/content/changelog/2026-06-29-database-gallery-layouts-adapt-when-the-agent-sidebar-is-open.md +6 -0
  92. package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +25 -20
  93. package/corpus/templates/design/.agents/skills/design-systems/SKILL.md +8 -0
  94. package/corpus/templates/design/.agents/skills/export-handoff/SKILL.md +8 -0
  95. package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +13 -0
  96. package/corpus/templates/design/AGENTS.md +20 -12
  97. package/corpus/templates/design/CODE_NATIVE_DESIGN_STUDIO_IMPLEMENTATION_PLAN.md +1054 -0
  98. package/corpus/templates/design/actions/apply-visual-edit.ts +24 -4
  99. package/corpus/templates/design/actions/export-coding-handoff.ts +12 -4
  100. package/corpus/templates/design/actions/generate-design.ts +6 -21
  101. package/corpus/templates/design/actions/generate-screens.ts +43 -2
  102. package/corpus/templates/design/actions/get-design.ts +1 -0
  103. package/corpus/templates/design/actions/present-design-variants.ts +355 -30
  104. package/corpus/templates/design/actions/view-screen.ts +75 -31
  105. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +329 -69
  106. package/corpus/templates/design/app/components/design/DesignEditorSkeleton.tsx +1 -1
  107. package/corpus/templates/design/app/components/design/EditPanel.tsx +479 -77
  108. package/corpus/templates/design/app/components/design/LayersPanel.tsx +380 -216
  109. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +1050 -196
  110. package/corpus/templates/design/app/components/design/QuestionFlow.tsx +83 -206
  111. package/corpus/templates/design/app/components/design/TweaksPanel.tsx +1 -1
  112. package/corpus/templates/design/app/components/design/index.ts +0 -1
  113. package/corpus/templates/design/app/components/design/inspector/AutoLayoutMatrix.tsx +225 -133
  114. package/corpus/templates/design/app/components/design/inspector/DesignColorPicker.tsx +122 -11
  115. package/corpus/templates/design/app/components/design/inspector/ExportSettingsPanel.tsx +24 -5
  116. package/corpus/templates/design/app/components/design/inspector/ImageFillControls.tsx +57 -1
  117. package/corpus/templates/design/app/components/design/inspector/ScrubInput.tsx +37 -12
  118. package/corpus/templates/design/app/components/design/inspector/index.ts +1 -0
  119. package/corpus/templates/design/app/components/design/inspector/scrub-input-utils.ts +12 -5
  120. package/corpus/templates/design/app/components/design/types.ts +9 -0
  121. package/corpus/templates/design/app/components/layout/Layout.tsx +23 -5
  122. package/corpus/templates/design/app/global.css +77 -49
  123. package/corpus/templates/design/app/hooks/use-question-flow.ts +2 -2
  124. package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +8 -1
  125. package/corpus/templates/design/app/i18n/zh-TW.ts +3 -0
  126. package/corpus/templates/design/app/i18n-data.ts +45 -3
  127. package/corpus/templates/design/app/pages/DesignEditor.tsx +2602 -657
  128. package/corpus/templates/design/app/root.tsx +1 -1
  129. package/corpus/templates/design/changelog/2026-06-29-containers-no-longer-block-selecting-nested-elements-and-nor.md +6 -0
  130. package/corpus/templates/design/changelog/2026-06-29-design-agents-now-generate-and-refine-variants-from-stronger.md +6 -0
  131. package/corpus/templates/design/changelog/2026-06-29-design-inspector-controls-now-match-figmas-softer-dark-chrome.md +6 -0
  132. package/corpus/templates/design/changelog/2026-06-29-design-questions-now-appear-as-a-cleaner-canvas-intake-with-.md +6 -0
  133. package/corpus/templates/design/changelog/2026-06-29-design-variant-directions-now-appear-as-board-screens-with-chat-buttons.md +5 -0
  134. package/corpus/templates/design/changelog/2026-06-29-element-selection-no-longer-snaps-back-to-the-previous-layer.md +6 -0
  135. package/corpus/templates/design/changelog/2026-06-29-frame-resize-measurements-now-stay-beside-the-cursor-while-d.md +6 -0
  136. package/corpus/templates/design/changelog/2026-06-29-inspector-number-fields-have-cleaner-tooltips-and-draggable-.md +6 -0
  137. package/corpus/templates/design/changelog/2026-06-29-layer-locking-layer-nesting-generated-question-intake-and-im.md +6 -0
  138. package/corpus/templates/design/changelog/2026-06-29-layer-names-in-the-sidebar-can-scroll-horizontally-instead-o.md +6 -0
  139. package/corpus/templates/design/changelog/2026-06-29-layer-nesting-in-the-sidebar-now-uses-tighter-spacing-so-nam.md +6 -0
  140. package/corpus/templates/design/changelog/2026-06-29-layers-no-longer-repeat-document-wrapper-rows-when-a-screen-.md +6 -0
  141. package/corpus/templates/design/changelog/2026-06-29-overview-previews-now-keep-element-hover-and-selection-tied-.md +6 -0
  142. package/corpus/templates/design/changelog/2026-06-29-pressing-escape-now-cancels-a-stuck-screen-drag-in-the-overv.md +6 -0
  143. package/corpus/templates/design/changelog/2026-06-29-screen-overview-is-easier-to-find-and-named-screens-open-dir.md +6 -0
  144. package/corpus/templates/design/changelog/2026-06-29-screen-overview-only-highlights-screens-when-the-frame-or-ti.md +6 -0
  145. package/corpus/templates/design/changelog/2026-06-29-screen-overview-previews-now-resize-to-match-the-selected-de.md +6 -0
  146. package/corpus/templates/design/changelog/2026-06-29-screen-overview-selection-now-uses-a-pointer-cursor-instead-.md +6 -0
  147. package/corpus/templates/design/changelog/2026-06-29-screen-overview-selection-outlines-now-stay-locked-to-the-se.md +6 -0
  148. package/corpus/templates/design/changelog/2026-06-29-screen-overview-zoom-now-reports-real-screen-scale-separatel.md +6 -0
  149. package/corpus/templates/design/changelog/2026-06-29-screen-overview-zooming-feels-smoother-and-selection-outline.md +6 -0
  150. package/corpus/templates/design/changelog/2026-06-29-screen-overview-zooming-now-stays-on-the-overview-canvas-ins.md +6 -0
  151. package/corpus/templates/design/changelog/2026-06-29-selecting-a-nested-layer-from-all-screens-now-keeps-you-in-a.md +6 -0
  152. package/corpus/templates/design/changelog/2026-06-29-share-now-groups-link-sharing-exports-and-agent-handoff.md +6 -0
  153. package/corpus/templates/design/changelog/2026-06-29-the-design-editor-loading-skeleton-now-uses-a-softer-charcoa.md +6 -0
  154. package/corpus/templates/design/changelog/2026-06-29-the-device-preview-menu-now-sits-next-to-the-preview-button-.md +6 -0
  155. package/corpus/templates/design/changelog/2026-06-29-the-inspector-stays-read-only-while-an-empty-design-is-still.md +6 -0
  156. package/corpus/templates/design/changelog/2026-06-29-the-missing-design-view-now-matches-the-rest-of-the-editor-c.md +6 -0
  157. package/corpus/templates/design/changelog/2026-06-29-the-pen-tool-icon-and-tool-option-menus-better-match-the-edi.md +6 -0
  158. package/corpus/templates/design/changelog/2026-06-29-typography-controls-now-keep-the-font-name-visible-and-move-.md +6 -0
  159. package/corpus/templates/design/e2e/README.md +3 -3
  160. package/corpus/templates/design/e2e/global-setup.ts +11 -22
  161. package/corpus/templates/design/e2e/helpers.ts +122 -11
  162. package/corpus/templates/design/playwright.config.ts +9 -3
  163. package/corpus/templates/design/server/lib/coding-handoff.ts +126 -2
  164. package/corpus/templates/design/server/plugins/core-routes.ts +1 -2
  165. package/corpus/templates/design/server/routes/api/design-handoff/[id].zip.get.ts +86 -0
  166. package/corpus/templates/design/shared/code-layer.ts +125 -22
  167. package/corpus/templates/design/shared/generation-session.ts +41 -0
  168. package/corpus/templates/dispatch/app/global.css +79 -35
  169. package/corpus/templates/dispatch/app/routes/integrations.tsx +8 -7
  170. package/corpus/templates/dispatch/changelog/2026-06-29-integration-layouts-adapt-when-the-agent-sidebar-is-open.md +6 -0
  171. package/corpus/templates/forms/app/components/layout/Layout.tsx +6 -2
  172. package/corpus/templates/forms/app/global.css +64 -35
  173. package/corpus/templates/forms/app/pages/FormsListPage.tsx +2 -2
  174. package/corpus/templates/forms/app/pages/ResponseInsightsPage.tsx +3 -3
  175. package/corpus/templates/forms/changelog/2026-06-29-form-list-and-insight-layouts-adapt-when-the-agent-sidebar.md +6 -0
  176. package/corpus/templates/macros/app/components/layout/AppLayout.tsx +3 -1
  177. package/corpus/templates/macros/app/global.css +25 -9
  178. package/corpus/templates/macros/changelog/2026-06-29-macro-layouts-adapt-when-the-agent-sidebar-is-open.md +6 -0
  179. package/corpus/templates/mail/app/components/layout/AppLayout.tsx +6 -2
  180. package/corpus/templates/mail/app/global.css +42 -36
  181. package/corpus/templates/mail/app/pages/InboxPage.tsx +1 -1
  182. package/corpus/templates/mail/changelog/2026-06-29-the-contact-panel-now-adapts-to-the-available-mail-pane-width.md +6 -0
  183. package/corpus/templates/plan/app/components/layout/Layout.tsx +3 -1
  184. package/corpus/templates/plan/app/components/plan/DocumentArea.tsx +6 -7
  185. package/corpus/templates/plan/app/global.css +74 -42
  186. package/corpus/templates/plan/changelog/2026-06-29-plan-document-blocks-adapt-to-the-available-document-width.md +6 -0
  187. package/corpus/templates/plan/changelog/2026-06-29-plan-titles-and-summaries-can-be-edited-inline-without-focus.md +6 -0
  188. package/corpus/templates/slides/app/components/layout/Layout.tsx +3 -1
  189. package/corpus/templates/slides/app/global.css +49 -33
  190. package/corpus/templates/slides/changelog/2026-06-29-slide-layouts-adapt-when-the-agent-sidebar-is-open.md +6 -0
  191. package/corpus/templates/videos/app/components/layout/Layout.tsx +3 -1
  192. package/corpus/templates/videos/app/global.css +35 -35
  193. package/corpus/templates/videos/changelog/2026-06-29-video-layouts-adapt-when-the-agent-sidebar-is-open.md +6 -0
  194. package/dist/cli/mcp.d.ts.map +1 -1
  195. package/dist/cli/mcp.js +10 -0
  196. package/dist/cli/mcp.js.map +1 -1
  197. package/dist/cli/skills.d.ts.map +1 -1
  198. package/dist/cli/skills.js +58 -12
  199. package/dist/cli/skills.js.map +1 -1
  200. package/dist/client/error-format.d.ts.map +1 -1
  201. package/dist/client/error-format.js +17 -0
  202. package/dist/client/error-format.js.map +1 -1
  203. package/dist/client/extensions/ExtensionViewer.d.ts.map +1 -1
  204. package/dist/client/extensions/ExtensionViewer.js +3 -4
  205. package/dist/client/extensions/ExtensionViewer.js.map +1 -1
  206. package/dist/client/guided-questions.d.ts +4 -0
  207. package/dist/client/guided-questions.d.ts.map +1 -1
  208. package/dist/client/guided-questions.js +16 -7
  209. package/dist/client/guided-questions.js.map +1 -1
  210. package/dist/client/onboarding/OnboardingPanel.js +26 -1
  211. package/dist/client/onboarding/OnboardingPanel.js.map +1 -1
  212. package/dist/client/resources/BuiltinCapabilityDetail.d.ts.map +1 -1
  213. package/dist/client/resources/BuiltinCapabilityDetail.js +1 -1
  214. package/dist/client/resources/BuiltinCapabilityDetail.js.map +1 -1
  215. package/dist/client/resources/use-builtin-capabilities.d.ts +1 -1
  216. package/dist/client/resources/use-builtin-capabilities.d.ts.map +1 -1
  217. package/dist/client/resources/use-builtin-capabilities.js +2 -1
  218. package/dist/client/resources/use-builtin-capabilities.js.map +1 -1
  219. package/dist/client/session-replay.d.ts.map +1 -1
  220. package/dist/client/session-replay.js +31 -0
  221. package/dist/client/session-replay.js.map +1 -1
  222. package/dist/client/sharing/ShareButton.d.ts +14 -0
  223. package/dist/client/sharing/ShareButton.d.ts.map +1 -1
  224. package/dist/client/sharing/ShareButton.js +36 -7
  225. package/dist/client/sharing/ShareButton.js.map +1 -1
  226. package/dist/coding-tools/index.js +1 -1
  227. package/dist/coding-tools/index.js.map +1 -1
  228. package/dist/collab/routes.d.ts +1 -1
  229. package/dist/file-upload/actions/upload-image.d.ts +2 -2
  230. package/dist/mcp/index.d.ts +2 -0
  231. package/dist/mcp/index.d.ts.map +1 -1
  232. package/dist/mcp/index.js +1 -0
  233. package/dist/mcp/index.js.map +1 -1
  234. package/dist/mcp/screen-memory-stdio.d.ts +6 -0
  235. package/dist/mcp/screen-memory-stdio.d.ts.map +1 -0
  236. package/dist/mcp/screen-memory-stdio.js +213 -0
  237. package/dist/mcp/screen-memory-stdio.js.map +1 -0
  238. package/dist/mcp-client/builtin-capabilities.d.ts +1 -1
  239. package/dist/mcp-client/builtin-capabilities.d.ts.map +1 -1
  240. package/dist/mcp-client/builtin-capabilities.js +10 -0
  241. package/dist/mcp-client/builtin-capabilities.js.map +1 -1
  242. package/dist/mcp-client/index.d.ts +1 -0
  243. package/dist/mcp-client/index.d.ts.map +1 -1
  244. package/dist/mcp-client/index.js +1 -0
  245. package/dist/mcp-client/index.js.map +1 -1
  246. package/dist/mcp-client/screen-memory-local.d.ts +61 -0
  247. package/dist/mcp-client/screen-memory-local.d.ts.map +1 -0
  248. package/dist/mcp-client/screen-memory-local.js +336 -0
  249. package/dist/mcp-client/screen-memory-local.js.map +1 -0
  250. package/dist/notifications/routes.d.ts +2 -2
  251. package/dist/observability/routes.d.ts +8 -8
  252. package/dist/onboarding/types.d.ts +7 -0
  253. package/dist/onboarding/types.d.ts.map +1 -1
  254. package/dist/onboarding/types.js.map +1 -1
  255. package/dist/resources/handlers.d.ts +2 -2
  256. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  257. package/dist/server/agent-chat-plugin.js +26 -0
  258. package/dist/server/agent-chat-plugin.js.map +1 -1
  259. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  260. package/dist/server/agents-bundle.d.ts.map +1 -1
  261. package/dist/server/agents-bundle.js +22 -7
  262. package/dist/server/agents-bundle.js.map +1 -1
  263. package/dist/server/transcribe-voice.d.ts +1 -1
  264. package/dist/styles/agent-native.css +5 -0
  265. package/dist/templates/default/app/global.css +35 -35
  266. package/docs/content/locales/ar-SA/template-design.mdx +6 -0
  267. package/docs/content/locales/de-DE/template-design.mdx +8 -0
  268. package/docs/content/locales/es-ES/template-design.mdx +10 -2
  269. package/docs/content/locales/fr-FR/template-design.mdx +10 -2
  270. package/docs/content/locales/hi-IN/template-design.mdx +7 -0
  271. package/docs/content/locales/ja-JP/template-design.mdx +7 -0
  272. package/docs/content/locales/ko-KR/template-design.mdx +7 -0
  273. package/docs/content/locales/pt-BR/template-design.mdx +9 -2
  274. package/docs/content/locales/zh-CN/template-design.mdx +6 -0
  275. package/docs/content/locales/zh-TW/template-design.mdx +6 -0
  276. package/docs/content/template-design.mdx +9 -2
  277. package/package.json +1 -1
  278. package/src/templates/default/app/global.css +35 -35
  279. package/corpus/templates/design/app/components/design/VariantGrid.tsx +0 -189
  280. package/corpus/templates/design/app/components/design/VariantHandoffCard.tsx +0 -115
  281. package/corpus/templates/design/app/hooks/use-variant-flow.ts +0 -342
@@ -56,10 +56,20 @@ const sourceSchema = z.preprocess(
56
56
  }),
57
57
  );
58
58
 
59
- const targetSchema = z.object({
60
- nodeId: z.string().optional(),
61
- selector: z.string().optional(),
62
- });
59
+ const targetSchema = z
60
+ .object({
61
+ nodeId: z.string().optional(),
62
+ selector: z.string().optional(),
63
+ })
64
+ .superRefine((target, ctx) => {
65
+ if (!target.nodeId && !target.selector) {
66
+ ctx.addIssue({
67
+ code: z.ZodIssueCode.custom,
68
+ path: ["nodeId"],
69
+ message: "target.nodeId or target.selector is required",
70
+ });
71
+ }
72
+ });
63
73
 
64
74
  const intentSchema = z.preprocess(
65
75
  parseJsonString,
@@ -168,6 +178,16 @@ async function resolveEditableDesignFile(
168
178
  if (file.fileType !== "html") {
169
179
  throw new Error("Visual code-layer edits only support HTML files for now.");
170
180
  }
181
+ if (source.designId && file.designId !== source.designId) {
182
+ throw new Error(
183
+ `source.designId "${source.designId}" does not match file "${file.id}"`,
184
+ );
185
+ }
186
+ if (source.filename && file.filename !== source.filename) {
187
+ throw new Error(
188
+ `source.filename "${source.filename}" does not match file "${file.id}"`,
189
+ );
190
+ }
171
191
 
172
192
  await assertAccess("design", file.designId, "editor");
173
193
 
@@ -11,6 +11,7 @@ import { z } from "zod";
11
11
  import { schema } from "../server/db/index.js";
12
12
  import {
13
13
  buildCodingHandoffPrompt,
14
+ buildHandoffZipUrl,
14
15
  buildRawHandoffUrl,
15
16
  normalizeHandoffFormat,
16
17
  } from "../server/lib/coding-handoff.js";
@@ -30,9 +31,9 @@ function designDeepLink(designId: string): string {
30
31
 
31
32
  export default defineAction({
32
33
  description:
33
- "Turn a design into code: create a coding-tool handoff for a design " +
34
- "project. Returns a tokenized raw-code URL external agents can fetch, " +
35
- "plus a ready-to-copy prompt. The bundle reflects the design's CURRENT " +
34
+ "Turn a design into code: create an agent handoff for a design project. " +
35
+ "Returns tokenized raw and ZIP URLs external agents can fetch, plus a " +
36
+ "ready-to-copy prompt. The bundle reflects the design's CURRENT " +
36
37
  "state — live editor (collab) content plus the user's applied visual " +
37
38
  "tweaks resolved into the HTML :root — so the generated code matches the " +
38
39
  "tuned design, not the original generated tokens. This is the canonical " +
@@ -56,7 +57,7 @@ export default defineAction({
56
57
  mcpApp: {
57
58
  compactCatalog: true,
58
59
  resource: embedApp({
59
- title: "Design coding handoff",
60
+ title: "Design agent handoff",
60
61
  description: "Open the design in the real Design editor.",
61
62
  iframeTitle: "Agent-Native Design",
62
63
  openLabel: "Open design",
@@ -97,8 +98,14 @@ export default defineAction({
97
98
  origin: resolvedOrigin,
98
99
  format: handoffFormat,
99
100
  });
101
+ const zipUrl = buildHandoffZipUrl({
102
+ id,
103
+ token,
104
+ origin: resolvedOrigin,
105
+ });
100
106
  const prompt = buildCodingHandoffPrompt({
101
107
  rawUrl,
108
+ zipUrl,
102
109
  title: design.title,
103
110
  fileCount: snapshot.files.length,
104
111
  });
@@ -106,6 +113,7 @@ export default defineAction({
106
113
  return {
107
114
  designId: id,
108
115
  rawUrl,
116
+ zipUrl,
109
117
  prompt,
110
118
  clipboardText: prompt,
111
119
  format: handoffFormat,
@@ -1,6 +1,5 @@
1
1
  import { defineAction, embedApp } from "@agent-native/core";
2
2
  import {
3
- deleteAppState,
4
3
  readAppState,
5
4
  writeAppState,
6
5
  } from "@agent-native/core/application-state";
@@ -26,6 +25,7 @@ import {
26
25
  import {
27
26
  designGenerationSessionKey,
28
27
  type DesignGenerationSession,
28
+ updateGenerationSessionWithSavedFiles,
29
29
  } from "../shared/generation-session.js";
30
30
 
31
31
  /** Editor deep link so external agents can surface "Open design". */
@@ -57,28 +57,13 @@ async function updateGenerationSessionForSavedFiles(
57
57
  const session = rawSession as unknown as DesignGenerationSession;
58
58
  if (session.designId !== designId || !Array.isArray(session.frames)) return;
59
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,
60
+ const nextSession = updateGenerationSessionWithSavedFiles(
61
+ session,
62
+ savedFilenames,
70
63
  );
71
- const allDone = frames.every((frame) => frame.status === "done");
72
- if (allDone) {
73
- await deleteAppState(key);
74
- return;
75
- }
64
+ if (nextSession === session) return;
76
65
 
77
- await writeAppState(key, {
78
- ...session,
79
- status: "generating",
80
- frames,
81
- } as unknown as Record<string, unknown>);
66
+ await writeAppState(key, nextSession as unknown as Record<string, unknown>);
82
67
  }
83
68
 
84
69
  export default defineAction({
@@ -51,7 +51,7 @@ const requestedScreenSchema = z
51
51
  .optional()
52
52
  .describe("Target filename for this screen, such as onboarding.html"),
53
53
  role: z.enum(["screen", "variant"]).optional().default("screen"),
54
- variantOf: z.string().optional(),
54
+ variantOf: z.string().trim().min(1).optional(),
55
55
  })
56
56
  .superRefine((screen, ctx) => {
57
57
  if (screen.role === "variant" && !screen.variantOf) {
@@ -80,7 +80,48 @@ export default defineAction({
80
80
  screens: z
81
81
  .preprocess(
82
82
  (value) => (typeof value === "string" ? JSON.parse(value) : value),
83
- z.array(requestedScreenSchema).min(1).max(8),
83
+ z
84
+ .array(requestedScreenSchema)
85
+ .min(1)
86
+ .max(8)
87
+ .superRefine((screens, ctx) => {
88
+ const requestAnchors = new Map<
89
+ string,
90
+ { index: number; role: DesignGenerationFrame["role"] }
91
+ >();
92
+ screens.forEach((screen, index) => {
93
+ const anchors = [screen.frameId, screen.filename, screen.title];
94
+ for (const anchor of anchors) {
95
+ if (!anchor || requestAnchors.has(anchor)) continue;
96
+ requestAnchors.set(anchor, {
97
+ index,
98
+ role: screen.role,
99
+ });
100
+ }
101
+ });
102
+
103
+ screens.forEach((screen, index) => {
104
+ if (screen.role !== "variant" || !screen.variantOf) return;
105
+ const anchor = requestAnchors.get(screen.variantOf);
106
+ if (!anchor) return;
107
+ if (anchor.index === index) {
108
+ ctx.addIssue({
109
+ code: z.ZodIssueCode.custom,
110
+ path: [index, "variantOf"],
111
+ message: "variant screens cannot point to themselves",
112
+ });
113
+ return;
114
+ }
115
+ if (anchor.role === "variant") {
116
+ ctx.addIssue({
117
+ code: z.ZodIssueCode.custom,
118
+ path: [index, "variantOf"],
119
+ message:
120
+ "variant screens must anchor to a base screen, not another variant",
121
+ });
122
+ }
123
+ });
124
+ }),
84
125
  )
85
126
  .describe("Screens or variants that should be generated on the canvas"),
86
127
  designSystemId: z
@@ -14,6 +14,7 @@ export default defineAction({
14
14
  }),
15
15
  readOnly: true,
16
16
  requiresAuth: false,
17
+ publicAgent: { expose: true, readOnly: true, requiresAuth: false },
17
18
  http: { method: "GET" },
18
19
  run: async ({ id }) => {
19
20
  const access = await resolveAccess("design", id);
@@ -1,64 +1,245 @@
1
1
  import { defineAction, embedApp } from "@agent-native/core";
2
- import { writeAppState } from "@agent-native/core/application-state";
2
+ import {
3
+ deleteAppState,
4
+ writeAppState,
5
+ writeAppStateForCurrentTab,
6
+ } from "@agent-native/core/application-state";
7
+ import { seedFromText } from "@agent-native/core/collab";
3
8
  import { buildDeepLink } from "@agent-native/core/server";
4
9
  import { assertAccess } from "@agent-native/core/sharing";
10
+ import { eq } from "drizzle-orm";
11
+ import { nanoid } from "nanoid";
5
12
  import { z } from "zod";
6
13
 
7
14
  import "../server/db/index.js"; // ensure registerShareableResource runs
15
+ import { getDb, schema } from "../server/db/index.js";
16
+ import {
17
+ mergeCanvasFramePlacements,
18
+ type CanvasFramePlacement,
19
+ } from "../shared/canvas-frames.js";
20
+
21
+ const VARIANT_GAP = 96;
22
+ const MAX_COLUMNS = 3;
23
+ const MOBILE_WIDTH = 390;
24
+ const MOBILE_HEIGHT = 844;
25
+ const TABLET_WIDTH = 768;
26
+ const TABLET_HEIGHT = 1024;
27
+ const DESKTOP_WIDTH = 1280;
28
+ const DESKTOP_HEIGHT = 900;
8
29
 
9
30
  function designDeepLink(designId: string): string {
10
31
  return buildDeepLink({
11
32
  app: "design",
12
33
  view: "editor",
13
- params: { designId },
14
- // `handoff=chat` marks a link opened from a link-only host (CLI / Codex /
15
- // Claude Code) so the editor shows a copyable paste-back summary after the
16
- // user picks — the choice can't ride a host chat bridge there.
17
- to: `/design/${encodeURIComponent(designId)}?handoff=chat`,
34
+ params: { designId, editorView: "overview" },
35
+ to: `/design/${encodeURIComponent(designId)}?view=overview`,
18
36
  });
19
37
  }
20
38
 
21
39
  const FALLBACK_INSTRUCTIONS =
22
- "If the design opens as a browser link instead of inline, the user picks a " +
23
- "direction there and the editor shows a copyable summary. Ask them to paste " +
24
- "that summary back into chat so you can continue from the chosen direction. " +
25
- 'They can also just tell you which one in words (e.g. "use variant A" / "the ' +
26
- 'editorial one") — honor that too instead of insisting on the paste-back.';
40
+ "The generated directions have been saved as normal screens on the Design " +
41
+ "overview board. The chat shows one button per screen. Ask the user to pick " +
42
+ "a screen by name if the inline buttons are not available; after they pick, " +
43
+ "delete the other variant screens and continue from the kept screen.";
27
44
 
28
45
  const variantSchema = z.object({
29
46
  id: z.string().min(1).describe("Stable variant id, e.g. 'minimal-focus'"),
30
47
  label: z
31
48
  .string()
32
49
  .min(1)
33
- .describe("Short user-facing variant name, e.g. 'One-Line Focus'"),
50
+ .describe("Short user-facing screen name, e.g. 'One-Line Focus'"),
34
51
  content: z
35
52
  .string()
36
53
  .min(1)
37
54
  .describe(
38
- "Complete self-contained HTML document for this variant. Inline the CSS needed for the preview; avoid relying on external CSS/script CDNs because MCP app sandboxes may block them.",
55
+ "Complete self-contained HTML document for this variant. Inline the CSS needed for the preview; avoid relying on external CSS/script CDNs because app sandboxes may block them.",
56
+ ),
57
+ width: z
58
+ .number()
59
+ .positive()
60
+ .optional()
61
+ .describe(
62
+ "Optional source viewport/artboard width for the overview frame.",
63
+ ),
64
+ height: z
65
+ .number()
66
+ .positive()
67
+ .optional()
68
+ .describe(
69
+ "Optional source viewport/artboard height for the overview frame.",
39
70
  ),
40
71
  });
41
72
 
73
+ interface VariantScreen {
74
+ id: string;
75
+ variantId: string;
76
+ label: string;
77
+ filename: string;
78
+ width: number;
79
+ height: number;
80
+ }
81
+
82
+ function isRecord(value: unknown): value is Record<string, unknown> {
83
+ return Boolean(value && typeof value === "object" && !Array.isArray(value));
84
+ }
85
+
86
+ function parseJsonRecord(value: string | null | undefined) {
87
+ if (!value) return {};
88
+ try {
89
+ const parsed = JSON.parse(value);
90
+ return isRecord(parsed) ? parsed : {};
91
+ } catch {
92
+ return {};
93
+ }
94
+ }
95
+
96
+ function slugify(value: string, fallback: string) {
97
+ return (
98
+ value
99
+ .trim()
100
+ .toLowerCase()
101
+ .replace(/[^a-z0-9]+/g, "-")
102
+ .replace(/^-+|-+$/g, "")
103
+ .slice(0, 52) || fallback
104
+ );
105
+ }
106
+
107
+ function optionName(index: number) {
108
+ return `Option ${String.fromCharCode(65 + index)}`;
109
+ }
110
+
111
+ function uniqueFilename(preferred: string, used: Set<string>) {
112
+ const dot = preferred.lastIndexOf(".");
113
+ const stem = dot > 0 ? preferred.slice(0, dot) : preferred;
114
+ const ext = dot > 0 ? preferred.slice(dot) : ".html";
115
+ let candidate = `${stem}${ext}`;
116
+ let suffix = 2;
117
+ while (used.has(candidate)) {
118
+ candidate = `${stem}-${suffix}${ext}`;
119
+ suffix += 1;
120
+ }
121
+ used.add(candidate);
122
+ return candidate;
123
+ }
124
+
125
+ function firstCssPixelValue(content: string, property: string) {
126
+ const escaped = property.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
127
+ const pattern = new RegExp(`${escaped}\\s*:\\s*(\\d{2,4})px`, "i");
128
+ const match = content.match(pattern);
129
+ if (!match) return undefined;
130
+ const value = Number(match[1]);
131
+ return Number.isFinite(value) ? value : undefined;
132
+ }
133
+
134
+ function boundedDimension(value: unknown, min: number, max: number) {
135
+ return typeof value === "number" && Number.isFinite(value)
136
+ ? Math.min(max, Math.max(min, Math.round(value)))
137
+ : undefined;
138
+ }
139
+
140
+ function inferVariantSize(variant: z.infer<typeof variantSchema>) {
141
+ const explicitWidth = boundedDimension(variant.width, 240, 1920);
142
+ const explicitHeight = boundedDimension(variant.height, 240, 3000);
143
+ if (explicitWidth && explicitHeight) {
144
+ return { width: explicitWidth, height: explicitHeight };
145
+ }
146
+
147
+ const content = variant.content;
148
+ const cssWidth =
149
+ firstCssPixelValue(content, "width") ??
150
+ firstCssPixelValue(content, "max-width") ??
151
+ firstCssPixelValue(content, "min-width");
152
+ const cssHeight =
153
+ firstCssPixelValue(content, "height") ??
154
+ firstCssPixelValue(content, "min-height");
155
+ const inferredWidth = boundedDimension(cssWidth, 240, 1920);
156
+ const inferredHeight = boundedDimension(cssHeight, 240, 3000);
157
+ if (inferredWidth && inferredWidth <= 560) {
158
+ return {
159
+ width: explicitWidth ?? inferredWidth,
160
+ height: explicitHeight ?? inferredHeight ?? MOBILE_HEIGHT,
161
+ };
162
+ }
163
+ if (inferredWidth && inferredHeight) {
164
+ return {
165
+ width: explicitWidth ?? inferredWidth,
166
+ height: explicitHeight ?? inferredHeight,
167
+ };
168
+ }
169
+
170
+ const lowercase = content.toLowerCase();
171
+ if (
172
+ /\b(?:mobile|phone|iphone|android)\b/.test(lowercase) ||
173
+ /\b(?:max-w-sm|max-w-md|w-\[(?:360|375|390|393|414)px\])\b/.test(lowercase)
174
+ ) {
175
+ return {
176
+ width: explicitWidth ?? MOBILE_WIDTH,
177
+ height: explicitHeight ?? MOBILE_HEIGHT,
178
+ };
179
+ }
180
+ if (/\b(?:tablet|ipad)\b/.test(lowercase)) {
181
+ return {
182
+ width: explicitWidth ?? TABLET_WIDTH,
183
+ height: explicitHeight ?? TABLET_HEIGHT,
184
+ };
185
+ }
186
+
187
+ return {
188
+ width: explicitWidth ?? DESKTOP_WIDTH,
189
+ height: explicitHeight ?? DESKTOP_HEIGHT,
190
+ };
191
+ }
192
+
193
+ function placeVariantScreens(screens: VariantScreen[]) {
194
+ const placements: CanvasFramePlacement[] = [];
195
+ const columns = Math.min(MAX_COLUMNS, Math.max(1, screens.length));
196
+ let rowY = 0;
197
+
198
+ for (let rowStart = 0; rowStart < screens.length; rowStart += columns) {
199
+ const row = screens.slice(rowStart, rowStart + columns);
200
+ let x = 0;
201
+ let rowHeight = 0;
202
+
203
+ for (const [offset, screen] of row.entries()) {
204
+ placements.push({
205
+ fileId: screen.id,
206
+ filename: screen.filename,
207
+ x,
208
+ y: rowY,
209
+ width: screen.width,
210
+ height: screen.height,
211
+ z: rowStart + offset,
212
+ });
213
+ x += screen.width + VARIANT_GAP;
214
+ rowHeight = Math.max(rowHeight, screen.height);
215
+ }
216
+
217
+ rowY += rowHeight + VARIANT_GAP;
218
+ }
219
+
220
+ return placements;
221
+ }
222
+
42
223
  export default defineAction({
43
224
  description:
44
- "Present generated design directions in the Design editor so the user can " +
45
- "visually compare options and pick one. Provide 2-5 variants (3 is the " +
46
- "sweet spot). Use this for design exploration before calling " +
47
- "generate-design. The user's choice is persisted automatically by the app; " +
48
- "if it opens as a browser link, they paste a copyable summary back to chat " +
49
- 'or simply tell you which one (e.g. "use variant A").',
225
+ "Present generated design directions as normal screens on the Design " +
226
+ "overview board and ask the user to choose one with inline chat buttons. " +
227
+ "Provide 2-5 variants (3 is the sweet spot). Use this for design " +
228
+ "exploration before follow-up refinement. After the user's choice, keep " +
229
+ "the chosen screen, delete the other generated variant screens, and " +
230
+ "continue from the kept screen.",
50
231
  schema: z.object({
51
232
  designId: z.string().describe("Design project ID to show variants for"),
52
233
  prompt: z
53
234
  .string()
54
235
  .optional()
55
- .describe("Caption shown above the variant grid"),
236
+ .describe("Caption shown in chat above the variant choice buttons"),
56
237
  variants: z
57
238
  .array(variantSchema)
58
239
  .min(2)
59
240
  .max(5)
60
241
  .describe(
61
- "2-5 concise, visually distinct generated design options to preview side by side (3 is the sweet spot). Inline CSS so all options render in the MCP app preview.",
242
+ "2-5 concise, visually distinct generated design options to place as overview screens (3 is the sweet spot). Inline CSS so all options render in the app preview.",
62
243
  ),
63
244
  }),
64
245
  mcpApp: {
@@ -66,30 +247,174 @@ export default defineAction({
66
247
  resource: embedApp({
67
248
  title: "Design directions",
68
249
  description:
69
- "Open the Design editor with a visual picker for generated variants.",
250
+ "Open the Design editor with generated directions on the overview board.",
70
251
  iframeTitle: "Agent-Native Design",
71
- openLabel: "Open design directions",
252
+ openLabel: "Open screen overview",
72
253
  height: 720,
73
254
  }),
74
255
  },
75
256
  run: async ({ designId, prompt, variants }) => {
76
257
  await assertAccess("design", designId, "editor");
77
258
 
78
- await writeAppState("design-variants", {
259
+ const db = getDb();
260
+ const now = new Date().toISOString();
261
+ const [design] = await db
262
+ .select({ data: schema.designs.data })
263
+ .from(schema.designs)
264
+ .where(eq(schema.designs.id, designId))
265
+ .limit(1);
266
+ const existingFiles = await db
267
+ .select()
268
+ .from(schema.designFiles)
269
+ .where(eq(schema.designFiles.designId, designId));
270
+ const usedFilenames = new Set(existingFiles.map((file) => file.filename));
271
+ const variantSetId = nanoid();
272
+ const screens: VariantScreen[] = [];
273
+
274
+ for (let index = 0; index < variants.length; index += 1) {
275
+ const variant = variants[index]!;
276
+ const label = variant.label.trim() || optionName(index);
277
+ const slug = slugify(label, `option-${index + 1}`);
278
+ const preferredFilename = `variant-${slug}.html`;
279
+ const filename = uniqueFilename(preferredFilename, usedFilenames);
280
+ const fileId = nanoid();
281
+ const { width, height } = inferVariantSize(variant);
282
+
283
+ await db.insert(schema.designFiles).values({
284
+ id: fileId,
285
+ designId,
286
+ filename,
287
+ fileType: "html",
288
+ content: variant.content,
289
+ createdAt: now,
290
+ updatedAt: now,
291
+ });
292
+ await seedFromText(fileId, variant.content);
293
+
294
+ screens.push({
295
+ id: fileId,
296
+ variantId: variant.id,
297
+ label,
298
+ filename,
299
+ width,
300
+ height,
301
+ });
302
+ }
303
+
304
+ const placements = placeVariantScreens(screens);
305
+ await db.transaction(async (tx) => {
306
+ const [currentDesign] = await tx
307
+ .select({ data: schema.designs.data })
308
+ .from(schema.designs)
309
+ .where(eq(schema.designs.id, designId))
310
+ .limit(1);
311
+ const prevData = parseJsonRecord(currentDesign?.data ?? design?.data);
312
+ const mergedFrames = mergeCanvasFramePlacements({
313
+ existing: prevData.canvasFrames,
314
+ placements,
315
+ resolveFileId: (placement) => placement.fileId,
316
+ });
317
+ const previousMetadata = isRecord(prevData.screenMetadata)
318
+ ? { ...prevData.screenMetadata }
319
+ : {};
320
+ const previousVariantSets = isRecord(prevData.designVariantSets)
321
+ ? { ...prevData.designVariantSets }
322
+ : {};
323
+ for (const screen of screens) {
324
+ previousMetadata[screen.id] = {
325
+ sourceType: "inline",
326
+ previewState: "preview",
327
+ title: screen.label,
328
+ width: screen.width,
329
+ height: screen.height,
330
+ variantSetId,
331
+ variantId: screen.variantId,
332
+ };
333
+ }
334
+ previousVariantSets[variantSetId] = {
335
+ id: variantSetId,
336
+ prompt: prompt ?? "Pick a direction",
337
+ createdAt: now,
338
+ screens: screens.map((screen) => ({
339
+ id: screen.id,
340
+ variantId: screen.variantId,
341
+ label: screen.label,
342
+ filename: screen.filename,
343
+ width: screen.width,
344
+ height: screen.height,
345
+ })),
346
+ };
347
+
348
+ await tx
349
+ .update(schema.designs)
350
+ .set({
351
+ data: JSON.stringify({
352
+ ...prevData,
353
+ canvasFrames: mergedFrames.canvasFrames,
354
+ screenMetadata: previousMetadata,
355
+ designVariantSets: previousVariantSets,
356
+ updatedAt: now,
357
+ }),
358
+ updatedAt: now,
359
+ })
360
+ .where(eq(schema.designs.id, designId));
361
+ });
362
+
363
+ await writeAppState("navigate", {
364
+ view: "editor",
79
365
  designId,
80
- prompt: prompt ?? "Pick a direction",
81
- variants,
366
+ editorView: "overview",
367
+ path: `/design/${encodeURIComponent(designId)}?view=overview`,
368
+ });
369
+ await writeAppStateForCurrentTab("guided-questions", {
370
+ title: prompt ?? "Pick a direction",
371
+ description:
372
+ "All options are on the board. Choose the one to keep and I will continue from it.",
373
+ submitLabel: "Use selected direction",
374
+ submitMessage: "Use this design direction.",
375
+ skipLabel: "Show another set",
376
+ skipMessage: "None of these directions are right.",
377
+ questions: [
378
+ {
379
+ id: "variant",
380
+ type: "text-options",
381
+ question: "Which screen should I keep?",
382
+ required: true,
383
+ allowOther: false,
384
+ includeExplore: false,
385
+ includeDecide: false,
386
+ submitOnSelect: true,
387
+ options: screens.map((screen, index) => {
388
+ const otherScreens = screens
389
+ .filter((other) => other.id !== screen.id)
390
+ .map(
391
+ (other) =>
392
+ `${other.label} (${other.filename}, file id ${other.id})`,
393
+ )
394
+ .join("; ");
395
+ return {
396
+ label: screen.label || optionName(index),
397
+ value:
398
+ `Keep "${screen.label}" (${screen.filename}, file id ${screen.id}) ` +
399
+ `from variant set ${variantSetId}. Delete the other variant screens: ${otherScreens}.`,
400
+ };
401
+ }),
402
+ },
403
+ ],
82
404
  });
405
+ await deleteAppState("design-variants").catch(() => false);
83
406
 
84
407
  return {
85
408
  designId,
86
409
  prompt: prompt ?? "Pick a direction",
87
- count: variants.length,
88
- path: `/design/${encodeURIComponent(designId)}?handoff=chat`,
410
+ variantSetId,
411
+ count: screens.length,
412
+ screens,
413
+ path: `/design/${encodeURIComponent(designId)}?view=overview`,
89
414
  embed: true,
90
415
  fallbackInstructions: FALLBACK_INSTRUCTIONS,
91
416
  nextRequiredAction:
92
- "Wait for the user to pick a variant before refining or calling generate-design.",
417
+ "Wait for the user to pick a screen in chat. Then delete the unchosen variant screens with delete-file and continue from the chosen screen.",
93
418
  };
94
419
  },
95
420
  link: ({ result }) => {
@@ -98,7 +423,7 @@ export default defineAction({
98
423
  if (!designId) return null;
99
424
  return {
100
425
  url: designDeepLink(designId),
101
- label: "Open design directions",
426
+ label: "Open screen overview",
102
427
  view: "editor",
103
428
  };
104
429
  },