@agent-native/core 0.80.0 → 0.80.1

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 (220) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +8 -0
  3. package/corpus/core/docs/content/locales/ar-SA/skills-guide.mdx +5 -0
  4. package/corpus/core/docs/content/locales/ar-SA/template-design.mdx +14 -1
  5. package/corpus/core/docs/content/locales/de-DE/skills-guide.mdx +5 -0
  6. package/corpus/core/docs/content/locales/de-DE/template-design.mdx +15 -1
  7. package/corpus/core/docs/content/locales/es-ES/skills-guide.mdx +5 -0
  8. package/corpus/core/docs/content/locales/es-ES/template-design.mdx +15 -1
  9. package/corpus/core/docs/content/locales/fr-FR/skills-guide.mdx +5 -0
  10. package/corpus/core/docs/content/locales/fr-FR/template-design.mdx +15 -1
  11. package/corpus/core/docs/content/locales/hi-IN/skills-guide.mdx +5 -0
  12. package/corpus/core/docs/content/locales/hi-IN/template-design.mdx +15 -1
  13. package/corpus/core/docs/content/locales/ja-JP/skills-guide.mdx +5 -0
  14. package/corpus/core/docs/content/locales/ja-JP/template-design.mdx +16 -1
  15. package/corpus/core/docs/content/locales/ko-KR/skills-guide.mdx +5 -0
  16. package/corpus/core/docs/content/locales/ko-KR/template-design.mdx +14 -1
  17. package/corpus/core/docs/content/locales/pt-BR/skills-guide.mdx +5 -0
  18. package/corpus/core/docs/content/locales/pt-BR/template-design.mdx +14 -1
  19. package/corpus/core/docs/content/locales/zh-CN/skills-guide.mdx +5 -0
  20. package/corpus/core/docs/content/locales/zh-CN/template-design.mdx +14 -1
  21. package/corpus/core/docs/content/locales/zh-TW/skills-guide.mdx +5 -0
  22. package/corpus/core/docs/content/locales/zh-TW/template-design.mdx +14 -1
  23. package/corpus/core/docs/content/skills-guide.mdx +5 -0
  24. package/corpus/core/docs/content/template-design.mdx +14 -1
  25. package/corpus/core/package.json +1 -1
  26. package/corpus/core/src/application-state/handlers.ts +1 -1
  27. package/corpus/core/src/brand-kit/index.ts +1 -1
  28. package/corpus/core/src/cli/skills.ts +18 -0
  29. package/corpus/core/src/client/AgentPanel.tsx +1 -1
  30. package/corpus/core/src/client/MultiTabAssistantChat.tsx +1 -1
  31. package/corpus/core/src/client/extensions/portable-extension.ts +1 -1
  32. package/corpus/core/src/code-agents/transcript-normalizer.ts +1 -1
  33. package/corpus/core/src/extensions/path.ts +1 -4
  34. package/corpus/core/src/integrations/a2a-continuation-processor.ts +1 -1
  35. package/corpus/core/src/mcp/build-server.ts +1 -1
  36. package/corpus/core/src/org/handlers.ts +5 -5
  37. package/corpus/core/src/org/plugin.ts +2 -2
  38. package/corpus/core/src/scripts/call-agent.ts +1 -1
  39. package/corpus/core/src/scripts/db/safety.ts +1 -1
  40. package/corpus/core/src/server/auth.ts +3 -0
  41. package/corpus/core/src/server/builder-design-systems.ts +308 -0
  42. package/corpus/core/src/server/core-routes-plugin.ts +29 -3
  43. package/corpus/core/src/server/index.ts +8 -0
  44. package/corpus/core/src/styles/agent-native.css +14 -7
  45. package/corpus/core/src/usage/store.ts +2 -2
  46. package/corpus/templates/analytics/actions/dashboard-mutation-api.ts +298 -15
  47. package/corpus/templates/analytics/actions/get-sql-dashboard.ts +9 -4
  48. package/corpus/templates/analytics/actions/mutate-dashboard.ts +18 -2
  49. package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +12 -2
  50. package/corpus/templates/analytics/app/hooks/use-replay-storage-status.ts +66 -0
  51. package/corpus/templates/analytics/app/i18n/zh-TW.ts +37 -0
  52. package/corpus/templates/analytics/app/i18n-data.ts +404 -0
  53. package/corpus/templates/analytics/app/pages/Settings.tsx +333 -0
  54. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/PanelEditorDialog.tsx +2 -1
  55. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/dashboard-layout.ts +121 -3
  56. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +49 -26
  57. package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +137 -36
  58. package/corpus/templates/analytics/changelog/2026-06-29-analytics-agents-can-now-place-new-charts-into-requested-das.md +6 -0
  59. package/corpus/templates/analytics/changelog/2026-06-29-analytics-queries-now-report-failed-source-query-errors-inst.md +6 -0
  60. package/corpus/templates/analytics/changelog/2026-06-29-charts-can-now-be-dropped-between-full-dashboard-rows-to-cre.md +6 -0
  61. package/corpus/templates/analytics/changelog/2026-06-29-dashboard-email-reports-include-the-full-dashboard-image-wit.md +6 -0
  62. package/corpus/templates/analytics/changelog/2026-06-29-main-surface-border-reaches-the-top.md +6 -0
  63. package/corpus/templates/analytics/changelog/2026-06-29-session-replay-now-records-playable-sessions-in-production-a.md +6 -0
  64. package/corpus/templates/analytics/changelog/2026-06-29-set-up-session-replay-storage-from-settings-connect-builder-.md +6 -0
  65. package/corpus/templates/analytics/scripts/cleanup-empty-session-recordings.ts +102 -0
  66. package/corpus/templates/analytics/server/lib/dashboard-report.ts +49 -26
  67. package/corpus/templates/analytics/server/lib/real-data-actions.ts +81 -20
  68. package/corpus/templates/analytics/server/lib/replay-storage.ts +79 -0
  69. package/corpus/templates/analytics/server/lib/s3-upload-provider.ts +255 -0
  70. package/corpus/templates/analytics/server/lib/session-replay.ts +29 -8
  71. package/corpus/templates/analytics/server/plugins/agent-chat.ts +11 -2
  72. package/corpus/templates/analytics/server/plugins/onboarding.ts +97 -0
  73. package/corpus/templates/clips/desktop/src/lib/recorder.ts +24 -0
  74. package/corpus/templates/clips/desktop/src/lib/transcription-capture.ts +105 -5
  75. package/corpus/templates/content/actions/set-image-alt-text.ts +1 -1
  76. package/corpus/templates/content/shared/document-export.ts +1 -1
  77. package/corpus/templates/design/.agents/skills/design-systems/SKILL.md +8 -18
  78. package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +17 -0
  79. package/corpus/templates/design/actions/add-localhost-screens.ts +32 -5
  80. package/corpus/templates/design/actions/index-design-system-with-builder.ts +259 -0
  81. package/corpus/templates/design/actions/update-file.ts +9 -2
  82. package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +33 -75
  83. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +72 -9
  84. package/corpus/templates/design/app/components/design/DesignExtensionsPanel.tsx +41 -39
  85. package/corpus/templates/design/app/components/design/EditPanel.tsx +1029 -249
  86. package/corpus/templates/design/app/components/design/LayersPanel.tsx +450 -101
  87. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +978 -154
  88. package/corpus/templates/design/app/components/design/TweaksPanel.tsx +7 -9
  89. package/corpus/templates/design/app/components/design/inspector/AlignmentMatrix.tsx +133 -66
  90. package/corpus/templates/design/app/components/design/inspector/AutoLayoutMatrix.tsx +1234 -344
  91. package/corpus/templates/design/app/components/design/inspector/ConstraintsWidget.tsx +144 -94
  92. package/corpus/templates/design/app/components/design/inspector/ExportSettingsPanel.tsx +301 -72
  93. package/corpus/templates/design/app/components/design/inspector/FigmaColorPicker.tsx +876 -286
  94. package/corpus/templates/design/app/components/design/inspector/GradientEditor.tsx +601 -0
  95. package/corpus/templates/design/app/components/design/inspector/ImageFillControls.tsx +242 -0
  96. package/corpus/templates/design/app/components/design/inspector/ScrubInput.tsx +30 -7
  97. package/corpus/templates/design/app/components/design/inspector/ShaderControls.tsx +212 -155
  98. package/corpus/templates/design/app/components/design/inspector/ShaderFillsPanel.tsx +423 -0
  99. package/corpus/templates/design/app/components/design/inspector/figma-icons.tsx +487 -107
  100. package/corpus/templates/design/app/components/design/inspector/index.ts +27 -0
  101. package/corpus/templates/design/app/global.css +29 -3
  102. package/corpus/templates/design/app/i18n/zh-TW.ts +13 -0
  103. package/corpus/templates/design/app/i18n-data.ts +239 -1
  104. package/corpus/templates/design/app/pages/DesignEditor.tsx +1023 -353
  105. package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +57 -221
  106. package/corpus/templates/design/changelog/2026-06-29-canvas-selection-no-longer-flashes-broken-prototype-html-whe.md +6 -0
  107. package/corpus/templates/design/changelog/2026-06-29-command-menu-selections-are-clearer-in-dark-mode.md +6 -0
  108. package/corpus/templates/design/changelog/2026-06-29-design-mode-top-chrome-now-groups-collaborators-preview-shar.md +6 -0
  109. package/corpus/templates/design/changelog/2026-06-29-element-selection-now-stays-on-the-intended-layer-after-sele.md +6 -0
  110. package/corpus/templates/design/changelog/2026-06-29-screen-overview-full-view-controls-now-sit-above-frames-inst.md +6 -0
  111. package/corpus/templates/design/changelog/2026-06-29-screen-overview-tools-can-draw-shapes-create-screens-and-kee.md +6 -0
  112. package/corpus/templates/design/changelog/2026-06-29-the-pen-tool-now-creates-anchor-based-bezier-vectors-with-ha.md +6 -0
  113. package/corpus/templates/design/server/handlers/import-figma-system.ts +38 -85
  114. package/corpus/templates/design/server/lib/design-snapshot.ts +9 -1
  115. package/corpus/templates/design/shared/code-layer.ts +209 -9
  116. package/corpus/templates/design/shared/html-content.ts +21 -0
  117. package/corpus/templates/design/shared/pen-path.ts +207 -0
  118. package/corpus/templates/mail/app/lib/utils.ts +2 -2
  119. package/corpus/templates/slides/.agents/skills/design-systems/SKILL.md +9 -10
  120. package/corpus/templates/slides/AGENTS.md +3 -2
  121. package/corpus/templates/slides/actions/import-file.ts +26 -17
  122. package/corpus/templates/slides/actions/index-design-system-with-builder.ts +259 -0
  123. package/corpus/templates/slides/app/components/design-system/DesignSystemSetup.tsx +35 -167
  124. package/corpus/templates/slides/app/components/design-system/fig-import-response.ts +9 -13
  125. package/corpus/templates/slides/app/context/DeckContext.tsx +1 -1
  126. package/corpus/templates/slides/app/i18n/ar-SA.ts +9 -37
  127. package/corpus/templates/slides/app/i18n/de-DE.ts +10 -25
  128. package/corpus/templates/slides/app/i18n/en-US.ts +9 -26
  129. package/corpus/templates/slides/app/i18n/es-ES.ts +10 -28
  130. package/corpus/templates/slides/app/i18n/fr-FR.ts +10 -28
  131. package/corpus/templates/slides/app/i18n/hi-IN.ts +9 -26
  132. package/corpus/templates/slides/app/i18n/ja-JP.ts +10 -22
  133. package/corpus/templates/slides/app/i18n/ko-KR.ts +9 -23
  134. package/corpus/templates/slides/app/i18n/pt-BR.ts +10 -28
  135. package/corpus/templates/slides/app/i18n/zh-CN.ts +9 -22
  136. package/corpus/templates/slides/app/i18n/zh-TW.ts +9 -22
  137. package/corpus/templates/slides/server/handlers/import-figma-system.ts +44 -12
  138. package/corpus/templates/slides/server/lib/chat-attachments.ts +1 -1
  139. package/corpus/templates/videos/app/components/NewCompositionPopover.tsx +1 -1
  140. package/dist/application-state/handlers.js +1 -1
  141. package/dist/application-state/handlers.js.map +1 -1
  142. package/dist/brand-kit/index.d.ts +1 -1
  143. package/dist/brand-kit/index.js +1 -1
  144. package/dist/brand-kit/index.js.map +1 -1
  145. package/dist/cli/skills.d.ts.map +1 -1
  146. package/dist/cli/skills.js +18 -0
  147. package/dist/cli/skills.js.map +1 -1
  148. package/dist/client/AgentPanel.js +1 -1
  149. package/dist/client/AgentPanel.js.map +1 -1
  150. package/dist/client/MultiTabAssistantChat.js +1 -1
  151. package/dist/client/MultiTabAssistantChat.js.map +1 -1
  152. package/dist/client/extensions/portable-extension.d.ts +1 -1
  153. package/dist/client/extensions/portable-extension.d.ts.map +1 -1
  154. package/dist/client/extensions/portable-extension.js.map +1 -1
  155. package/dist/code-agents/transcript-normalizer.js +1 -1
  156. package/dist/code-agents/transcript-normalizer.js.map +1 -1
  157. package/dist/collab/awareness.d.ts +2 -2
  158. package/dist/collab/awareness.d.ts.map +1 -1
  159. package/dist/extensions/path.d.ts +1 -1
  160. package/dist/extensions/path.d.ts.map +1 -1
  161. package/dist/extensions/path.js.map +1 -1
  162. package/dist/integrations/a2a-continuation-processor.js +1 -1
  163. package/dist/integrations/a2a-continuation-processor.js.map +1 -1
  164. package/dist/mcp/build-server.d.ts +1 -1
  165. package/dist/mcp/build-server.d.ts.map +1 -1
  166. package/dist/mcp/build-server.js.map +1 -1
  167. package/dist/observability/routes.d.ts +3 -3
  168. package/dist/org/handlers.js +5 -5
  169. package/dist/org/handlers.js.map +1 -1
  170. package/dist/org/plugin.js +2 -2
  171. package/dist/org/plugin.js.map +1 -1
  172. package/dist/progress/routes.d.ts +1 -1
  173. package/dist/scripts/call-agent.js +1 -1
  174. package/dist/scripts/call-agent.js.map +1 -1
  175. package/dist/scripts/db/safety.js +1 -1
  176. package/dist/scripts/db/safety.js.map +1 -1
  177. package/dist/server/auth.d.ts.map +1 -1
  178. package/dist/server/auth.js +3 -0
  179. package/dist/server/auth.js.map +1 -1
  180. package/dist/server/builder-design-systems.d.ts +28 -0
  181. package/dist/server/builder-design-systems.d.ts.map +1 -0
  182. package/dist/server/builder-design-systems.js +217 -0
  183. package/dist/server/builder-design-systems.js.map +1 -0
  184. package/dist/server/core-routes-plugin.d.ts +1 -0
  185. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  186. package/dist/server/core-routes-plugin.js +20 -3
  187. package/dist/server/core-routes-plugin.js.map +1 -1
  188. package/dist/server/index.d.ts +1 -0
  189. package/dist/server/index.d.ts.map +1 -1
  190. package/dist/server/index.js +1 -0
  191. package/dist/server/index.js.map +1 -1
  192. package/dist/server/transcribe-voice.d.ts +1 -1
  193. package/dist/styles/agent-native.css +14 -7
  194. package/dist/usage/store.js +2 -2
  195. package/dist/usage/store.js.map +1 -1
  196. package/docs/content/locales/ar-SA/skills-guide.mdx +5 -0
  197. package/docs/content/locales/ar-SA/template-design.mdx +14 -1
  198. package/docs/content/locales/de-DE/skills-guide.mdx +5 -0
  199. package/docs/content/locales/de-DE/template-design.mdx +15 -1
  200. package/docs/content/locales/es-ES/skills-guide.mdx +5 -0
  201. package/docs/content/locales/es-ES/template-design.mdx +15 -1
  202. package/docs/content/locales/fr-FR/skills-guide.mdx +5 -0
  203. package/docs/content/locales/fr-FR/template-design.mdx +15 -1
  204. package/docs/content/locales/hi-IN/skills-guide.mdx +5 -0
  205. package/docs/content/locales/hi-IN/template-design.mdx +15 -1
  206. package/docs/content/locales/ja-JP/skills-guide.mdx +5 -0
  207. package/docs/content/locales/ja-JP/template-design.mdx +16 -1
  208. package/docs/content/locales/ko-KR/skills-guide.mdx +5 -0
  209. package/docs/content/locales/ko-KR/template-design.mdx +14 -1
  210. package/docs/content/locales/pt-BR/skills-guide.mdx +5 -0
  211. package/docs/content/locales/pt-BR/template-design.mdx +14 -1
  212. package/docs/content/locales/zh-CN/skills-guide.mdx +5 -0
  213. package/docs/content/locales/zh-CN/template-design.mdx +14 -1
  214. package/docs/content/locales/zh-TW/skills-guide.mdx +5 -0
  215. package/docs/content/locales/zh-TW/template-design.mdx +14 -1
  216. package/docs/content/skills-guide.mdx +5 -0
  217. package/docs/content/template-design.mdx +14 -1
  218. package/package.json +1 -1
  219. package/corpus/templates/design/actions/import-figma-file.ts +0 -166
  220. package/corpus/templates/slides/server/lib/fig-design-system.ts +0 -110
@@ -3,13 +3,13 @@ import path from "path";
3
3
 
4
4
  import { defineAction } from "@agent-native/core";
5
5
  import { writeAppState } from "@agent-native/core/application-state";
6
+ import { startBuilderDesignSystemIndex } from "@agent-native/core/server";
6
7
  import { assertAccess } from "@agent-native/core/sharing";
7
8
  import { eq } from "drizzle-orm";
8
9
  import { z } from "zod";
9
10
 
10
11
  import { getDb, schema } from "../server/db/index.js";
11
12
  import { notifyClients } from "../server/handlers/decks.js";
12
- import { parseSlidesFigDesignSystem } from "../server/lib/fig-design-system.js";
13
13
  import { resolveUserUploadedFile } from "./_uploaded-files.js";
14
14
 
15
15
  const DEFAULT_MAX_SOURCE_CHARS = 60_000;
@@ -20,8 +20,8 @@ export default defineAction({
20
20
  "For PPTX files, returns parsed slides with text and layout info ready for conversion. " +
21
21
  "For DOCX files, returns structured sections extracted from the document. " +
22
22
  "For PDF files, returns extracted text organized by page. " +
23
- "For Figma .fig files, returns extracted brand/design-system tokens and a preview; call create-design-system with the returned data. " +
24
- "The agent can then use the extracted content to create a deck via create-deck or add-slide, or create a design system from .fig tokens.",
23
+ "For Figma .fig files, requires Builder.io and starts Builder design-system indexing; the returned Builder job/design-system ids are the source of truth. " +
24
+ "The agent can then use the extracted content to create a deck via create-deck or add-slide, or tell the user where Builder is indexing the design system.",
25
25
  schema: z.object({
26
26
  filePath: z
27
27
  .string()
@@ -78,27 +78,36 @@ export default defineAction({
78
78
  if (detectedFormat === "fig") {
79
79
  if (importIntoDeck) {
80
80
  throw new Error(
81
- "Figma .fig imports create design systems, not slide replacements. Re-run without importIntoDeck, then call create-design-system with the returned data.",
81
+ "Figma .fig imports start Builder design-system indexing, not slide replacements. Re-run without importIntoDeck.",
82
82
  );
83
83
  }
84
- const result = parseSlidesFigDesignSystem({
85
- data: fileBuffer,
86
- filename: path.basename(absPath),
84
+ const title = titleFromPath(absPath);
85
+ const result = await startBuilderDesignSystemIndex({
86
+ projectName: title,
87
+ files: [
88
+ {
89
+ name: path.basename(absPath),
90
+ data: fileBuffer,
91
+ mimeType: "application/octet-stream",
92
+ },
93
+ ],
87
94
  });
88
95
  return {
89
96
  format: "fig",
90
- title: result.suggestedTitle,
91
- designSystem: result.data,
92
- customInstructions: result.customInstructions,
93
- preview: result.preview,
97
+ title,
98
+ source: "builder",
99
+ projectId: result.projectId,
100
+ jobId: result.jobId,
101
+ designSystemId: result.designSystemId,
102
+ builderUrl: result.builderUrl,
103
+ status: result.status,
94
104
  deckId,
95
105
  instructions: [
96
- "Parsed the .fig file and extracted a slide-ready design system.",
97
- "Call create-design-system with:",
98
- `- title: ${JSON.stringify(result.suggestedTitle)}`,
99
- "- data: JSON.stringify(designSystem)",
100
- "- customInstructions: the returned customInstructions string",
101
- "Then set it as default or apply it to a deck if the user asked.",
106
+ "Sent the .fig file to Builder design-system indexing.",
107
+ `Builder design system: ${result.designSystemId}`,
108
+ `Builder job: ${result.jobId}`,
109
+ `Open: ${result.builderUrl}`,
110
+ "Do not call create-design-system locally for this .fig file; Builder owns the indexed design-system docs and generated usage guidance.",
102
111
  ].join("\n"),
103
112
  };
104
113
  }
@@ -0,0 +1,259 @@
1
+ import { defineAction } from "@agent-native/core";
2
+ import {
3
+ startBuilderDesignSystemIndex,
4
+ type BuilderDesignSystemIndexFile,
5
+ } from "@agent-native/core/server";
6
+ import {
7
+ getRequestOrgId,
8
+ getRequestUserEmail,
9
+ } from "@agent-native/core/server/request-context";
10
+ import { eq } from "drizzle-orm";
11
+ import { nanoid } from "nanoid";
12
+ import { z } from "zod";
13
+
14
+ import { getDb, schema } from "../server/db/index.js";
15
+
16
+ const MAX_CODE_FILES = 50;
17
+ const MAX_TOTAL_CODE_BYTES = 2 * 1024 * 1024;
18
+
19
+ const codeFileSchema = z.object({
20
+ filename: z.string().trim().min(1).describe("File name or relative path"),
21
+ content: z.string().describe("Raw text content of the code/design file"),
22
+ mimeType: z.string().trim().optional().describe("Optional MIME type"),
23
+ });
24
+
25
+ function mimeTypeForFilename(filename: string, explicit?: string): string {
26
+ if (explicit?.trim()) return explicit.trim();
27
+ const lower = filename.toLowerCase();
28
+ if (lower.endsWith(".css")) return "text/css";
29
+ if (lower.endsWith(".json")) return "application/json";
30
+ if (lower.endsWith(".md") || lower.endsWith(".mdx")) return "text/markdown";
31
+ if (lower.endsWith(".html")) return "text/html";
32
+ if (lower.endsWith(".svg")) return "image/svg+xml";
33
+ return "text/plain";
34
+ }
35
+
36
+ function makeFiles(
37
+ codeFiles: Array<z.infer<typeof codeFileSchema>> | undefined,
38
+ ): BuilderDesignSystemIndexFile[] {
39
+ const encoder = new TextEncoder();
40
+ const files: BuilderDesignSystemIndexFile[] = [];
41
+ let totalBytes = 0;
42
+ for (const file of (codeFiles ?? []).slice(0, MAX_CODE_FILES)) {
43
+ const data = encoder.encode(file.content);
44
+ if (totalBytes + data.byteLength > MAX_TOTAL_CODE_BYTES) break;
45
+ totalBytes += data.byteLength;
46
+ files.push({
47
+ name: file.filename.replace(/^\/+/, "") || "code.txt",
48
+ data,
49
+ mimeType: mimeTypeForFilename(file.filename, file.mimeType),
50
+ });
51
+ }
52
+ return files;
53
+ }
54
+
55
+ function localBuilderDesignSystemId(builderDesignSystemId: string): string {
56
+ const slug = builderDesignSystemId
57
+ .replace(/[^a-zA-Z0-9_-]+/g, "-")
58
+ .replace(/^-+|-+$/g, "")
59
+ .slice(0, 96);
60
+ return `builder-${slug || "design-system"}`;
61
+ }
62
+
63
+ function builderProxyData({
64
+ builderDesignSystemId,
65
+ jobId,
66
+ builderUrl,
67
+ projectName,
68
+ description,
69
+ }: {
70
+ builderDesignSystemId: string;
71
+ jobId: string;
72
+ builderUrl: string;
73
+ projectName?: string;
74
+ description?: string;
75
+ }) {
76
+ return JSON.stringify({
77
+ source: "builder",
78
+ builderDesignSystemId,
79
+ builderJobId: jobId,
80
+ builderUrl,
81
+ colors: {
82
+ primary: "var(--primary)",
83
+ secondary: "var(--secondary)",
84
+ accent: "var(--accent)",
85
+ background: "var(--background)",
86
+ surface: "var(--card)",
87
+ text: "var(--foreground)",
88
+ textMuted: "var(--muted-foreground)",
89
+ },
90
+ typography: {
91
+ headingFont: "inherit",
92
+ bodyFont: "inherit",
93
+ headingWeight: "700",
94
+ bodyWeight: "400",
95
+ headingSizes: { h1: "48px", h2: "32px", h3: "24px" },
96
+ },
97
+ spacing: { elementGap: "24px", slidePadding: "48px" },
98
+ borders: { radius: "12px", accentWidth: "1px" },
99
+ logos: [],
100
+ notes: [
101
+ "This is a local proxy for a Builder-indexed design system.",
102
+ `Builder design system id: ${builderDesignSystemId}`,
103
+ `Builder indexing job id: ${jobId}`,
104
+ `Builder URL: ${builderUrl}`,
105
+ projectName ? `Requested name: ${projectName}` : "",
106
+ description ? `Context: ${description}` : "",
107
+ "Use Builder as the source of truth for extracted tokens and guidance.",
108
+ ]
109
+ .filter(Boolean)
110
+ .join("\n"),
111
+ });
112
+ }
113
+
114
+ function builderProxyInstructions({
115
+ builderDesignSystemId,
116
+ jobId,
117
+ builderUrl,
118
+ }: {
119
+ builderDesignSystemId: string;
120
+ jobId: string;
121
+ builderUrl: string;
122
+ }) {
123
+ return [
124
+ "This design system is indexed and owned by Builder.",
125
+ `Builder design system id: ${builderDesignSystemId}`,
126
+ `Builder job id: ${jobId}`,
127
+ `Builder URL: ${builderUrl}`,
128
+ "When generating slides, treat Builder as the source of truth for the final extracted tokens, assets, and guidance.",
129
+ ].join("\n");
130
+ }
131
+
132
+ export default defineAction({
133
+ description:
134
+ "Start Builder design-system indexing from a GitHub repository and/or code files. " +
135
+ "Use this instead of local import-code/import-github when the user wants a reusable brand kit or slide design system. " +
136
+ "Requires Builder.io to be connected; Builder owns the indexed design-system docs, generated guidance, and job state.",
137
+ schema: z.object({
138
+ projectName: z
139
+ .string()
140
+ .optional()
141
+ .describe("Optional Builder project/design-system name"),
142
+ description: z
143
+ .string()
144
+ .optional()
145
+ .describe("Additional brand context or instructions for Builder"),
146
+ githubRepoUrl: z
147
+ .string()
148
+ .optional()
149
+ .describe("GitHub repository URL to index with Builder"),
150
+ connectedProjectId: z
151
+ .string()
152
+ .optional()
153
+ .describe("Optional existing Builder project id to attach indexing to"),
154
+ codeFiles: z
155
+ .array(codeFileSchema)
156
+ .optional()
157
+ .describe("Optional inlined code/design files to upload to Builder"),
158
+ }),
159
+ run: async ({
160
+ projectName,
161
+ description,
162
+ githubRepoUrl,
163
+ connectedProjectId,
164
+ codeFiles,
165
+ }) => {
166
+ const files = makeFiles(codeFiles);
167
+ const result = await startBuilderDesignSystemIndex({
168
+ projectName,
169
+ description,
170
+ githubRepoUrl,
171
+ connectedProjectId,
172
+ files,
173
+ });
174
+ const ownerEmail = getRequestUserEmail();
175
+ if (!ownerEmail) throw new Error("no authenticated user");
176
+
177
+ const db = getDb();
178
+ const now = new Date().toISOString();
179
+ const orgId = getRequestOrgId();
180
+ const baseLocalDesignSystemId = localBuilderDesignSystemId(
181
+ result.designSystemId,
182
+ );
183
+ const title = projectName?.trim() || "Builder indexed design system";
184
+ const localData = builderProxyData({
185
+ builderDesignSystemId: result.designSystemId,
186
+ jobId: result.jobId,
187
+ builderUrl: result.builderUrl,
188
+ projectName,
189
+ description,
190
+ });
191
+ const customInstructions = builderProxyInstructions({
192
+ builderDesignSystemId: result.designSystemId,
193
+ jobId: result.jobId,
194
+ builderUrl: result.builderUrl,
195
+ });
196
+ const [existing] = await db
197
+ .select({
198
+ id: schema.designSystems.id,
199
+ ownerEmail: schema.designSystems.ownerEmail,
200
+ })
201
+ .from(schema.designSystems)
202
+ .where(eq(schema.designSystems.id, baseLocalDesignSystemId))
203
+ .limit(1);
204
+ const localDesignSystemId =
205
+ existing && existing.ownerEmail !== ownerEmail
206
+ ? `${baseLocalDesignSystemId}-${nanoid(8)}`
207
+ : baseLocalDesignSystemId;
208
+ if (existing && existing.ownerEmail === ownerEmail) {
209
+ await db
210
+ .update(schema.designSystems)
211
+ .set({
212
+ title,
213
+ description:
214
+ description ??
215
+ `Builder indexed design system ${result.designSystemId}`,
216
+ data: localData,
217
+ assets: "[]",
218
+ customInstructions,
219
+ updatedAt: now,
220
+ })
221
+ .where(eq(schema.designSystems.id, existing.id));
222
+ } else {
223
+ const [ownedSystem] = await db
224
+ .select({ id: schema.designSystems.id })
225
+ .from(schema.designSystems)
226
+ .where(eq(schema.designSystems.ownerEmail, ownerEmail))
227
+ .limit(1);
228
+ await db.insert(schema.designSystems).values({
229
+ id: localDesignSystemId,
230
+ title,
231
+ description:
232
+ description ??
233
+ `Builder indexed design system ${result.designSystemId}`,
234
+ data: localData,
235
+ assets: "[]",
236
+ customInstructions,
237
+ isDefault: !ownedSystem,
238
+ ownerEmail,
239
+ orgId,
240
+ createdAt: now,
241
+ updatedAt: now,
242
+ });
243
+ }
244
+
245
+ return {
246
+ ...result,
247
+ localDesignSystemId,
248
+ uploadedFileCount: files.length,
249
+ instructions: [
250
+ "Builder design-system indexing has started.",
251
+ `Builder design system: ${result.designSystemId}`,
252
+ `Local selectable design system: ${localDesignSystemId}`,
253
+ `Builder job: ${result.jobId}`,
254
+ `Open: ${result.builderUrl}`,
255
+ "Use the local design system id in Slides flows; Builder remains the source of truth for the indexed brand kit.",
256
+ ].join("\n"),
257
+ };
258
+ },
259
+ });
@@ -4,7 +4,6 @@ import {
4
4
  sendToAgentChat,
5
5
  openAgentSidebar,
6
6
  appApiPath,
7
- useFormatters,
8
7
  useT,
9
8
  } from "@agent-native/core/client";
10
9
  import {
@@ -18,6 +17,7 @@ import {
18
17
  IconFileDescription,
19
18
  IconPhoto,
20
19
  IconCheck,
20
+ IconExternalLink,
21
21
  } from "@tabler/icons-react";
22
22
  import { useState, useCallback, useEffect, useRef, useMemo } from "react";
23
23
 
@@ -108,14 +108,11 @@ export function DesignSystemSetup({
108
108
  const [figParsing, setFigParsing] = useState(false);
109
109
  const [figResult, setFigResult] = useState<FigImportResult | null>(null);
110
110
  const [figError, setFigError] = useState<string | null>(null);
111
- const [figTitle, setFigTitle] = useState("");
112
- const [figCreating, setFigCreating] = useState(false);
113
111
 
114
112
  const codeInputRef = useRef<HTMLInputElement>(null);
115
113
  const docInputRef = useRef<HTMLInputElement>(null);
116
114
  const imageInputRef = useRef<HTMLInputElement>(null);
117
115
  const figInputRef = useRef<HTMLInputElement>(null);
118
- const createSystemMutation = useActionMutation("create-design-system");
119
116
  const updateSystemMutation = useActionMutation("update-design-system");
120
117
 
121
118
  const { data: existingDs } = useActionQuery<{
@@ -164,8 +161,6 @@ export function DesignSystemSetup({
164
161
  setFigParsing(false);
165
162
  setFigResult(null);
166
163
  setFigError(null);
167
- setFigTitle("");
168
- setFigCreating(false);
169
164
  }
170
165
  }, [open]);
171
166
 
@@ -273,9 +268,6 @@ export function DesignSystemSetup({
273
268
  });
274
269
  const parsed = await readFigImportResponse(res);
275
270
  setFigResult(parsed);
276
- setFigTitle(
277
- parsed.suggestedTitle || t("designSystemSetup.importedBrand"),
278
- );
279
271
  } catch (err) {
280
272
  setFigError(
281
273
  err instanceof Error
@@ -286,37 +278,9 @@ export function DesignSystemSetup({
286
278
  setFigParsing(false);
287
279
  }
288
280
  },
289
- [],
281
+ [t],
290
282
  );
291
283
 
292
- const handleCreateFromFig = useCallback(async () => {
293
- if (!figResult) return;
294
- const title =
295
- figTitle.trim() ||
296
- figResult.suggestedTitle ||
297
- t("designSystemSetup.importedBrand");
298
- setFigCreating(true);
299
- try {
300
- await createSystemMutation.mutateAsync({
301
- title,
302
- data: JSON.stringify(figResult.data),
303
- customInstructions: figResult.customInstructions || "",
304
- } as any);
305
- toast({ title: t("designSystemSetup.figmaCreated") });
306
- onComplete();
307
- } catch (err) {
308
- setFigCreating(false);
309
- toast({
310
- title: t("designSystemSetup.createFailed"),
311
- description:
312
- err instanceof Error
313
- ? err.message
314
- : t("designSystemSetup.genericError"),
315
- variant: "destructive",
316
- });
317
- }
318
- }, [figResult, figTitle, createSystemMutation, onComplete, t]);
319
-
320
284
  const handleEditSave = async () => {
321
285
  if (!editingId) return;
322
286
  setGenerating(true);
@@ -371,7 +335,7 @@ export function DesignSystemSetup({
371
335
 
372
336
  if (githubLinks.length > 0) {
373
337
  parts.push(
374
- `\n## GitHub Repositories\nExtract design tokens from code. Call \`import-github\` for each:\n${githubLinks.map((l) => `- ${l.url}`).join("\n")}`,
338
+ `\n## GitHub Repositories\nStart Builder design-system indexing for each repository with \`index-design-system-with-builder\`:\n${githubLinks.map((l) => `- ${l.url}`).join("\n")}\n\nBuilder is the source of truth for repo/code design-system indexing. The action also creates a local selectable proxy design system for Slides flows. If Builder is not connected, stop and tell me to connect Builder from Settings.`,
375
339
  );
376
340
  }
377
341
 
@@ -379,7 +343,7 @@ export function DesignSystemSetup({
379
343
  const withContent = codeFiles.filter((f) => f.textContent);
380
344
  if (withContent.length > 0) {
381
345
  parts.push(
382
- `\n## Code Files (${withContent.length} files)\nCall \`import-code\` with these files:`,
346
+ `\n## Code Files (${withContent.length} files)\nStart Builder design-system indexing with \`index-design-system-with-builder\` using these files:`,
383
347
  );
384
348
  for (const f of withContent) {
385
349
  parts.push(
@@ -430,12 +394,12 @@ export function DesignSystemSetup({
430
394
 
431
395
  if (customInstructions.trim()) {
432
396
  parts.push(
433
- `\n## Custom Instructions (durable — store on the design system)\nWhen you call \`create-design-system\`, pass these verbatim as the \`customInstructions\` argument. They will be re-applied every time the design system is used to generate slides:\n\n${customInstructions.trim()}`,
397
+ `\n## Custom Instructions (durable — store on the design system)\nIf you create a local design system from non-Builder sources, pass these verbatim as the \`customInstructions\` argument. They will be re-applied every time the design system is used to generate slides:\n\n${customInstructions.trim()}`,
434
398
  );
435
399
  }
436
400
 
437
401
  parts.push(
438
- `\n---\nAfter processing all sources, call \`create-design-system\` with the combined tokens${
402
+ `\n---\nAfter processing all sources, if you started Builder design-system indexing, report the Builder job/design-system URL plus the local selectable design-system id returned by \`index-design-system-with-builder\`. Do not call \`create-design-system\` again for those Builder-indexed sources. If you processed non-Builder sources into concrete tokens, call \`create-design-system\` with the combined tokens${
439
403
  customInstructions.trim()
440
404
  ? " AND the verbatim --customInstructions string from above"
441
405
  : ""
@@ -543,14 +507,9 @@ export function DesignSystemSetup({
543
507
  ) : (
544
508
  <FigImportPreview
545
509
  result={figResult}
546
- title={figTitle}
547
- onTitleChange={setFigTitle}
548
- creating={figCreating}
549
- onCreate={handleCreateFromFig}
550
510
  onReset={() => {
551
511
  setFigResult(null);
552
512
  setFigError(null);
553
- setFigTitle("");
554
513
  }}
555
514
  />
556
515
  )}
@@ -885,148 +844,57 @@ function TagList({
885
844
 
886
845
  function FigImportPreview({
887
846
  result,
888
- title,
889
- onTitleChange,
890
- creating,
891
- onCreate,
892
847
  onReset,
893
848
  }: {
894
849
  result: FigImportResult;
895
- title: string;
896
- onTitleChange: (value: string) => void;
897
- creating: boolean;
898
- onCreate: () => void;
899
850
  onReset: () => void;
900
851
  }) {
901
852
  const t = useT();
902
- const { formatNumber } = useFormatters();
903
- const colors = result.data.colors;
904
- const colorEntries = (
905
- [
906
- [t("designSystemSetup.colorAccent"), "accent"],
907
- [t("designSystemSetup.colorPrimary"), "primary"],
908
- [t("designSystemSetup.colorSecondary"), "secondary"],
909
- [t("designSystemSetup.colorBackground"), "background"],
910
- [t("designSystemSetup.colorText"), "text"],
911
- ] as const
912
- ).filter(([, key]) => colors[key]);
913
- const typography = result.data.typography;
914
- const gradients = result.preview.gradients ?? [];
915
-
916
853
  return (
917
854
  <div className="space-y-4 rounded-lg border border-border bg-accent/40 p-4">
918
855
  <div className="flex items-start gap-3">
919
- {result.preview.thumbnailDataUrl ? (
920
- <img
921
- src={result.preview.thumbnailDataUrl}
922
- alt={t("designSystemSetup.figmaThumbnailAlt")}
923
- className="h-16 w-24 shrink-0 rounded-md border border-border object-cover"
924
- />
925
- ) : null}
856
+ <div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-[#609FF8]/10">
857
+ <IconBrandFigma className="h-5 w-5 text-[#609FF8]" />
858
+ </div>
926
859
  <div className="min-w-0 flex-1 space-y-1.5">
927
- <Label className="text-xs text-muted-foreground">
928
- {t("designSystemSetup.designSystemName")}
929
- </Label>
930
- <Input
931
- value={title}
932
- onChange={(event) => onTitleChange(event.target.value)}
933
- className="bg-card border-border text-foreground"
934
- placeholder={t("designSystemSetup.brandNamePlaceholder")}
935
- />
936
- <p className="text-[11px] text-muted-foreground">
937
- {t("designSystemSetup.figPreviewStats", {
938
- nodes: t("designSystemSetup.nodeCount", {
939
- count: result.preview.nodeCount,
940
- formattedCount: formatNumber(result.preview.nodeCount),
941
- }),
942
- gradients: t("designSystemSetup.gradientCount", {
943
- count: gradients.length,
944
- formattedCount: formatNumber(gradients.length),
945
- }),
946
- images: t("designSystemSetup.imageCount", {
947
- count: result.preview.imageCount,
948
- formattedCount: formatNumber(result.preview.imageCount),
949
- }),
860
+ <h4 className="text-sm font-medium text-foreground">
861
+ {t("designSystemSetup.builderIndexingStarted")}
862
+ </h4>
863
+ <p className="text-xs text-muted-foreground">
864
+ {t("designSystemSetup.builderIndexingDescription", {
865
+ title:
866
+ result.suggestedTitle || t("designSystemSetup.importedBrand"),
950
867
  })}
951
868
  </p>
952
869
  </div>
953
870
  </div>
954
871
 
955
- {colorEntries.length > 0 && (
956
- <div className="flex flex-wrap gap-3">
957
- {colorEntries.map(([label, key]) => (
958
- <div key={key} className="flex items-center gap-2">
959
- <div
960
- className="h-7 w-7 rounded-md border border-border"
961
- style={{ backgroundColor: colors[key] }}
962
- />
963
- <div className="text-xs">
964
- <div className="text-foreground/80">{label}</div>
965
- <div className="font-mono text-[10px] text-muted-foreground">
966
- {colors[key]}
967
- </div>
968
- </div>
969
- </div>
970
- ))}
971
- </div>
972
- )}
973
-
974
- {gradients.length > 0 && (
975
- <div className="flex flex-wrap gap-2">
976
- {gradients.slice(0, 4).map((gradient, index) => (
977
- <div
978
- key={index}
979
- className="h-8 w-24 rounded-md border border-border"
980
- style={{ backgroundImage: gradient }}
981
- title={gradient}
982
- />
983
- ))}
984
- </div>
985
- )}
986
-
987
- {(typography.headingFont || typography.bodyFont) && (
988
- <div className="text-xs text-foreground/80">
989
- {typography.headingFont && (
990
- <span>
991
- <span className="text-muted-foreground">
992
- {t("designSystemSetup.headingsLabel")}
993
- </span>{" "}
994
- {typography.headingFont}
995
- {typography.headingWeight ? ` ${typography.headingWeight}` : ""}
996
- </span>
997
- )}
998
- {typography.bodyFont && (
999
- <span className="ml-3">
1000
- <span className="text-muted-foreground">
1001
- {t("designSystemSetup.bodyLabel")}
1002
- </span>{" "}
1003
- {typography.bodyFont}
1004
- </span>
1005
- )}
1006
- </div>
1007
- )}
872
+ <dl className="grid grid-cols-[112px_minmax(0,1fr)] gap-x-3 gap-y-2 rounded-md border border-border bg-card/50 p-3 text-xs">
873
+ <dt className="text-muted-foreground">
874
+ {t("designSystemSetup.builderDesignSystemId")}
875
+ </dt>
876
+ <dd className="truncate font-mono text-foreground/80">
877
+ {result.designSystemId}
878
+ </dd>
879
+ <dt className="text-muted-foreground">
880
+ {t("designSystemSetup.builderJobId")}
881
+ </dt>
882
+ <dd className="truncate font-mono text-foreground/80">
883
+ {result.jobId}
884
+ </dd>
885
+ </dl>
1008
886
 
1009
887
  <div className="flex flex-wrap items-center gap-2 border-t border-border pt-3">
1010
- <Button
1011
- size="sm"
1012
- onClick={onCreate}
1013
- disabled={creating || !title.trim()}
1014
- className="cursor-pointer"
1015
- >
1016
- {creating ? (
1017
- <>
1018
- <IconLoader2 className="w-3.5 h-3.5 animate-spin" />
1019
- {t("designSystemSetup.creating")}
1020
- </>
1021
- ) : (
1022
- t("designSystemSetup.createDesignSystem")
1023
- )}
888
+ <Button size="sm" asChild className="cursor-pointer">
889
+ <a href={result.builderUrl} target="_blank" rel="noreferrer">
890
+ <IconExternalLink className="w-3.5 h-3.5" />
891
+ {t("designSystemSetup.openInBuilder")}
892
+ </a>
1024
893
  </Button>
1025
894
  <Button
1026
895
  size="sm"
1027
896
  variant="ghost"
1028
897
  onClick={onReset}
1029
- disabled={creating}
1030
898
  className="cursor-pointer"
1031
899
  >
1032
900
  {t("designSystemSetup.chooseAnotherFile")}
@@ -1,18 +1,13 @@
1
- import type { DesignSystemData } from "../../../shared/api";
2
-
3
1
  export interface FigImportResult {
4
2
  ok: boolean;
3
+ source: "builder";
5
4
  suggestedTitle: string;
6
- data: DesignSystemData;
7
- customInstructions: string;
8
- preview: {
9
- gradients: string[];
10
- palette: { hex: string; name?: string; count: number }[];
11
- namedColors: Record<string, string>;
12
- thumbnailDataUrl: string | null;
13
- nodeCount: number;
14
- imageCount: number;
15
- };
5
+ projectId: string;
6
+ jobId: string;
7
+ designSystemId: string;
8
+ builderUrl: string;
9
+ status: "in-progress";
10
+ builderConnectUrl?: string;
16
11
  }
17
12
 
18
13
  export const MAX_FIG_UPLOAD_BYTES = 200 * 1024 * 1024;
@@ -51,7 +46,8 @@ export async function readFigImportResponse(
51
46
  }
52
47
 
53
48
  if (json && typeof json === "object" && "error" in json) {
54
- const error = (json as { error?: unknown }).error;
49
+ const error = (json as { error?: unknown; builderConnectUrl?: unknown })
50
+ .error;
55
51
  throw new Error(
56
52
  typeof error === "string"
57
53
  ? error