@agent-native/core 0.132.1 → 0.133.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 (456) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +198 -0
  3. package/corpus/core/package.json +1 -1
  4. package/corpus/core/src/a2a/correlation.ts +11 -1
  5. package/corpus/core/src/a2a/types.ts +11 -3
  6. package/corpus/core/src/agent/engine/ai-sdk-engine.ts +33 -46
  7. package/corpus/core/src/agent/engine/builder-engine.ts +22 -10
  8. package/corpus/core/src/agent/engine/error-detail.ts +184 -3
  9. package/corpus/core/src/agent/engine/failure-taxonomy.ts +123 -0
  10. package/corpus/core/src/agent/engine/index.ts +8 -0
  11. package/corpus/core/src/agent/engine/registry.ts +92 -8
  12. package/corpus/core/src/agent/engine/translate-ai-sdk.ts +17 -2
  13. package/corpus/core/src/agent/production-agent.ts +13 -33
  14. package/corpus/core/src/agent/run-loop-with-resume.ts +1 -1
  15. package/corpus/core/src/agent/run-manager.ts +43 -14
  16. package/corpus/core/src/agent/run-store.ts +30 -3
  17. package/corpus/core/src/agent/thread-data-builder.ts +36 -4
  18. package/corpus/core/src/chat-threads/store.ts +42 -0
  19. package/corpus/core/src/cli/templates-meta.ts +13 -0
  20. package/corpus/core/src/cli/workspace-dev.ts +1 -0
  21. package/corpus/core/src/client/error-format.ts +12 -0
  22. package/corpus/core/src/client/use-chat-threads.ts +76 -16
  23. package/corpus/core/src/credentials/index.ts +51 -12
  24. package/corpus/core/src/extensions/url-safety.ts +46 -12
  25. package/corpus/core/src/integrations/adapters/slack.ts +32 -10
  26. package/corpus/core/src/integrations/google-docs-poller.ts +12 -1
  27. package/corpus/core/src/integrations/installations-store.ts +30 -0
  28. package/corpus/core/src/integrations/plugin.ts +5 -5
  29. package/corpus/core/src/integrations/types.ts +7 -0
  30. package/corpus/core/src/integrations/webhook-handler.ts +24 -1
  31. package/corpus/core/src/jobs/background-automation-runner.ts +38 -1
  32. package/corpus/core/src/provider-api/index.ts +8 -2
  33. package/corpus/core/src/scripts/call-agent.ts +6 -0
  34. package/corpus/core/src/server/agent-chat-plugin.ts +46 -10
  35. package/corpus/core/src/server/agent-discovery.ts +2 -0
  36. package/corpus/core/src/server/builder-design-systems.ts +21 -0
  37. package/corpus/core/src/server/credential-provider.ts +51 -12
  38. package/corpus/core/src/server/index.ts +1 -0
  39. package/corpus/core/src/server/onboarding-html.ts +37 -2
  40. package/corpus/core/src/shared/reasoning-effort.ts +1 -1
  41. package/corpus/core/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +11 -0
  42. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +6 -2
  43. package/corpus/templates/assets/app/components/layout/Sidebar.tsx +39 -19
  44. package/corpus/templates/assets/changelog/2026-07-31-the-agent-native-logo-stays-visible-when-the-sidebar-is-coll.md +6 -0
  45. package/corpus/templates/brain/app/components/layout/Sidebar.tsx +30 -3
  46. package/corpus/templates/brain/changelog/2026-07-31-clicking-the-agent-native-logo-now-toggles-the-app-sidebar.md +6 -0
  47. package/corpus/templates/calendar/app/components/layout/AppLayout.tsx +1 -1
  48. package/corpus/templates/calendar/app/components/layout/Sidebar.tsx +54 -25
  49. package/corpus/templates/calendar/changelog/2026-07-31-the-agent-native-logo-stays-visible-when-the-sidebar-is-coll.md +6 -0
  50. package/corpus/templates/chat/app/components/layout/Sidebar.tsx +30 -3
  51. package/corpus/templates/chat/changelog/2026-07-31-clicking-the-agent-native-logo-now-toggles-the-app-sidebar.md +6 -0
  52. package/corpus/templates/clips/app/components/library/library-layout.tsx +37 -21
  53. package/corpus/templates/clips/changelog/2026-07-30-meeting-microphone-transcription-works-reliably-from-the-fir.md +6 -0
  54. package/corpus/templates/clips/changelog/2026-07-31-the-agent-native-logo-stays-visible-when-the-sidebar-is-coll.md +6 -0
  55. package/corpus/templates/clips/desktop/src/hooks/useMediaDevices.ts +1 -1
  56. package/corpus/templates/clips/desktop/src/lib/media-capture-constraints.ts +1 -1
  57. package/corpus/templates/clips/desktop/src-tauri/src/native_screen/custom_capture.rs +13 -0
  58. package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +2 -0
  59. package/corpus/templates/clips/desktop/src-tauri/src/system_audio.rs +25 -132
  60. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +34 -17
  61. package/corpus/templates/content/changelog/2026-07-31-the-agent-native-logo-stays-visible-when-the-sidebar-is-coll.md +6 -0
  62. package/corpus/templates/design/.agents/skills/design-systems/SKILL.md +6 -2
  63. package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +5 -0
  64. package/corpus/templates/design/actions/create-design-system.ts +1 -0
  65. package/corpus/templates/design/actions/set-default-design-system.ts +34 -26
  66. package/corpus/templates/design/app/components/design/KeyboardShortcutsPanel.tsx +5 -3
  67. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +23 -0
  68. package/corpus/templates/design/app/components/design/keyboard-shortcuts.ts +3 -0
  69. package/corpus/templates/design/app/components/layout/Sidebar.tsx +21 -4
  70. package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +11 -7
  71. package/corpus/templates/design/app/i18n-data.ts +39 -0
  72. package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +229 -12
  73. package/corpus/templates/design/app/pages/DesignSystems.tsx +10 -4
  74. package/corpus/templates/design/changelog/2026-07-30-fixed-the-keyboard-shortcuts-panel-not-opening-with-ctrl-shi.md +6 -0
  75. package/corpus/templates/design/changelog/2026-07-31-clicking-the-agent-native-logo-now-toggles-the-app-sidebar.md +6 -0
  76. package/corpus/templates/design/changelog/2026-07-31-design-system-indexing-keeps-your-chosen-name-when-you-uploa.md +6 -0
  77. package/corpus/templates/design/server/lib/builder-design-system-proxy.ts +19 -4
  78. package/corpus/templates/dispatch/AGENTS.md +4 -0
  79. package/corpus/templates/factory/.agents/skills/actions/SKILL.md +562 -0
  80. package/corpus/templates/factory/.agents/skills/adding-a-feature/SKILL.md +198 -0
  81. package/corpus/templates/factory/.agents/skills/agent-native-docs/SKILL.md +115 -0
  82. package/corpus/templates/factory/.agents/skills/agent-native-toolkit/SKILL.md +182 -0
  83. package/corpus/templates/factory/.agents/skills/capture-learnings/SKILL.md +89 -0
  84. package/corpus/templates/factory/.agents/skills/create-skill/SKILL.md +221 -0
  85. package/corpus/templates/factory/.agents/skills/customizing-agent-native/SKILL.md +220 -0
  86. package/corpus/templates/factory/.agents/skills/delegate-to-agent/SKILL.md +263 -0
  87. package/corpus/templates/factory/.agents/skills/factory-graphs/SKILL.md +52 -0
  88. package/corpus/templates/factory/.agents/skills/feature-flags/SKILL.md +169 -0
  89. package/corpus/templates/factory/.agents/skills/frontend-design/SKILL.md +174 -0
  90. package/corpus/templates/factory/.agents/skills/real-time-sync/SKILL.md +232 -0
  91. package/corpus/templates/factory/.agents/skills/security/SKILL.md +324 -0
  92. package/corpus/templates/factory/.agents/skills/self-modifying-code/SKILL.md +119 -0
  93. package/corpus/templates/factory/.agents/skills/shadcn-ui/SKILL.md +123 -0
  94. package/corpus/templates/factory/.agents/skills/sharing/SKILL.md +232 -0
  95. package/corpus/templates/factory/.agents/skills/storing-data/SKILL.md +178 -0
  96. package/corpus/templates/factory/.agents/skills/upgrade-agent-native/SKILL.md +122 -0
  97. package/corpus/templates/factory/.env.example +24 -0
  98. package/corpus/templates/factory/.ignore +0 -0
  99. package/corpus/templates/factory/.oxfmtrc.json +8 -0
  100. package/corpus/templates/factory/AGENTS.md +90 -0
  101. package/corpus/templates/factory/CHANGELOG.md +10 -0
  102. package/corpus/templates/factory/DEVELOPING.md +185 -0
  103. package/corpus/templates/factory/README.md +64 -0
  104. package/corpus/templates/factory/_gitignore +42 -0
  105. package/corpus/templates/factory/actions/add-factory-comment.ts +55 -0
  106. package/corpus/templates/factory/actions/approve-factory-item.ts +214 -0
  107. package/corpus/templates/factory/actions/babysit-pull-request.ts +126 -0
  108. package/corpus/templates/factory/actions/evaluate-triage-item.ts +172 -0
  109. package/corpus/templates/factory/actions/get-factory-graph.ts +62 -0
  110. package/corpus/templates/factory/actions/get-triage-config.ts +42 -0
  111. package/corpus/templates/factory/actions/get-triage-item.ts +74 -0
  112. package/corpus/templates/factory/actions/hello.ts +13 -0
  113. package/corpus/templates/factory/actions/ingest-github-observation.ts +100 -0
  114. package/corpus/templates/factory/actions/list-factories.ts +40 -0
  115. package/corpus/templates/factory/actions/list-factory-comments.ts +40 -0
  116. package/corpus/templates/factory/actions/list-triage-items.ts +85 -0
  117. package/corpus/templates/factory/actions/list-triage-rules.ts +44 -0
  118. package/corpus/templates/factory/actions/navigate.ts +41 -0
  119. package/corpus/templates/factory/actions/poll-slack-channel.ts +118 -0
  120. package/corpus/templates/factory/actions/reconcile-triage-run.ts +179 -0
  121. package/corpus/templates/factory/actions/record-triage-feedback.ts +58 -0
  122. package/corpus/templates/factory/actions/run.ts +2 -0
  123. package/corpus/templates/factory/actions/save-factory-graph.ts +129 -0
  124. package/corpus/templates/factory/actions/save-triage-config.ts +67 -0
  125. package/corpus/templates/factory/actions/save-triage-rule.ts +89 -0
  126. package/corpus/templates/factory/actions/suggest-factory-rules.ts +70 -0
  127. package/corpus/templates/factory/actions/view-screen.ts +73 -0
  128. package/corpus/templates/factory/app/components/factory/FactoryCanvas.tsx +441 -0
  129. package/corpus/templates/factory/app/components/factory/FactoryInspector.tsx +388 -0
  130. package/corpus/templates/factory/app/components/layout/Header.tsx +60 -0
  131. package/corpus/templates/factory/app/components/layout/Layout.tsx +190 -0
  132. package/corpus/templates/factory/app/components/layout/Sidebar.tsx +538 -0
  133. package/corpus/templates/factory/app/components/triage/triage-status-pill.tsx +28 -0
  134. package/corpus/templates/factory/app/components/ui/button.tsx +1 -0
  135. package/corpus/templates/factory/app/components/ui/card.tsx +1 -0
  136. package/corpus/templates/factory/app/components/ui/dropdown-menu.tsx +1 -0
  137. package/corpus/templates/factory/app/components/ui/input.tsx +1 -0
  138. package/corpus/templates/factory/app/components/ui/label.tsx +1 -0
  139. package/corpus/templates/factory/app/components/ui/sheet.tsx +1 -0
  140. package/corpus/templates/factory/app/components/ui/textarea.tsx +1 -0
  141. package/corpus/templates/factory/app/components/ui/toolkit-provider.tsx +17 -0
  142. package/corpus/templates/factory/app/components/ui/tooltip.tsx +1 -0
  143. package/corpus/templates/factory/app/design-system.ts +3 -0
  144. package/corpus/templates/factory/app/entry.client.tsx +22 -0
  145. package/corpus/templates/factory/app/entry.server.tsx +10 -0
  146. package/corpus/templates/factory/app/global.css +93 -0
  147. package/corpus/templates/factory/app/hooks/use-navigation-state.ts +113 -0
  148. package/corpus/templates/factory/app/i18n/en-US.ts +211 -0
  149. package/corpus/templates/factory/app/i18n/index.ts +34 -0
  150. package/corpus/templates/factory/app/i18n-data.ts +556 -0
  151. package/corpus/templates/factory/app/lib/agent-page.tsx +49 -0
  152. package/corpus/templates/factory/app/lib/app-config.ts +11 -0
  153. package/corpus/templates/factory/app/lib/tab-id.ts +1 -0
  154. package/corpus/templates/factory/app/lib/utils.ts +1 -0
  155. package/corpus/templates/factory/app/root.tsx +175 -0
  156. package/corpus/templates/factory/app/routes/_index.tsx +94 -0
  157. package/corpus/templates/factory/app/routes/agent.tsx +24 -0
  158. package/corpus/templates/factory/app/routes/chat.$threadId.tsx +1 -0
  159. package/corpus/templates/factory/app/routes/database.tsx +17 -0
  160. package/corpus/templates/factory/app/routes/extensions.$id.$slug.tsx +2 -0
  161. package/corpus/templates/factory/app/routes/extensions.$id.tsx +11 -0
  162. package/corpus/templates/factory/app/routes/extensions._index.tsx +11 -0
  163. package/corpus/templates/factory/app/routes/extensions.tsx +5 -0
  164. package/corpus/templates/factory/app/routes/factory.tsx +1003 -0
  165. package/corpus/templates/factory/app/routes/observability.tsx +19 -0
  166. package/corpus/templates/factory/app/routes/settings.tsx +89 -0
  167. package/corpus/templates/factory/app/routes/team.tsx +11 -0
  168. package/corpus/templates/factory/app/routes.ts +4 -0
  169. package/corpus/templates/factory/app/vite-env.d.ts +6 -0
  170. package/corpus/templates/factory/changelog/2026-06-24-a-new-settings-page-gives-quick-access-to-language-workspace.md +6 -0
  171. package/corpus/templates/factory/changelog/2026-06-24-added-a-language-picker-and-localized-app-chrome-for-support.md +6 -0
  172. package/corpus/templates/factory/changelog/2026-06-27-traditional-chinese-copy-uses-taiwan-terminology.md +6 -0
  173. package/corpus/templates/factory/changelog/2026-06-28-left-sidebar-collapse-motion-and-footer-chrome-are-quieter.md +6 -0
  174. package/corpus/templates/factory/changelog/2026-06-29-chat-layouts-adapt-when-the-agent-sidebar-is-open.md +6 -0
  175. package/corpus/templates/factory/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
  176. package/corpus/templates/factory/changelog/2026-07-10-chat-now-makes-ai-connection-setup-clear-without-shifting-th.md +6 -0
  177. package/corpus/templates/factory/changelog/2026-07-13-a-full-agent-page-now-brings-context-files-connections-jobs-.md +6 -0
  178. package/corpus/templates/factory/changelog/2026-07-14-chat-opens-reliably-on-hosted-deployments-instead-of-failing.md +6 -0
  179. package/corpus/templates/factory/changelog/2026-07-14-fixed-chat-template-startup-with-older-core-versions.md +6 -0
  180. package/corpus/templates/factory/changelog/2026-07-15-chat-navigation-focuses-on-chat-and-agent.md +6 -0
  181. package/corpus/templates/factory/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +6 -0
  182. package/corpus/templates/factory/changelog/2026-07-22-compact-sidebar-footer.md +6 -0
  183. package/corpus/templates/factory/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +6 -0
  184. package/corpus/templates/factory/changelog/2026-07-22-manage-agent-navigation-now-uses-the-connected-nodes-icon.md +6 -0
  185. package/corpus/templates/factory/changelog/2026-07-22-recent-chats-are-easier-to-scan-and-expand.md +6 -0
  186. package/corpus/templates/factory/changelog/2026-07-23-full-page-chat-is-better-centered-with-quieter-chat-history-.md +6 -0
  187. package/corpus/templates/factory/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  188. package/corpus/templates/factory/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  189. package/corpus/templates/factory/changelog/2026-07-25-settings-navigation-now-keeps-manage-agent-as-a-dedicated-li.md +6 -0
  190. package/corpus/templates/factory/changelog/2026-07-29-sidebar-footers-now-keep-feedback-search-and-collapse-togeth.md +6 -0
  191. package/corpus/templates/factory/changelog/2026-07-31-added-an-inspectable-observe-only-factory-queue-for-slack-.md +6 -0
  192. package/corpus/templates/factory/changelog/2026-07-31-clicking-the-agent-native-logo-now-toggles-the-app-sidebar.md +6 -0
  193. package/corpus/templates/factory/components.json +20 -0
  194. package/corpus/templates/factory/data/sync-config.json +1 -0
  195. package/corpus/templates/factory/learnings.defaults.md +5 -0
  196. package/corpus/templates/factory/netlify.toml +10 -0
  197. package/corpus/templates/factory/package.json +105 -0
  198. package/corpus/templates/factory/public/agent-native-icon-dark.svg +10 -0
  199. package/corpus/templates/factory/public/agent-native-icon-light.svg +10 -0
  200. package/corpus/templates/factory/public/agent-native-logo-dark.svg +21 -0
  201. package/corpus/templates/factory/public/agent-native-logo-light.svg +21 -0
  202. package/corpus/templates/factory/public/favicon.svg +1 -0
  203. package/corpus/templates/factory/public/icon-180.svg +1 -0
  204. package/corpus/templates/factory/public/icon-192.svg +1 -0
  205. package/corpus/templates/factory/public/icon-512.svg +1 -0
  206. package/corpus/templates/factory/public/manifest.json +21 -0
  207. package/corpus/templates/factory/react-router.config.ts +7 -0
  208. package/corpus/templates/factory/server/connectors/credentials.ts +129 -0
  209. package/corpus/templates/factory/server/connectors/slack.ts +129 -0
  210. package/corpus/templates/factory/server/db/index.ts +6 -0
  211. package/corpus/templates/factory/server/db/schema.ts +193 -0
  212. package/corpus/templates/factory/server/factory-graph/contracts.ts +212 -0
  213. package/corpus/templates/factory/server/factory-graph/store.ts +121 -0
  214. package/corpus/templates/factory/server/lib/require-workspace-member.ts +55 -0
  215. package/corpus/templates/factory/server/middleware/auth.ts +15 -0
  216. package/corpus/templates/factory/server/plugins/agent-chat.ts +58 -0
  217. package/corpus/templates/factory/server/plugins/auth.ts +14 -0
  218. package/corpus/templates/factory/server/plugins/factory-migrations.ts +247 -0
  219. package/corpus/templates/factory/server/plugins/factory-scheduler-job.ts +116 -0
  220. package/corpus/templates/factory/server/plugins/integrations.ts +46 -0
  221. package/corpus/templates/factory/server/routes/[...page].get.ts +5 -0
  222. package/corpus/templates/factory/server/routes/_agent-native/factory/builder-callback.post.ts +116 -0
  223. package/corpus/templates/factory/server/triage/ai-services-git.ts +197 -0
  224. package/corpus/templates/factory/server/triage/builder-executor.ts +118 -0
  225. package/corpus/templates/factory/server/triage/contracts.ts +164 -0
  226. package/corpus/templates/factory/server/triage/github-ingestion.ts +35 -0
  227. package/corpus/templates/factory/server/triage/guards.ts +121 -0
  228. package/corpus/templates/factory/server/triage/ids.ts +27 -0
  229. package/corpus/templates/factory/server/triage/pr-babysit.ts +100 -0
  230. package/corpus/templates/factory/server/triage/pr-monitor.ts +220 -0
  231. package/corpus/templates/factory/server/triage/slack-client.ts +55 -0
  232. package/corpus/templates/factory/server/triage/slack-poller.ts +152 -0
  233. package/corpus/templates/factory/ssr-entry.ts +15 -0
  234. package/corpus/templates/factory/tsconfig.json +21 -0
  235. package/corpus/templates/factory/vite.config.ts +19 -0
  236. package/corpus/templates/forms/app/components/layout/Sidebar.tsx +55 -5
  237. package/corpus/templates/forms/changelog/2026-07-31-the-agent-native-logo-stays-visible-when-the-sidebar-is-coll.md +6 -0
  238. package/corpus/templates/macros/app/components/layout/AppLayout.tsx +6 -2
  239. package/corpus/templates/plan/app/components/layout/Sidebar.tsx +21 -6
  240. package/corpus/templates/plan/changelog/2026-07-31-clicking-the-agent-native-logo-now-toggles-the-app-sidebar.md +6 -0
  241. package/corpus/templates/slides/.agents/skills/create-deck/SKILL.md +12 -0
  242. package/corpus/templates/slides/.agents/skills/design-systems/SKILL.md +9 -0
  243. package/corpus/templates/slides/.agents/skills/slide-editing/SKILL.md +11 -0
  244. package/corpus/templates/slides/AGENTS.md +5 -6
  245. package/corpus/templates/slides/actions/_await-fit-check.ts +20 -10
  246. package/corpus/templates/slides/actions/add-slide.ts +17 -4
  247. package/corpus/templates/slides/actions/create-design-system.ts +16 -4
  248. package/corpus/templates/slides/actions/delete-design-system.ts +18 -2
  249. package/corpus/templates/slides/actions/get-layout-overflows.ts +88 -0
  250. package/corpus/templates/slides/actions/import-file.ts +1 -0
  251. package/corpus/templates/slides/actions/index-design-system-with-builder.ts +8 -0
  252. package/corpus/templates/slides/actions/patch-deck.ts +48 -16
  253. package/corpus/templates/slides/actions/set-default-design-system.ts +49 -19
  254. package/corpus/templates/slides/actions/update-slide.ts +13 -3
  255. package/corpus/templates/slides/actions/view-screen.ts +87 -10
  256. package/corpus/templates/slides/app/components/deck/SlideRenderer.tsx +155 -28
  257. package/corpus/templates/slides/app/components/design-system/DesignSystemCard.tsx +21 -17
  258. package/corpus/templates/slides/app/components/design-system/DesignSystemSetup.tsx +849 -341
  259. package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +102 -2
  260. package/corpus/templates/slides/app/components/editor/PromptDialog.tsx +13 -16
  261. package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +60 -12
  262. package/corpus/templates/slides/app/components/editor/SlideOverflowWarning.tsx +11 -1
  263. package/corpus/templates/slides/app/components/layout/Sidebar.tsx +66 -19
  264. package/corpus/templates/slides/app/i18n/en-US.ts +23 -0
  265. package/corpus/templates/slides/app/lib/normalize-slide-padding.ts +8 -15
  266. package/corpus/templates/slides/app/pages/DeckEditor.tsx +4 -3
  267. package/corpus/templates/slides/app/pages/DesignSystems.tsx +4 -3
  268. package/corpus/templates/slides/app/pages/Index.tsx +1 -1
  269. package/corpus/templates/slides/changelog/2026-07-31-design-system-details-now-show-their-source-and-indexing-sta.md +6 -0
  270. package/corpus/templates/slides/changelog/2026-07-31-design-system-indexing-keeps-your-chosen-name-when-you-uploa.md +6 -0
  271. package/corpus/templates/slides/changelog/2026-07-31-design-system-setup-keeps-focus-rings-visible-and-uses-a-sim.md +6 -0
  272. package/corpus/templates/slides/changelog/2026-07-31-skip-prompt-is-now-available-in-the-new-deck-prompt-header.md +6 -0
  273. package/corpus/templates/slides/changelog/2026-07-31-slides-now-detect-real-text-and-box-overflow-across-the-deck.md +6 -0
  274. package/corpus/templates/slides/changelog/2026-07-31-the-agent-native-logo-stays-visible-when-the-sidebar-is-coll.md +6 -0
  275. package/corpus/templates/slides/server/handlers/design-systems.ts +1 -0
  276. package/corpus/templates/slides/server/handlers/index-design-system-sources.ts +1 -0
  277. package/corpus/templates/slides/server/lib/builder-design-system-proxy.ts +23 -4
  278. package/corpus/templates/slides/server/plugins/agent-chat.ts +5 -0
  279. package/corpus/templates/slides/server/plugins/creative-context.ts +16 -3
  280. package/corpus/templates/slides/server/workspace-defaults.ts +5 -1
  281. package/corpus/templates/slides/shared/slide-fit.ts +26 -0
  282. package/corpus/templates/tasks/app/components/layout/Sidebar.tsx +30 -3
  283. package/corpus/templates/tasks/changelog/2026-07-31-clicking-the-agent-native-logo-now-toggles-the-app-sidebar.md +6 -0
  284. package/dist/a2a/correlation.d.ts +4 -1
  285. package/dist/a2a/correlation.d.ts.map +1 -1
  286. package/dist/a2a/correlation.js +8 -1
  287. package/dist/a2a/correlation.js.map +1 -1
  288. package/dist/a2a/types.d.ts +11 -3
  289. package/dist/a2a/types.d.ts.map +1 -1
  290. package/dist/a2a/types.js.map +1 -1
  291. package/dist/agent/engine/ai-sdk-engine.d.ts.map +1 -1
  292. package/dist/agent/engine/ai-sdk-engine.js +27 -41
  293. package/dist/agent/engine/ai-sdk-engine.js.map +1 -1
  294. package/dist/agent/engine/builder-engine.d.ts.map +1 -1
  295. package/dist/agent/engine/builder-engine.js +18 -8
  296. package/dist/agent/engine/builder-engine.js.map +1 -1
  297. package/dist/agent/engine/error-detail.d.ts +61 -0
  298. package/dist/agent/engine/error-detail.d.ts.map +1 -1
  299. package/dist/agent/engine/error-detail.js +145 -3
  300. package/dist/agent/engine/error-detail.js.map +1 -1
  301. package/dist/agent/engine/failure-taxonomy.d.ts +24 -0
  302. package/dist/agent/engine/failure-taxonomy.d.ts.map +1 -0
  303. package/dist/agent/engine/failure-taxonomy.js +88 -0
  304. package/dist/agent/engine/failure-taxonomy.js.map +1 -0
  305. package/dist/agent/engine/index.d.ts +2 -1
  306. package/dist/agent/engine/index.d.ts.map +1 -1
  307. package/dist/agent/engine/index.js +2 -1
  308. package/dist/agent/engine/index.js.map +1 -1
  309. package/dist/agent/engine/registry.d.ts +16 -0
  310. package/dist/agent/engine/registry.d.ts.map +1 -1
  311. package/dist/agent/engine/registry.js +71 -6
  312. package/dist/agent/engine/registry.js.map +1 -1
  313. package/dist/agent/engine/translate-ai-sdk.d.ts.map +1 -1
  314. package/dist/agent/engine/translate-ai-sdk.js +14 -2
  315. package/dist/agent/engine/translate-ai-sdk.js.map +1 -1
  316. package/dist/agent/production-agent.d.ts.map +1 -1
  317. package/dist/agent/production-agent.js +13 -24
  318. package/dist/agent/production-agent.js.map +1 -1
  319. package/dist/agent/run-loop-with-resume.js +1 -1
  320. package/dist/agent/run-loop-with-resume.js.map +1 -1
  321. package/dist/agent/run-manager.d.ts.map +1 -1
  322. package/dist/agent/run-manager.js +39 -10
  323. package/dist/agent/run-manager.js.map +1 -1
  324. package/dist/agent/run-store.d.ts +10 -0
  325. package/dist/agent/run-store.d.ts.map +1 -1
  326. package/dist/agent/run-store.js +20 -3
  327. package/dist/agent/run-store.js.map +1 -1
  328. package/dist/agent/thread-data-builder.d.ts.map +1 -1
  329. package/dist/agent/thread-data-builder.js +28 -4
  330. package/dist/agent/thread-data-builder.js.map +1 -1
  331. package/dist/chat-threads/store.d.ts +13 -0
  332. package/dist/chat-threads/store.d.ts.map +1 -1
  333. package/dist/chat-threads/store.js +35 -0
  334. package/dist/chat-threads/store.js.map +1 -1
  335. package/dist/cli/templates-meta.d.ts.map +1 -1
  336. package/dist/cli/templates-meta.js +13 -0
  337. package/dist/cli/templates-meta.js.map +1 -1
  338. package/dist/cli/workspace-dev.d.ts.map +1 -1
  339. package/dist/cli/workspace-dev.js +1 -0
  340. package/dist/cli/workspace-dev.js.map +1 -1
  341. package/dist/client/error-format.d.ts.map +1 -1
  342. package/dist/client/error-format.js +10 -0
  343. package/dist/client/error-format.js.map +1 -1
  344. package/dist/client/use-chat-threads.d.ts.map +1 -1
  345. package/dist/client/use-chat-threads.js +66 -16
  346. package/dist/client/use-chat-threads.js.map +1 -1
  347. package/dist/collab/awareness.d.ts +2 -2
  348. package/dist/collab/awareness.d.ts.map +1 -1
  349. package/dist/collab/struct-routes.d.ts +1 -1
  350. package/dist/credentials/index.d.ts +9 -2
  351. package/dist/credentials/index.d.ts.map +1 -1
  352. package/dist/credentials/index.js +50 -8
  353. package/dist/credentials/index.js.map +1 -1
  354. package/dist/extensions/url-safety.d.ts.map +1 -1
  355. package/dist/extensions/url-safety.js +38 -12
  356. package/dist/extensions/url-safety.js.map +1 -1
  357. package/dist/integrations/adapters/slack.d.ts.map +1 -1
  358. package/dist/integrations/adapters/slack.js +25 -8
  359. package/dist/integrations/adapters/slack.js.map +1 -1
  360. package/dist/integrations/google-docs-poller.d.ts.map +1 -1
  361. package/dist/integrations/google-docs-poller.js +13 -1
  362. package/dist/integrations/google-docs-poller.js.map +1 -1
  363. package/dist/integrations/installations-store.d.ts +10 -0
  364. package/dist/integrations/installations-store.d.ts.map +1 -1
  365. package/dist/integrations/installations-store.js +24 -0
  366. package/dist/integrations/installations-store.js.map +1 -1
  367. package/dist/integrations/plugin.d.ts.map +1 -1
  368. package/dist/integrations/plugin.js +6 -5
  369. package/dist/integrations/plugin.js.map +1 -1
  370. package/dist/integrations/types.d.ts +7 -0
  371. package/dist/integrations/types.d.ts.map +1 -1
  372. package/dist/integrations/types.js.map +1 -1
  373. package/dist/integrations/webhook-handler.d.ts.map +1 -1
  374. package/dist/integrations/webhook-handler.js +16 -1
  375. package/dist/integrations/webhook-handler.js.map +1 -1
  376. package/dist/jobs/background-automation-runner.d.ts.map +1 -1
  377. package/dist/jobs/background-automation-runner.js +35 -2
  378. package/dist/jobs/background-automation-runner.js.map +1 -1
  379. package/dist/notifications/routes.d.ts +6 -6
  380. package/dist/observability/routes.d.ts +3 -3
  381. package/dist/provider-api/actions/custom-provider-registration.d.ts +14 -14
  382. package/dist/provider-api/actions/provider-api.d.ts +8 -8
  383. package/dist/provider-api/index.js +7 -3
  384. package/dist/provider-api/index.js.map +1 -1
  385. package/dist/scripts/call-agent.d.ts.map +1 -1
  386. package/dist/scripts/call-agent.js +6 -1
  387. package/dist/scripts/call-agent.js.map +1 -1
  388. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  389. package/dist/server/agent-chat-plugin.js +38 -9
  390. package/dist/server/agent-chat-plugin.js.map +1 -1
  391. package/dist/server/agent-discovery.d.ts +2 -0
  392. package/dist/server/agent-discovery.d.ts.map +1 -1
  393. package/dist/server/agent-discovery.js.map +1 -1
  394. package/dist/server/builder-design-systems.d.ts +4 -1
  395. package/dist/server/builder-design-systems.d.ts.map +1 -1
  396. package/dist/server/builder-design-systems.js +11 -1
  397. package/dist/server/builder-design-systems.js.map +1 -1
  398. package/dist/server/credential-provider.d.ts.map +1 -1
  399. package/dist/server/credential-provider.js +49 -12
  400. package/dist/server/credential-provider.js.map +1 -1
  401. package/dist/server/index.d.ts +1 -1
  402. package/dist/server/index.d.ts.map +1 -1
  403. package/dist/server/index.js.map +1 -1
  404. package/dist/server/onboarding-html.d.ts.map +1 -1
  405. package/dist/server/onboarding-html.js +37 -2
  406. package/dist/server/onboarding-html.js.map +1 -1
  407. package/dist/server/transcribe-voice.d.ts +1 -1
  408. package/dist/shared/reasoning-effort.d.ts +1 -0
  409. package/dist/shared/reasoning-effort.d.ts.map +1 -1
  410. package/dist/shared/reasoning-effort.js +1 -1
  411. package/dist/shared/reasoning-effort.js.map +1 -1
  412. package/dist/templates/chat/app/components/layout/Sidebar.tsx +30 -3
  413. package/dist/templates/chat/changelog/2026-07-31-clicking-the-agent-native-logo-now-toggles-the-app-sidebar.md +6 -0
  414. package/dist/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +11 -0
  415. package/package.json +1 -1
  416. package/src/a2a/correlation.ts +11 -1
  417. package/src/a2a/types.ts +11 -3
  418. package/src/agent/engine/ai-sdk-engine.ts +33 -46
  419. package/src/agent/engine/builder-engine.ts +22 -10
  420. package/src/agent/engine/error-detail.ts +184 -3
  421. package/src/agent/engine/failure-taxonomy.ts +123 -0
  422. package/src/agent/engine/index.ts +8 -0
  423. package/src/agent/engine/registry.ts +92 -8
  424. package/src/agent/engine/translate-ai-sdk.ts +17 -2
  425. package/src/agent/production-agent.ts +13 -33
  426. package/src/agent/run-loop-with-resume.ts +1 -1
  427. package/src/agent/run-manager.ts +43 -14
  428. package/src/agent/run-store.ts +30 -3
  429. package/src/agent/thread-data-builder.ts +36 -4
  430. package/src/chat-threads/store.ts +42 -0
  431. package/src/cli/templates-meta.ts +13 -0
  432. package/src/cli/workspace-dev.ts +1 -0
  433. package/src/client/error-format.ts +12 -0
  434. package/src/client/use-chat-threads.ts +76 -16
  435. package/src/credentials/index.ts +51 -12
  436. package/src/extensions/url-safety.ts +46 -12
  437. package/src/integrations/adapters/slack.ts +32 -10
  438. package/src/integrations/google-docs-poller.ts +12 -1
  439. package/src/integrations/installations-store.ts +30 -0
  440. package/src/integrations/plugin.ts +5 -5
  441. package/src/integrations/types.ts +7 -0
  442. package/src/integrations/webhook-handler.ts +24 -1
  443. package/src/jobs/background-automation-runner.ts +38 -1
  444. package/src/provider-api/index.ts +8 -2
  445. package/src/scripts/call-agent.ts +6 -0
  446. package/src/server/agent-chat-plugin.ts +46 -10
  447. package/src/server/agent-discovery.ts +2 -0
  448. package/src/server/builder-design-systems.ts +21 -0
  449. package/src/server/credential-provider.ts +51 -12
  450. package/src/server/index.ts +1 -0
  451. package/src/server/onboarding-html.ts +37 -2
  452. package/src/shared/reasoning-effort.ts +1 -1
  453. package/src/templates/chat/app/components/layout/Sidebar.tsx +30 -3
  454. package/src/templates/chat/changelog/2026-07-31-clicking-the-agent-native-logo-now-toggles-the-app-sidebar.md +6 -0
  455. package/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +11 -0
  456. package/corpus/templates/clips/desktop/src/lib/media-device-selection.ts +0 -157
@@ -18,6 +18,7 @@ import {
18
18
  IconPhoto,
19
19
  IconCheck,
20
20
  IconExternalLink,
21
+ IconChevronDown,
21
22
  } from "@tabler/icons-react";
22
23
  import { useState, useCallback, useEffect, useRef, useMemo } from "react";
23
24
  import { toast } from "sonner";
@@ -33,7 +34,9 @@ import {
33
34
  import { Input } from "@/components/ui/input";
34
35
  import { Label } from "@/components/ui/label";
35
36
  import { ScrollArea } from "@/components/ui/scroll-area";
37
+ import { Skeleton } from "@/components/ui/skeleton";
36
38
  import { Textarea } from "@/components/ui/textarea";
39
+ import { cn } from "@/lib/utils";
37
40
 
38
41
  import {
39
42
  uploadAndIndexFigmaFiles,
@@ -66,6 +69,30 @@ interface UploadedFile {
66
69
  textContent?: string;
67
70
  }
68
71
 
72
+ type BuilderSourceKind = "figma" | "code" | "github" | "mixed";
73
+
74
+ interface BuilderSourceDetails {
75
+ builderDesignSystemId: string;
76
+ builderJobId: string;
77
+ builderUrl?: string;
78
+ builderStatus?: string;
79
+ sourceKind?: BuilderSourceKind;
80
+ docs?: Array<unknown>;
81
+ tokenValues?: Record<string, string>;
82
+ docCount?: number;
83
+ warning?: string;
84
+ }
85
+
86
+ interface ExistingDesignSystem {
87
+ title?: string;
88
+ description?: string;
89
+ data?: string | null;
90
+ customInstructions?: string;
91
+ builder?: BuilderSourceDetails | null;
92
+ }
93
+
94
+ type OtherSource = "brand" | "code" | "files" | "existing" | "context";
95
+
69
96
  function normalizeWebsiteUrlInput(input: string): string | null {
70
97
  const trimmed = input.trim();
71
98
  if (!trimmed) return null;
@@ -120,6 +147,8 @@ export function DesignSystemSetup({
120
147
  const [builderIndexError, setBuilderIndexError] = useState<string | null>(
121
148
  null,
122
149
  );
150
+ const [sourcePanel, setSourcePanel] = useState<"figma" | "other">("figma");
151
+ const [otherSource, setOtherSource] = useState<OtherSource | null>(null);
123
152
  const [decodeStatus, setDecodeStatus] = useState<DecodeJobStatus | null>(
124
153
  null,
125
154
  );
@@ -183,14 +212,21 @@ export function DesignSystemSetup({
183
212
  const figInputRef = useRef<HTMLInputElement>(null);
184
213
  const updateSystemMutation = useActionMutation("update-design-system");
185
214
 
186
- const { data: existingDs } = useActionQuery<{
187
- title?: string;
188
- description?: string;
189
- data?: string | null;
190
- customInstructions?: string;
191
- }>("get-design-system", editingId ? { id: editingId } : undefined, {
192
- enabled: !!editingId && open,
193
- });
215
+ const {
216
+ data: existingDs,
217
+ isLoading: existingDsLoading,
218
+ isError: existingDsError,
219
+ } = useActionQuery<ExistingDesignSystem>(
220
+ "get-design-system",
221
+ editingId ? { id: editingId } : undefined,
222
+ {
223
+ enabled: !!editingId && open,
224
+ refetchInterval: (query) =>
225
+ query.state.data?.builder?.builderStatus === "in-progress"
226
+ ? 5_000
227
+ : false,
228
+ },
229
+ );
194
230
 
195
231
  const { data: designSystemsData } = useActionQuery<{
196
232
  designSystems: Array<{ id: string; title: string }>;
@@ -201,15 +237,27 @@ export function DesignSystemSetup({
201
237
 
202
238
  useEffect(() => {
203
239
  if (existingDs && editingId) {
240
+ const builder = existingDs.builder;
204
241
  setCompanyName(existingDs.title ?? "");
205
- setBrandNotes(existingDs.description ?? "");
206
- setCustomInstructions(existingDs.customInstructions ?? "");
207
- try {
208
- const parsed = existingDs.data ? JSON.parse(existingDs.data) : null;
209
- if (parsed?.notes) setBrandNotes(parsed.notes);
210
- } catch {
211
- // ignore
212
- }
242
+ const parsed = parseDesignSystemData(existingDs.data);
243
+ const generatedDescription = builder
244
+ ? `Builder indexed design system ${builder.builderDesignSystemId}`
245
+ : null;
246
+ setBrandNotes(
247
+ builder
248
+ ? existingDs.description !== generatedDescription
249
+ ? (existingDs.description ?? "")
250
+ : ""
251
+ : parsed.ok && typeof parsed.value.notes === "string"
252
+ ? parsed.value.notes
253
+ : (existingDs.description ?? ""),
254
+ );
255
+ setCustomInstructions(
256
+ builder &&
257
+ isGeneratedBuilderInstructions(existingDs.customInstructions, builder)
258
+ ? ""
259
+ : (existingDs.customInstructions ?? ""),
260
+ );
213
261
  }
214
262
  }, [existingDs, editingId]);
215
263
 
@@ -260,6 +308,11 @@ export function DesignSystemSetup({
260
308
  customInstructions,
261
309
  ]);
262
310
 
311
+ const selectOtherSource = useCallback((source: OtherSource) => {
312
+ setSourcePanel("other");
313
+ setOtherSource((current) => (current === source ? null : source));
314
+ }, []);
315
+
263
316
  const addWebsiteUrl = useCallback(() => {
264
317
  const url = normalizeWebsiteUrlInput(websiteUrl);
265
318
  if (!url) return;
@@ -340,7 +393,7 @@ export function DesignSystemSetup({
340
393
  .replace(/[-_]+/g, " ")
341
394
  .trim() || "Imported brand";
342
395
  const parsed = await uploadAndIndexFigmaFiles([file], {
343
- projectName: suggestedTitle,
396
+ projectName: companyName.trim() || suggestedTitle,
344
397
  });
345
398
  if (parsed.jobId) {
346
399
  startDecodePolling(parsed.jobId, parsed);
@@ -357,17 +410,17 @@ export function DesignSystemSetup({
357
410
  setBuilderIndexing(false);
358
411
  }
359
412
  },
360
- [t, startDecodePolling, stopDecodePolling],
413
+ [companyName, t, startDecodePolling, stopDecodePolling],
361
414
  );
362
415
 
363
416
  const handleEditSave = async () => {
364
- if (!editingId) return;
417
+ if (!editingId || !existingDs) return;
365
418
  setGenerating(true);
366
419
  try {
367
420
  await updateSystemMutation.mutateAsync({
368
421
  id: editingId,
369
422
  title: companyName || "My Brand",
370
- description: brandNotes || undefined,
423
+ description: brandNotes,
371
424
  customInstructions,
372
425
  });
373
426
  onComplete();
@@ -379,12 +432,31 @@ export function DesignSystemSetup({
379
432
  }
380
433
  };
381
434
 
382
- const handleGenerate = useCallback(() => {
435
+ const handleGenerate = useCallback(async () => {
383
436
  if (editingId) {
384
- handleEditSave();
437
+ await handleEditSave();
385
438
  return;
386
439
  }
387
440
 
441
+ const requestedTitle = companyName.trim();
442
+ const localDesignSystemId = builderIndexResult?.localDesignSystemId;
443
+ if (requestedTitle && localDesignSystemId) {
444
+ try {
445
+ await updateSystemMutation.mutateAsync({
446
+ id: localDesignSystemId,
447
+ title: requestedTitle,
448
+ });
449
+ } catch (error) {
450
+ toast.error(t("designSystemSetup.updateFailed"), {
451
+ description:
452
+ error instanceof Error
453
+ ? error.message
454
+ : t("designSystemSetup.updateFailed"),
455
+ });
456
+ return;
457
+ }
458
+ }
459
+
388
460
  // Cap inlined file content so a giant pasted README doesn't blow the
389
461
  // prompt budget. Append a marker so the agent doesn't treat the
390
462
  // truncation point as the end of the document.
@@ -400,7 +472,9 @@ export function DesignSystemSetup({
400
472
  );
401
473
 
402
474
  if (companyName.trim()) {
403
- parts.push(`\n## Company / Brand\n${companyName.trim()}`);
475
+ parts.push(
476
+ `\n## Company / Brand\n${companyName.trim()}\n\nUse exactly this as the design system name. Never replace it with the uploaded Figma filename.`,
477
+ );
404
478
  }
405
479
 
406
480
  if (websiteUrls.length > 0) {
@@ -528,14 +602,15 @@ export function DesignSystemSetup({
528
602
  customInstructions,
529
603
  onComplete,
530
604
  t,
605
+ updateSystemMutation,
606
+ existingDs,
531
607
  ]);
532
608
 
533
609
  return (
534
610
  <Dialog open={open} onOpenChange={(isOpen) => !isOpen && onClose()}>
535
611
  <DialogContent className="sm:max-w-2xl max-h-[85vh] p-0 bg-card border-border">
536
612
  <DialogHeader className="px-6 pt-6 pb-0">
537
- <DialogTitle className="text-foreground flex items-center gap-2">
538
- <IconPalette className="w-5 h-5 text-[#609FF8]" />
613
+ <DialogTitle className="text-foreground">
539
614
  {editingId
540
615
  ? t("designSystemSetup.editTitle")
541
616
  : t("designSystemSetup.newTitle")}
@@ -548,339 +623,511 @@ export function DesignSystemSetup({
548
623
  </DialogHeader>
549
624
 
550
625
  <ScrollArea className="max-h-[calc(85vh-160px)] px-6">
551
- <div className="space-y-5 py-4">
552
- {/* Company Name */}
553
- <div className="space-y-2">
554
- <Label className="text-foreground/80">
555
- {t("designSystemSetup.companyBrand")}
556
- </Label>
557
- <Input
558
- value={companyName}
559
- onChange={(e) => setCompanyName(e.target.value)}
560
- placeholder={t("designSystemSetup.companyBrandPlaceholder")}
561
- className="bg-accent border-border text-foreground placeholder:text-muted-foreground"
562
- />
563
- </div>
626
+ {editingId &&
627
+ (existingDsLoading || (!existingDs && !existingDsError)) ? (
628
+ <DesignSystemEditSkeleton />
629
+ ) : editingId && existingDsError ? (
630
+ <DesignSystemEditError />
631
+ ) : (
632
+ <div className="space-y-5 py-4">
633
+ {/* Company Name */}
634
+ <div className={cn("space-y-2", !editingId && "hidden")}>
635
+ <Label className="text-foreground/80">
636
+ {t("designSystemSetup.companyBrand")}
637
+ </Label>
638
+ <Input
639
+ value={companyName}
640
+ onChange={(e) => setCompanyName(e.target.value)}
641
+ placeholder={t("designSystemSetup.companyBrandPlaceholder")}
642
+ className="bg-accent border-border text-foreground placeholder:text-muted-foreground"
643
+ />
644
+ </div>
564
645
 
565
- {!editingId && (
566
- <>
567
- {/* Figma .fig */}
568
- <div className="space-y-2">
569
- <Label className="text-foreground/80 flex items-center gap-1.5">
570
- <IconBrandFigma className="w-3.5 h-3.5" />
571
- {t("designSystemSetup.figmaFile")}
572
- </Label>
573
- {!builderIndexResult ? (
574
- <>
575
- <button
576
- type="button"
577
- onClick={() => figInputRef.current?.click()}
578
- disabled={builderIndexing}
579
- className="w-full border border-dashed border-border rounded-lg p-4 text-center hover:border-foreground/20 cursor-pointer disabled:cursor-wait disabled:opacity-70"
580
- >
581
- {builderIndexing ? (
582
- <span className="inline-flex items-center gap-2 text-xs text-muted-foreground">
583
- <IconLoader2 className="w-3.5 h-3.5 animate-spin" />
584
- {t("designSystemSetup.parsingFigmaFile")}
585
- </span>
586
- ) : (
587
- <span className="text-xs text-muted-foreground">
588
- {t("designSystemSetup.uploadFigDescription")}
589
- </span>
646
+ {editingId && existingDs?.builder ? (
647
+ <BuilderSourceStatus builder={existingDs.builder} />
648
+ ) : null}
649
+
650
+ {!editingId && (
651
+ <>
652
+ <SourceAccordionRow
653
+ icon={IconBrandFigma}
654
+ title={t("designSystemSetup.figmaFile")}
655
+ description={t("designSystemSetup.uploadFigDescription")}
656
+ expanded={sourcePanel === "figma"}
657
+ onClick={() => setSourcePanel("figma")}
658
+ panelId="slides-design-system-figma-source"
659
+ />
660
+
661
+ {/* Figma .fig */}
662
+ <div
663
+ id="slides-design-system-figma-source"
664
+ className={cn(
665
+ "space-y-2 rounded-lg border border-border bg-card p-4",
666
+ sourcePanel !== "figma" && "hidden",
667
+ )}
668
+ >
669
+ <Label className="text-foreground/80 flex items-center gap-1.5">
670
+ <IconBrandFigma className="w-3.5 h-3.5" />
671
+ {t("designSystemSetup.figmaFile")}
672
+ </Label>
673
+ {!builderIndexResult ? (
674
+ <>
675
+ <button
676
+ type="button"
677
+ onClick={() => figInputRef.current?.click()}
678
+ disabled={builderIndexing}
679
+ className="w-full border border-dashed border-border rounded-lg p-4 text-center hover:border-foreground/20 cursor-pointer disabled:cursor-wait disabled:opacity-70"
680
+ >
681
+ {builderIndexing ? (
682
+ <span className="inline-flex items-center gap-2 text-xs text-muted-foreground">
683
+ <IconLoader2 className="w-3.5 h-3.5 animate-spin" />
684
+ {t("designSystemSetup.parsingFigmaFile")}
685
+ </span>
686
+ ) : (
687
+ <span className="text-xs text-muted-foreground">
688
+ {t("designSystemSetup.uploadFigDescription")}
689
+ </span>
690
+ )}
691
+ </button>
692
+ <input
693
+ ref={figInputRef}
694
+ type="file"
695
+ accept=".fig"
696
+ onChange={handleBuilderIndexUpload}
697
+ className="hidden"
698
+ />
699
+ {builderIndexError && (
700
+ <div
701
+ role="alert"
702
+ className="rounded-md border border-destructive/30 bg-destructive/10 px-3 py-2 text-sm text-destructive"
703
+ >
704
+ {builderIndexError}
705
+ </div>
706
+ )}
707
+ </>
708
+ ) : (
709
+ <BuilderIndexPreview
710
+ result={builderIndexResult}
711
+ decodeStatus={decodeStatus}
712
+ displayTitle={companyName.trim()}
713
+ onReset={() => {
714
+ stopDecodePolling();
715
+ setDecodeStatus(null);
716
+ setBuilderIndexResult(null);
717
+ setBuilderIndexError(null);
718
+ }}
719
+ />
720
+ )}
721
+ </div>
722
+
723
+ <SourceAccordionRow
724
+ icon={IconPalette}
725
+ title={t("designSystemSetup.otherSources")}
726
+ description={t("designSystemSetup.otherSourcesDescription")}
727
+ expanded={sourcePanel === "other"}
728
+ onClick={() => setSourcePanel("other")}
729
+ panelId="slides-design-system-other-sources"
730
+ />
731
+ {sourcePanel === "other" && (
732
+ <div
733
+ id="slides-design-system-other-sources"
734
+ className="rounded-lg border border-border"
735
+ >
736
+ <div className="border-b border-border px-4 py-3">
737
+ <p className="text-xs font-medium text-foreground/70">
738
+ {t("designSystemSetup.chooseSourcePrompt")}
739
+ </p>
740
+ </div>
741
+ <div className="divide-y divide-border">
742
+ <SourceAccordionRow
743
+ className="rounded-none border-0"
744
+ icon={IconPalette}
745
+ title={t("designSystemSetup.companyBrand")}
746
+ description={t(
747
+ "designSystemSetup.companyBrandPlaceholder",
748
+ )}
749
+ expanded={otherSource === "brand"}
750
+ onClick={() => selectOtherSource("brand")}
751
+ panelId="slides-design-system-brand-source"
752
+ />
753
+ <SourceAccordionRow
754
+ className="rounded-none border-0"
755
+ icon={IconBrandGithub}
756
+ title={t("designSystemSetup.githubRepository")}
757
+ description={t("designSystemSetup.codeFilesDrop")}
758
+ expanded={otherSource === "code"}
759
+ onClick={() => selectOtherSource("code")}
760
+ panelId="slides-design-system-code-source"
761
+ />
762
+ <SourceAccordionRow
763
+ className="rounded-none border-0"
764
+ icon={IconFileDescription}
765
+ title={t("designSystemSetup.documents")}
766
+ description={t("designSystemSetup.documentsDrop")}
767
+ expanded={otherSource === "files"}
768
+ onClick={() => selectOtherSource("files")}
769
+ panelId="slides-design-system-file-source"
770
+ />
771
+ {existingSystems.length > 0 && (
772
+ <SourceAccordionRow
773
+ className="rounded-none border-0"
774
+ icon={IconPalette}
775
+ title={t("designSystemSetup.forkExisting")}
776
+ description={t(
777
+ "designSystemSetup.customInstructionsDescription",
778
+ )}
779
+ expanded={otherSource === "existing"}
780
+ onClick={() => selectOtherSource("existing")}
781
+ panelId="slides-design-system-existing-source"
782
+ />
783
+ )}
784
+ <SourceAccordionRow
785
+ className="rounded-none border-0"
786
+ icon={IconFileDescription}
787
+ title={t("designSystemSetup.additionalNotes")}
788
+ description={t(
789
+ "designSystemSetup.customInstructionsDescription",
790
+ )}
791
+ expanded={otherSource === "context"}
792
+ onClick={() => selectOtherSource("context")}
793
+ panelId="slides-design-system-context-source"
794
+ />
795
+ </div>
796
+ </div>
797
+ )}
798
+
799
+ {/* Website URL */}
800
+ <div
801
+ id="slides-design-system-brand-source"
802
+ className={cn(
803
+ "space-y-4 rounded-lg border border-border bg-card p-4",
804
+ otherSource !== "brand" && "hidden",
805
+ )}
806
+ >
807
+ <div className="space-y-2">
808
+ <Label className="text-foreground/80">
809
+ {t("designSystemSetup.companyBrand")}
810
+ </Label>
811
+ <Input
812
+ value={companyName}
813
+ onChange={(e) => setCompanyName(e.target.value)}
814
+ placeholder={t(
815
+ "designSystemSetup.companyBrandPlaceholder",
590
816
  )}
591
- </button>
592
- <input
593
- ref={figInputRef}
594
- type="file"
595
- accept=".fig"
596
- onChange={handleBuilderIndexUpload}
597
- className="hidden"
817
+ className="bg-accent border-border text-foreground placeholder:text-muted-foreground"
598
818
  />
599
- {builderIndexError && (
600
- <div
601
- role="alert"
602
- className="rounded-md border border-destructive/30 bg-destructive/10 px-3 py-2 text-sm text-destructive"
819
+ </div>
820
+ <div className="space-y-2">
821
+ <Label className="text-foreground/80 flex items-center gap-1.5">
822
+ <IconWorld className="w-3.5 h-3.5" />
823
+ {t("designSystemSetup.websiteUrl")}
824
+ </Label>
825
+ <div className="flex gap-2">
826
+ <Input
827
+ value={websiteUrl}
828
+ onChange={(e) => setWebsiteUrl(e.target.value)}
829
+ placeholder={t(
830
+ "designSystemSetup.websitePlaceholder",
831
+ )}
832
+ className="bg-accent border-border text-foreground placeholder:text-muted-foreground"
833
+ onBlur={() => {
834
+ const normalized =
835
+ normalizeWebsiteUrlInput(websiteUrl);
836
+ if (normalized) setWebsiteUrl(normalized);
837
+ }}
838
+ onKeyDown={(e) => {
839
+ if (e.key === "Enter") addWebsiteUrl();
840
+ }}
841
+ />
842
+ <Button
843
+ variant="outline"
844
+ size="sm"
845
+ onClick={addWebsiteUrl}
846
+ className="shrink-0 cursor-pointer"
603
847
  >
604
- {builderIndexError}
605
- </div>
606
- )}
607
- </>
608
- ) : (
609
- <BuilderIndexPreview
610
- result={builderIndexResult}
611
- decodeStatus={decodeStatus}
612
- onReset={() => {
613
- stopDecodePolling();
614
- setDecodeStatus(null);
615
- setBuilderIndexResult(null);
616
- setBuilderIndexError(null);
617
- }}
848
+ {t("designSystemSetup.add")}
849
+ </Button>
850
+ </div>
851
+ <TagList
852
+ items={websiteUrls}
853
+ onRemove={(i) =>
854
+ setWebsiteUrls((p) => p.filter((_, j) => j !== i))
855
+ }
856
+ />
857
+ </div>
858
+ </div>
859
+
860
+ {/* GitHub */}
861
+ <div
862
+ id="slides-design-system-code-source"
863
+ className={cn(
864
+ "space-y-2 rounded-lg border border-border bg-card p-4",
865
+ otherSource !== "code" && "hidden",
866
+ )}
867
+ >
868
+ <Label className="text-foreground/80 flex items-center gap-1.5">
869
+ <IconBrandGithub className="w-3.5 h-3.5" />
870
+ {t("designSystemSetup.githubRepository")}
871
+ </Label>
872
+ <div className="flex gap-2">
873
+ <Input
874
+ value={githubUrl}
875
+ onChange={(e) => setGithubUrl(e.target.value)}
876
+ placeholder="https://github.com/org/repo"
877
+ className="bg-accent border-border text-foreground placeholder:text-muted-foreground"
878
+ onKeyDown={(e) => {
879
+ if (e.key === "Enter") addGithubLink();
880
+ }}
881
+ />
882
+ <Button
883
+ variant="outline"
884
+ size="sm"
885
+ onClick={addGithubLink}
886
+ className="shrink-0 cursor-pointer"
887
+ >
888
+ {t("designSystemSetup.add")}
889
+ </Button>
890
+ </div>
891
+ <TagList
892
+ items={githubLinks.map((l) => l.url)}
893
+ onRemove={(i) =>
894
+ setGithubLinks((p) => p.filter((_, j) => j !== i))
895
+ }
618
896
  />
619
- )}
620
- </div>
621
-
622
- {/* Website URL */}
623
- <div className="space-y-2">
624
- <Label className="text-foreground/80 flex items-center gap-1.5">
625
- <IconWorld className="w-3.5 h-3.5" />
626
- {t("designSystemSetup.websiteUrl")}
627
- </Label>
628
- <div className="flex gap-2">
629
- <Input
630
- value={websiteUrl}
631
- onChange={(e) => setWebsiteUrl(e.target.value)}
632
- placeholder={t("designSystemSetup.websitePlaceholder")}
633
- className="bg-accent border-border text-foreground placeholder:text-muted-foreground"
634
- onBlur={() => {
635
- const normalized = normalizeWebsiteUrlInput(websiteUrl);
636
- if (normalized) setWebsiteUrl(normalized);
897
+ </div>
898
+
899
+ {/* Code Files */}
900
+ <div
901
+ className={cn(
902
+ "space-y-2 rounded-lg border border-border bg-card p-4",
903
+ otherSource !== "code" && "hidden",
904
+ )}
905
+ >
906
+ <Label className="text-foreground/80 flex items-center gap-1.5">
907
+ <IconFolder className="w-3.5 h-3.5" />
908
+ {t("designSystemSetup.codeFiles")}
909
+ </Label>
910
+ <button
911
+ onClick={() => codeInputRef.current?.click()}
912
+ onDrop={(e) => {
913
+ e.preventDefault();
914
+ if (e.dataTransfer.files)
915
+ readTextFiles(e.dataTransfer.files, setCodeFiles);
637
916
  }}
638
- onKeyDown={(e) => {
639
- if (e.key === "Enter") addWebsiteUrl();
917
+ onDragOver={(e) => e.preventDefault()}
918
+ className="w-full border border-dashed border-border rounded-lg p-4 text-center hover:border-foreground/20 cursor-pointer"
919
+ >
920
+ <p className="text-xs text-muted-foreground">
921
+ {t("designSystemSetup.codeFilesDrop")}
922
+ </p>
923
+ </button>
924
+ <input
925
+ ref={codeInputRef}
926
+ type="file"
927
+ multiple
928
+ accept=".css,.scss,.sass,.less,.ts,.tsx,.js,.jsx,.json,.html,.svg,.xml,.md,.markdown,.mdx,.txt"
929
+ onChange={(e) => {
930
+ if (e.target.files)
931
+ readTextFiles(e.target.files, setCodeFiles);
932
+ e.target.value = "";
640
933
  }}
934
+ className="hidden"
935
+ />
936
+ <FileList
937
+ files={codeFiles}
938
+ onRemove={(id) =>
939
+ setCodeFiles((p) => p.filter((f) => f.id !== id))
940
+ }
641
941
  />
642
- <Button
643
- variant="outline"
644
- size="sm"
645
- onClick={addWebsiteUrl}
646
- className="shrink-0 cursor-pointer"
647
- >
648
- {t("designSystemSetup.add")}
649
- </Button>
650
942
  </div>
651
- <TagList
652
- items={websiteUrls}
653
- onRemove={(i) =>
654
- setWebsiteUrls((p) => p.filter((_, j) => j !== i))
655
- }
656
- />
657
- </div>
658
-
659
- {/* GitHub */}
660
- <div className="space-y-2">
661
- <Label className="text-foreground/80 flex items-center gap-1.5">
662
- <IconBrandGithub className="w-3.5 h-3.5" />
663
- {t("designSystemSetup.githubRepository")}
664
- </Label>
665
- <div className="flex gap-2">
666
- <Input
667
- value={githubUrl}
668
- onChange={(e) => setGithubUrl(e.target.value)}
669
- placeholder="https://github.com/org/repo"
670
- className="bg-accent border-border text-foreground placeholder:text-muted-foreground"
671
- onKeyDown={(e) => {
672
- if (e.key === "Enter") addGithubLink();
943
+
944
+ {/* Documents */}
945
+ <div
946
+ id="slides-design-system-file-source"
947
+ className={cn(
948
+ "space-y-2 rounded-lg border border-border bg-card p-4",
949
+ otherSource !== "files" && "hidden",
950
+ )}
951
+ >
952
+ <Label className="text-foreground/80 flex items-center gap-1.5">
953
+ <IconFileDescription className="w-3.5 h-3.5" />
954
+ {t("designSystemSetup.documents")}
955
+ </Label>
956
+ <button
957
+ onClick={() => docInputRef.current?.click()}
958
+ onDrop={(e) => {
959
+ e.preventDefault();
960
+ if (e.dataTransfer.files)
961
+ readTextFiles(e.dataTransfer.files, setDocFiles);
673
962
  }}
674
- />
675
- <Button
676
- variant="outline"
677
- size="sm"
678
- onClick={addGithubLink}
679
- className="shrink-0 cursor-pointer"
963
+ onDragOver={(e) => e.preventDefault()}
964
+ className="w-full border border-dashed border-border rounded-lg p-4 text-center hover:border-foreground/20 cursor-pointer"
680
965
  >
681
- {t("designSystemSetup.add")}
682
- </Button>
966
+ <p className="text-xs text-muted-foreground">
967
+ {t("designSystemSetup.documentsDrop")}
968
+ </p>
969
+ </button>
970
+ <input
971
+ ref={docInputRef}
972
+ type="file"
973
+ accept=".pptx,.ppt,.docx,.doc,.pdf,.xlsx,.xls,.md,.markdown,.mdx,.txt"
974
+ multiple
975
+ onChange={(e) => {
976
+ if (e.target.files)
977
+ readTextFiles(e.target.files, setDocFiles);
978
+ e.target.value = "";
979
+ }}
980
+ className="hidden"
981
+ />
982
+ <FileList
983
+ files={docFiles}
984
+ onRemove={(id) =>
985
+ setDocFiles((p) => p.filter((f) => f.id !== id))
986
+ }
987
+ />
683
988
  </div>
684
- <TagList
685
- items={githubLinks.map((l) => l.url)}
686
- onRemove={(i) =>
687
- setGithubLinks((p) => p.filter((_, j) => j !== i))
688
- }
689
- />
690
- </div>
691
-
692
- {/* Code Files */}
693
- <div className="space-y-2">
694
- <Label className="text-foreground/80 flex items-center gap-1.5">
695
- <IconFolder className="w-3.5 h-3.5" />
696
- {t("designSystemSetup.codeFiles")}
697
- </Label>
698
- <button
699
- onClick={() => codeInputRef.current?.click()}
700
- onDrop={(e) => {
701
- e.preventDefault();
702
- if (e.dataTransfer.files)
703
- readTextFiles(e.dataTransfer.files, setCodeFiles);
704
- }}
705
- onDragOver={(e) => e.preventDefault()}
706
- className="w-full border border-dashed border-border rounded-lg p-4 text-center hover:border-foreground/20 cursor-pointer"
707
- >
708
- <p className="text-xs text-muted-foreground">
709
- {t("designSystemSetup.codeFilesDrop")}
710
- </p>
711
- </button>
712
- <input
713
- ref={codeInputRef}
714
- type="file"
715
- multiple
716
- accept=".css,.scss,.sass,.less,.ts,.tsx,.js,.jsx,.json,.html,.svg,.xml,.md,.markdown,.mdx,.txt"
717
- onChange={(e) => {
718
- if (e.target.files)
719
- readTextFiles(e.target.files, setCodeFiles);
720
- e.target.value = "";
721
- }}
722
- className="hidden"
723
- />
724
- <FileList
725
- files={codeFiles}
726
- onRemove={(id) =>
727
- setCodeFiles((p) => p.filter((f) => f.id !== id))
728
- }
729
- />
730
- </div>
731
-
732
- {/* Documents */}
733
- <div className="space-y-2">
734
- <Label className="text-foreground/80 flex items-center gap-1.5">
735
- <IconFileDescription className="w-3.5 h-3.5" />
736
- {t("designSystemSetup.documents")}
737
- </Label>
738
- <button
739
- onClick={() => docInputRef.current?.click()}
740
- onDrop={(e) => {
741
- e.preventDefault();
742
- if (e.dataTransfer.files)
743
- readTextFiles(e.dataTransfer.files, setDocFiles);
744
- }}
745
- onDragOver={(e) => e.preventDefault()}
746
- className="w-full border border-dashed border-border rounded-lg p-4 text-center hover:border-foreground/20 cursor-pointer"
747
- >
748
- <p className="text-xs text-muted-foreground">
749
- {t("designSystemSetup.documentsDrop")}
750
- </p>
751
- </button>
752
- <input
753
- ref={docInputRef}
754
- type="file"
755
- accept=".pptx,.ppt,.docx,.doc,.pdf,.xlsx,.xls,.md,.markdown,.mdx,.txt"
756
- multiple
757
- onChange={(e) => {
758
- if (e.target.files)
759
- readTextFiles(e.target.files, setDocFiles);
760
- e.target.value = "";
761
- }}
762
- className="hidden"
763
- />
764
- <FileList
765
- files={docFiles}
766
- onRemove={(id) =>
767
- setDocFiles((p) => p.filter((f) => f.id !== id))
768
- }
769
- />
770
- </div>
771
-
772
- {/* Images */}
773
- <div className="space-y-2">
774
- <Label className="text-foreground/80 flex items-center gap-1.5">
775
- <IconPhoto className="w-3.5 h-3.5" />
776
- {t("designSystemSetup.visualReferences")}
777
- </Label>
778
- <button
779
- onClick={() => imageInputRef.current?.click()}
780
- className="w-full border border-dashed border-border rounded-lg p-4 text-center hover:border-foreground/20 cursor-pointer"
781
- >
782
- <p className="text-xs text-muted-foreground">
783
- {t("designSystemSetup.visualReferencesDrop")}
784
- </p>
785
- </button>
786
- <input
787
- ref={imageInputRef}
788
- type="file"
789
- accept="image/*,.svg"
790
- multiple
791
- onChange={(e) => {
792
- if (!e.target.files) return;
793
- const newFiles = Array.from(e.target.files).map((f) => ({
794
- id: crypto.randomUUID(),
795
- name: f.name,
796
- type: f.type,
797
- size: f.size,
798
- }));
799
- setImageFiles((p) => [...p, ...newFiles]);
800
- e.target.value = "";
801
- }}
802
- className="hidden"
803
- />
804
- <FileList
805
- files={imageFiles}
806
- onRemove={(id) =>
807
- setImageFiles((p) => p.filter((f) => f.id !== id))
808
- }
809
- />
810
- </div>
811
989
 
812
- {/* Fork existing */}
813
- {existingSystems.length > 0 && (
814
- <div className="space-y-2">
815
- <Label className="text-foreground/80">
816
- {t("designSystemSetup.forkExisting")}
990
+ {/* Images */}
991
+ <div
992
+ className={cn(
993
+ "space-y-2 rounded-lg border border-border bg-card p-4",
994
+ otherSource !== "files" && "hidden",
995
+ )}
996
+ >
997
+ <Label className="text-foreground/80 flex items-center gap-1.5">
998
+ <IconPhoto className="w-3.5 h-3.5" />
999
+ {t("designSystemSetup.visualReferences")}
817
1000
  </Label>
818
- <div className="grid grid-cols-2 gap-2">
819
- {existingSystems
820
- .filter((s) => s.id !== editingId)
821
- .map((ds) => (
822
- <button
823
- key={ds.id}
824
- onClick={() =>
825
- setSelectedSystemId((prev) =>
826
- prev === ds.id ? "" : ds.id,
827
- )
828
- }
829
- className={`text-left p-3 rounded-lg border cursor-pointer ${
830
- selectedSystemId === ds.id
831
- ? "border-[#609FF8]/40 bg-[#609FF8]/5"
832
- : "border-border bg-accent hover:border-foreground/20"
833
- }`}
834
- >
835
- <div className="flex items-center gap-2">
836
- <IconPalette className="w-3.5 h-3.5 text-muted-foreground" />
837
- <span className="text-sm text-foreground/80 truncate">
838
- {ds.title}
839
- </span>
840
- </div>
841
- </button>
842
- ))}
843
- </div>
1001
+ <button
1002
+ onClick={() => imageInputRef.current?.click()}
1003
+ className="w-full border border-dashed border-border rounded-lg p-4 text-center hover:border-foreground/20 cursor-pointer"
1004
+ >
1005
+ <p className="text-xs text-muted-foreground">
1006
+ {t("designSystemSetup.visualReferencesDrop")}
1007
+ </p>
1008
+ </button>
1009
+ <input
1010
+ ref={imageInputRef}
1011
+ type="file"
1012
+ accept="image/*,.svg"
1013
+ multiple
1014
+ onChange={(e) => {
1015
+ if (!e.target.files) return;
1016
+ const newFiles = Array.from(e.target.files).map(
1017
+ (f) => ({
1018
+ id: crypto.randomUUID(),
1019
+ name: f.name,
1020
+ type: f.type,
1021
+ size: f.size,
1022
+ }),
1023
+ );
1024
+ setImageFiles((p) => [...p, ...newFiles]);
1025
+ e.target.value = "";
1026
+ }}
1027
+ className="hidden"
1028
+ />
1029
+ <FileList
1030
+ files={imageFiles}
1031
+ onRemove={(id) =>
1032
+ setImageFiles((p) => p.filter((f) => f.id !== id))
1033
+ }
1034
+ />
844
1035
  </div>
845
- )}
846
- </>
847
- )}
848
1036
 
849
- {/* Brand Notes */}
850
- <div className="space-y-2">
851
- <Label className="text-foreground/80">
852
- {editingId
853
- ? t("designSystemSetup.brandNotes")
854
- : t("designSystemSetup.additionalNotes")}
855
- </Label>
856
- <Textarea
857
- value={brandNotes}
858
- onChange={(e) => setBrandNotes(e.target.value)}
859
- placeholder={t("designSystemSetup.notesPlaceholder")}
860
- rows={3}
861
- className="bg-accent border-border text-foreground placeholder:text-muted-foreground resize-none"
862
- />
863
- </div>
1037
+ {/* Fork existing */}
1038
+ {existingSystems.length > 0 && (
1039
+ <div
1040
+ id="slides-design-system-existing-source"
1041
+ className={cn(
1042
+ "space-y-2 rounded-lg border border-border bg-card p-4",
1043
+ otherSource !== "existing" && "hidden",
1044
+ )}
1045
+ >
1046
+ <Label className="text-foreground/80">
1047
+ {t("designSystemSetup.forkExisting")}
1048
+ </Label>
1049
+ <div className="grid grid-cols-2 gap-2">
1050
+ {existingSystems
1051
+ .filter((s) => s.id !== editingId)
1052
+ .map((ds) => (
1053
+ <button
1054
+ key={ds.id}
1055
+ onClick={() =>
1056
+ setSelectedSystemId((prev) =>
1057
+ prev === ds.id ? "" : ds.id,
1058
+ )
1059
+ }
1060
+ className={`text-left p-3 rounded-lg border cursor-pointer ${
1061
+ selectedSystemId === ds.id
1062
+ ? "border-primary/40 bg-primary/5"
1063
+ : "border-border bg-accent hover:border-foreground/20"
1064
+ }`}
1065
+ >
1066
+ <div className="flex items-center gap-2">
1067
+ <IconPalette className="w-3.5 h-3.5 text-muted-foreground" />
1068
+ <span className="text-sm text-foreground/80 truncate">
1069
+ {ds.title}
1070
+ </span>
1071
+ </div>
1072
+ </button>
1073
+ ))}
1074
+ </div>
1075
+ </div>
1076
+ )}
1077
+ </>
1078
+ )}
1079
+
1080
+ {/* Brand Notes */}
1081
+ <div
1082
+ id="slides-design-system-context-source"
1083
+ className={cn(
1084
+ "space-y-2 rounded-lg border border-border bg-card p-4",
1085
+ !editingId &&
1086
+ (sourcePanel !== "other" || otherSource !== "context") &&
1087
+ "hidden",
1088
+ )}
1089
+ >
1090
+ <Label className="text-foreground/80">
1091
+ {editingId
1092
+ ? t("designSystemSetup.brandNotes")
1093
+ : t("designSystemSetup.additionalNotes")}
1094
+ </Label>
1095
+ <Textarea
1096
+ value={brandNotes}
1097
+ onChange={(e) => setBrandNotes(e.target.value)}
1098
+ placeholder={t("designSystemSetup.notesPlaceholder")}
1099
+ rows={3}
1100
+ className="bg-accent border-border text-foreground placeholder:text-muted-foreground resize-none"
1101
+ />
1102
+ </div>
864
1103
 
865
- {/* Custom Instructions — durable, stored on the design system */}
866
- <div className="space-y-2">
867
- <Label className="text-foreground/80">
868
- {t("designSystemSetup.customInstructions")}
869
- </Label>
870
- <Textarea
871
- value={customInstructions}
872
- onChange={(e) => setCustomInstructions(e.target.value)}
873
- placeholder={t(
874
- "designSystemSetup.customInstructionsPlaceholder",
1104
+ {/* Custom Instructions — durable, stored on the design system */}
1105
+ <div
1106
+ className={cn(
1107
+ "space-y-2 rounded-lg border border-border bg-card p-4",
1108
+ !editingId &&
1109
+ (sourcePanel !== "other" || otherSource !== "context") &&
1110
+ "hidden",
875
1111
  )}
876
- rows={4}
877
- className="bg-accent border-border text-foreground placeholder:text-muted-foreground resize-none"
878
- />
879
- <p className="text-[11px] text-muted-foreground">
880
- {t("designSystemSetup.customInstructionsDescription")}
881
- </p>
1112
+ >
1113
+ <Label className="text-foreground/80">
1114
+ {t("designSystemSetup.customInstructions")}
1115
+ </Label>
1116
+ <Textarea
1117
+ value={customInstructions}
1118
+ onChange={(e) => setCustomInstructions(e.target.value)}
1119
+ placeholder={t(
1120
+ "designSystemSetup.customInstructionsPlaceholder",
1121
+ )}
1122
+ rows={4}
1123
+ className="bg-accent border-border text-foreground placeholder:text-muted-foreground resize-none"
1124
+ />
1125
+ <p className="text-[11px] text-muted-foreground">
1126
+ {t("designSystemSetup.customInstructionsDescription")}
1127
+ </p>
1128
+ </div>
882
1129
  </div>
883
- </div>
1130
+ )}
884
1131
  </ScrollArea>
885
1132
 
886
1133
  {/* Actions */}
@@ -895,7 +1142,11 @@ export function DesignSystemSetup({
895
1142
  </Button>
896
1143
  <Button
897
1144
  onClick={handleGenerate}
898
- disabled={editingId ? generating : !hasAnySources}
1145
+ disabled={
1146
+ editingId
1147
+ ? generating || !existingDs || existingDsLoading
1148
+ : !hasAnySources
1149
+ }
899
1150
  className="cursor-pointer"
900
1151
  >
901
1152
  {generating ? (
@@ -915,6 +1166,259 @@ export function DesignSystemSetup({
915
1166
  );
916
1167
  }
917
1168
 
1169
+ function parseDesignSystemData(
1170
+ data?: string | null,
1171
+ ): { ok: true; value: Record<string, unknown> } | { ok: false } {
1172
+ if (!data) return { ok: false };
1173
+ try {
1174
+ const parsed: unknown = JSON.parse(data);
1175
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
1176
+ return { ok: false };
1177
+ }
1178
+ return { ok: true, value: parsed as Record<string, unknown> };
1179
+ } catch {
1180
+ return { ok: false };
1181
+ }
1182
+ }
1183
+
1184
+ function isGeneratedBuilderInstructions(
1185
+ value: string | undefined,
1186
+ builder: BuilderSourceDetails,
1187
+ ): boolean {
1188
+ const instructions = value?.trim();
1189
+ if (!instructions) return false;
1190
+ return (
1191
+ instructions.startsWith(
1192
+ "This design system is indexed by Builder Design System Intelligence (DSI).",
1193
+ ) &&
1194
+ instructions.includes(
1195
+ `Builder design system id: ${builder.builderDesignSystemId}`,
1196
+ ) &&
1197
+ instructions.includes("Call get-design-system for this local id")
1198
+ );
1199
+ }
1200
+
1201
+ function SourceAccordionRow({
1202
+ icon: Icon,
1203
+ title,
1204
+ description,
1205
+ expanded,
1206
+ onClick,
1207
+ panelId,
1208
+ className,
1209
+ }: {
1210
+ icon: React.ComponentType<{ className?: string }>;
1211
+ title: string;
1212
+ description: string;
1213
+ expanded: boolean;
1214
+ onClick: () => void;
1215
+ panelId: string;
1216
+ className?: string;
1217
+ }) {
1218
+ return (
1219
+ <button
1220
+ type="button"
1221
+ aria-controls={panelId}
1222
+ aria-expanded={expanded}
1223
+ onClick={onClick}
1224
+ className={cn(
1225
+ "flex w-full items-center gap-3 rounded-lg border border-border px-4 py-3 text-left transition-[background-color,border-color] duration-150 hover:bg-accent/50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
1226
+ expanded && "bg-accent/40",
1227
+ className,
1228
+ )}
1229
+ >
1230
+ <Icon className="size-4 shrink-0 text-muted-foreground" />
1231
+ <span className="min-w-0 flex-1">
1232
+ <span className="block text-sm font-medium text-foreground/90">
1233
+ {title}
1234
+ </span>
1235
+ <span className="mt-0.5 block truncate text-xs text-muted-foreground">
1236
+ {description}
1237
+ </span>
1238
+ </span>
1239
+ <IconChevronDown
1240
+ className={cn(
1241
+ "size-4 shrink-0 text-muted-foreground transition-transform duration-150",
1242
+ expanded && "rotate-180",
1243
+ )}
1244
+ />
1245
+ </button>
1246
+ );
1247
+ }
1248
+
1249
+ function BuilderSourceStatus({ builder }: { builder: BuilderSourceDetails }) {
1250
+ const t = useT();
1251
+ const docs = builder.docCount ?? builder.docs?.length ?? 0;
1252
+ const tokens = Object.keys(builder.tokenValues ?? {}).length;
1253
+ const normalizedStatus = builder.builderStatus?.toLowerCase();
1254
+ const hasIndexedResults = docs > 0 || tokens > 0;
1255
+ const isIndexed =
1256
+ hasIndexedResults ||
1257
+ normalizedStatus === "ready" ||
1258
+ normalizedStatus === "complete" ||
1259
+ normalizedStatus === "completed";
1260
+ const isIndexing = ["in-progress", "pending", "processing"].includes(
1261
+ normalizedStatus ?? "",
1262
+ );
1263
+ const state =
1264
+ isIndexing && !isIndexed
1265
+ ? "indexing"
1266
+ : builder.warning
1267
+ ? "unavailable"
1268
+ : isIndexed
1269
+ ? "indexed"
1270
+ : "indexing";
1271
+ const sourceKind = builder.sourceKind;
1272
+ const SourceIcon =
1273
+ sourceKind === "figma"
1274
+ ? IconBrandFigma
1275
+ : sourceKind === "github"
1276
+ ? IconBrandGithub
1277
+ : sourceKind === "code"
1278
+ ? IconFolder
1279
+ : IconPalette;
1280
+ const sourceTitle =
1281
+ sourceKind === "figma"
1282
+ ? t("designSystemSetup.sourceFigma")
1283
+ : sourceKind === "github"
1284
+ ? t("designSystemSetup.sourceGitHub")
1285
+ : sourceKind === "code"
1286
+ ? t("designSystemSetup.sourceCode")
1287
+ : sourceKind === "mixed"
1288
+ ? t("designSystemSetup.sourceMixed")
1289
+ : t("designSystemSetup.sourceBuilder");
1290
+ const statusTitle =
1291
+ state === "unavailable"
1292
+ ? t("designSystemSetup.sourceUnavailable")
1293
+ : state === "indexed"
1294
+ ? t("designSystemSetup.sourceIndexed")
1295
+ : t("designSystemSetup.sourceIndexing");
1296
+ const statusDescription =
1297
+ state === "unavailable"
1298
+ ? t("designSystemSetup.sourceUnavailableDescription")
1299
+ : state === "indexing"
1300
+ ? t("designSystemSetup.sourceIndexingDescription")
1301
+ : docs > 0 && tokens > 0
1302
+ ? t("designSystemSetup.sourceIndexedDescription", { docs, tokens })
1303
+ : docs > 0
1304
+ ? t("designSystemSetup.sourceIndexedDocsOnly", { docs })
1305
+ : tokens > 0
1306
+ ? t("designSystemSetup.sourceIndexedTokensOnly", { tokens })
1307
+ : t("designSystemSetup.sourceIndexedDescription", {
1308
+ docs,
1309
+ tokens,
1310
+ });
1311
+ const statusClassName =
1312
+ state === "unavailable"
1313
+ ? "text-destructive"
1314
+ : state === "indexed"
1315
+ ? "text-primary"
1316
+ : "text-muted-foreground";
1317
+
1318
+ return (
1319
+ <section
1320
+ aria-label={t("designSystemSetup.sourceLabel")}
1321
+ className="rounded-lg border border-border bg-accent/30 px-4 py-3"
1322
+ >
1323
+ <div className="flex items-start gap-3">
1324
+ <div className="flex size-9 shrink-0 items-center justify-center rounded-md bg-background text-muted-foreground">
1325
+ <SourceIcon className="size-4" />
1326
+ </div>
1327
+ <div className="min-w-0 flex-1">
1328
+ <p className="text-[11px] font-medium uppercase tracking-wide text-muted-foreground">
1329
+ {t("designSystemSetup.sourceLabel")}
1330
+ </p>
1331
+ <p className="mt-0.5 truncate text-sm font-medium text-foreground">
1332
+ {sourceTitle}
1333
+ </p>
1334
+ <p className="mt-1 text-xs leading-relaxed text-muted-foreground">
1335
+ {statusDescription}
1336
+ </p>
1337
+ </div>
1338
+ <div
1339
+ className={cn(
1340
+ "flex shrink-0 items-center gap-1.5 text-xs font-medium",
1341
+ statusClassName,
1342
+ )}
1343
+ role="status"
1344
+ aria-live="polite"
1345
+ >
1346
+ <span
1347
+ className="size-1.5 rounded-full bg-current"
1348
+ aria-hidden="true"
1349
+ />
1350
+ {statusTitle}
1351
+ </div>
1352
+ </div>
1353
+ {builder.builderUrl ? (
1354
+ <div className="mt-3 border-t border-border pt-3">
1355
+ <a
1356
+ href={withBuilderUtmTrackingParams(builder.builderUrl, {
1357
+ campaign: "product",
1358
+ content: "design_system_intelligence",
1359
+ })}
1360
+ target="_blank"
1361
+ rel="noreferrer"
1362
+ className="inline-flex items-center gap-1.5 text-xs font-medium text-foreground underline-offset-4 hover:underline"
1363
+ >
1364
+ {t("designSystemSetup.sourceOpenInBuilder")}
1365
+ <IconExternalLink className="size-3.5" />
1366
+ </a>
1367
+ </div>
1368
+ ) : null}
1369
+ </section>
1370
+ );
1371
+ }
1372
+
1373
+ function DesignSystemEditSkeleton() {
1374
+ const t = useT();
1375
+ return (
1376
+ <div
1377
+ aria-busy="true"
1378
+ aria-label={t("designSystemSetup.loading")}
1379
+ className="space-y-5 py-4"
1380
+ >
1381
+ <div className="space-y-2">
1382
+ <Skeleton className="h-4 w-28" />
1383
+ <Skeleton className="h-10 w-full rounded-md" />
1384
+ </div>
1385
+ <div className="space-y-3 rounded-lg border border-border bg-accent/30 px-4 py-3">
1386
+ <div className="flex items-center gap-3">
1387
+ <Skeleton className="size-9 rounded-md" />
1388
+ <div className="flex-1 space-y-2">
1389
+ <Skeleton className="h-3 w-16" />
1390
+ <Skeleton className="h-4 w-32" />
1391
+ </div>
1392
+ <Skeleton className="h-4 w-24" />
1393
+ </div>
1394
+ <Skeleton className="h-3 w-4/5" />
1395
+ <Skeleton className="h-3 w-24" />
1396
+ </div>
1397
+ <div className="space-y-2">
1398
+ <Skeleton className="h-4 w-24" />
1399
+ <Skeleton className="h-24 w-full rounded-md" />
1400
+ </div>
1401
+ <div className="space-y-2">
1402
+ <Skeleton className="h-4 w-36" />
1403
+ <Skeleton className="h-32 w-full rounded-md" />
1404
+ <Skeleton className="h-3 w-64" />
1405
+ </div>
1406
+ </div>
1407
+ );
1408
+ }
1409
+
1410
+ function DesignSystemEditError() {
1411
+ const t = useT();
1412
+ return (
1413
+ <div
1414
+ role="alert"
1415
+ className="flex min-h-64 items-center justify-center py-8 text-center text-sm text-destructive"
1416
+ >
1417
+ {t("designSystemSetup.loadFailed")}
1418
+ </div>
1419
+ );
1420
+ }
1421
+
918
1422
  function TagList({
919
1423
  items,
920
1424
  onRemove,
@@ -949,10 +1453,12 @@ function TagList({
949
1453
  function BuilderIndexPreview({
950
1454
  result,
951
1455
  decodeStatus,
1456
+ displayTitle,
952
1457
  onReset,
953
1458
  }: {
954
1459
  result: BuilderIndexResult;
955
1460
  decodeStatus: DecodeJobStatus | null;
1461
+ displayTitle?: string;
956
1462
  onReset: () => void;
957
1463
  }) {
958
1464
  const t = useT();
@@ -977,7 +1483,9 @@ function BuilderIndexPreview({
977
1483
  <p className="text-xs text-muted-foreground">
978
1484
  {t("designSystemSetup.builderIndexingDescription", {
979
1485
  title:
980
- result.suggestedTitle || t("designSystemSetup.importedBrand"),
1486
+ displayTitle ||
1487
+ result.suggestedTitle ||
1488
+ t("designSystemSetup.importedBrand"),
981
1489
  })}
982
1490
  </p>
983
1491
  </div>