@agent-native/core 0.153.9 → 0.154.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 (149) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/AGENTS.md +20 -30
  3. package/corpus/templates/analytics/actions/search-dashboard-references.ts +58 -0
  4. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +1 -1
  5. package/corpus/templates/analytics/app/lib/utils.ts +1 -1
  6. package/corpus/templates/analytics/app/pages/DataSources.tsx +2 -1
  7. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/ViewSqlPopover.tsx +1 -1
  8. package/corpus/templates/analytics/app/pages/monitoring/errors/IssueList.tsx +4 -2
  9. package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +4 -2
  10. package/corpus/templates/analytics/server/lib/agent-chat-plan-mode.ts +2 -0
  11. package/corpus/templates/analytics/server/lib/dashboards-store.ts +366 -3
  12. package/corpus/templates/analytics/server/lib/real-data-actions.ts +3 -1
  13. package/corpus/templates/analytics/server/plugins/agent-chat.ts +6 -2
  14. package/corpus/templates/calendar/app/components/calendar/EventDialog.tsx +1 -1
  15. package/corpus/templates/calendar/app/lib/utils.ts +1 -1
  16. package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +32 -5
  17. package/corpus/templates/clips/app/components/sharing/share-ui.tsx +15 -15
  18. package/corpus/templates/clips/app/i18n/en-US.ts +3 -3
  19. package/corpus/templates/clips/app/lib/utils.ts +5 -6
  20. package/corpus/templates/clips/app/root.tsx +4 -1
  21. package/corpus/templates/clips/app/routes/share.$shareId.tsx +2 -2
  22. package/corpus/templates/clips/chrome-extension/src/offscreen.ts +43 -8
  23. package/corpus/templates/clips/desktop/src/app.tsx +27 -13
  24. package/corpus/templates/clips/desktop/src/lib/recorder.ts +23 -9
  25. package/corpus/templates/clips/desktop/src-tauri/src/native_screen/custom_capture.rs +261 -11
  26. package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +21 -3
  27. package/corpus/templates/clips/shared/mic-audio-cleanup.ts +350 -0
  28. package/corpus/templates/content/app/i18n-data.ts +10 -10
  29. package/corpus/templates/content/scripts/check-native-deps.mjs +181 -15
  30. package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +79 -7
  31. package/corpus/templates/design/.agents/skills/design-systems/SKILL.md +14 -2
  32. package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +2 -2
  33. package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +35 -11
  34. package/corpus/templates/design/actions/get-design-system.ts +103 -3
  35. package/corpus/templates/design/actions/import-design-tokens.ts +37 -8
  36. package/corpus/templates/design/actions/import-github.ts +32 -138
  37. package/corpus/templates/design/actions/index-design-system-with-builder.ts +49 -16
  38. package/corpus/templates/design/actions/present-design-variants.ts +93 -4
  39. package/corpus/templates/design/actions/run-design-audit.ts +229 -0
  40. package/corpus/templates/design/actions/sync-design-system-with-builder.ts +64 -0
  41. package/corpus/templates/design/app/components/design/DesignImportPanel.tsx +2 -1
  42. package/corpus/templates/design/app/components/design/TweaksPanel.tsx +2 -1
  43. package/corpus/templates/design/app/components/design/code-workbench/commands.ts +2 -2
  44. package/corpus/templates/design/app/components/design/inspector/DesignColorPicker.tsx +17 -4
  45. package/corpus/templates/design/app/components/design/inspector/GradientEditor.tsx +5 -1
  46. package/corpus/templates/design/app/components/design/inspector/ImageFillControls.tsx +5 -1
  47. package/corpus/templates/design/app/hooks/use-question-flow.ts +81 -5
  48. package/corpus/templates/design/app/i18n/en-US.ts +1 -1
  49. package/corpus/templates/design/app/i18n-data.ts +32 -1
  50. package/corpus/templates/design/app/i18n-keyboard-shortcuts.ts +10 -10
  51. package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +83 -11
  52. package/corpus/templates/design/app/pages/DesignSystems.tsx +14 -0
  53. package/corpus/templates/design/app/pages/design-editor/generation-prompt-directives.ts +22 -0
  54. package/corpus/templates/design/changelog/2026-08-13-a-screen-that-would-render-behind-an-invisible-alpine-overla.md +6 -0
  55. package/corpus/templates/design/changelog/2026-08-13-attach-a-ui-screenshot-and-the-design-is-reproduced-not-rein.md +6 -0
  56. package/corpus/templates/design/changelog/2026-08-13-linking-a-design-system-means-you-never-get-generic-directio.md +6 -0
  57. package/corpus/templates/design/changelog/2026-08-13-the-design-audit-now-reports-when-a-screen-ignores-its-linke.md +6 -0
  58. package/corpus/templates/design/changelog/2026-08-13-the-design-system-preview-now-shows-how-many-named-tokens-we.md +6 -0
  59. package/corpus/templates/design/changelog/2026-08-13-your-design-system-prompt-and-reference-screenshots-now-reac.md +6 -0
  60. package/corpus/templates/design/server/lib/builder-design-system-proxy.ts +18 -2
  61. package/corpus/templates/design/shared/design-review.ts +1 -0
  62. package/corpus/templates/design/shared/html-integrity.ts +171 -0
  63. package/corpus/templates/mail/app/lib/utils.ts +1 -1
  64. package/corpus/templates/plan/app/pages/PlansPage.tsx +5 -2
  65. package/corpus/templates/slides/.agents/skills/design-systems/SKILL.md +10 -6
  66. package/corpus/templates/slides/actions/index-design-system-with-builder.ts +41 -3
  67. package/corpus/templates/slides/actions/sync-design-system-with-builder.ts +64 -0
  68. package/corpus/templates/slides/app/components/deck/DeckCard.tsx +1 -1
  69. package/corpus/templates/slides/app/components/design-system/DesignSystemSetup.tsx +193 -20
  70. package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +58 -33
  71. package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +28 -41
  72. package/corpus/templates/slides/app/components/editor/ExportMenu.tsx +119 -91
  73. package/corpus/templates/slides/app/components/editor/ImageOverlay.tsx +16 -0
  74. package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +158 -31
  75. package/corpus/templates/slides/app/components/editor/SlideOverflowWarning.tsx +30 -14
  76. package/corpus/templates/slides/app/components/editor/SpeakerNotesPanel.tsx +2 -2
  77. package/corpus/templates/slides/app/components/editor/canvas-interactions/slides-canvas-adapter.ts +4 -1
  78. package/corpus/templates/slides/app/components/editor/rich-text-selection.ts +14 -0
  79. package/corpus/templates/slides/app/components/editor/slide-text-targets.ts +24 -0
  80. package/corpus/templates/slides/app/global.css +24 -0
  81. package/corpus/templates/slides/app/hooks/use-navigation-state.ts +5 -1
  82. package/corpus/templates/slides/app/i18n/en-US.ts +19 -10
  83. package/corpus/templates/slides/app/lib/deck-filter.ts +47 -0
  84. package/corpus/templates/slides/app/lib/export-google-slides-client.ts +15 -4
  85. package/corpus/templates/slides/app/lib/export-pptx-client.ts +637 -1
  86. package/corpus/templates/slides/app/lib/image-download.ts +84 -0
  87. package/corpus/templates/slides/app/lib/utils.ts +1 -1
  88. package/corpus/templates/slides/app/pages/Index.tsx +25 -9
  89. package/corpus/templates/slides/netlify.toml +1 -0
  90. package/corpus/templates/slides/server/lib/builder-design-system-proxy.ts +14 -2
  91. package/dist/agent/production-agent.js +1 -1
  92. package/dist/brand-kit/types.d.ts +10 -2
  93. package/dist/cli/code.js +1 -1
  94. package/dist/cli/index.js +30 -1
  95. package/dist/cli/native-dependencies.d.ts +24 -0
  96. package/dist/cli/native-dependencies.js +264 -0
  97. package/dist/cli/plan-local.js +1 -1
  98. package/dist/cli/skills-content/design-visual-edit-skill.d.ts +1 -1
  99. package/dist/cli/skills-content/design-visual-edit-skill.js +2 -2
  100. package/dist/cli/skills-content/help.d.ts +1 -1
  101. package/dist/cli/skills-content/help.js +2 -1
  102. package/dist/cli/skills.js +2 -1
  103. package/dist/cli/visualize-repo.js +1 -1
  104. package/dist/client/FeedbackButton.js +12 -12
  105. package/dist/client/NewWorkspaceAppFlow.js +4 -1
  106. package/dist/client/agent-chat-adapter.js +3 -4
  107. package/dist/client/agent-page/AgentTabsPage.d.ts +2 -2
  108. package/dist/client/agent-page/AgentTabsPage.js +12 -9
  109. package/dist/client/assistant-ui-recovery.d.ts +1 -1
  110. package/dist/client/assistant-ui-recovery.js +4 -0
  111. package/dist/client/chat/message-components.d.ts +11 -3
  112. package/dist/client/chat/message-components.js +31 -5
  113. package/dist/client/chat/tool-call-display.d.ts +2 -1
  114. package/dist/client/chat/tool-call-display.js +33 -15
  115. package/dist/client/db-admin/SqlEditor.js +1 -1
  116. package/dist/client/dev-overlay/DevOverlay.js +2 -2
  117. package/dist/client/extensions/ExtensionsSidebarSection.js +2 -1
  118. package/dist/client/extensions/portable-extension.js +4 -0
  119. package/dist/client/guided-questions.d.ts +8 -0
  120. package/dist/client/guided-questions.js +12 -3
  121. package/dist/client/onboarding/FirstRunOnboarding.js +2 -1
  122. package/dist/client/org/TeamPage.js +14 -3
  123. package/dist/client/settings/SettingsPanel.js +26 -1
  124. package/dist/client/sharing/ShareButton.js +16 -24
  125. package/dist/client/sse-event-processor.js +35 -15
  126. package/dist/client/tool-display.d.ts +9 -0
  127. package/dist/client/tool-display.js +39 -0
  128. package/dist/client/vite-dev-recovery-script.js +1 -1
  129. package/dist/extensions/html-shell.js +5 -0
  130. package/dist/integrations/catalog.js +9 -8
  131. package/dist/observability/routes.d.ts +2 -2
  132. package/dist/secrets/routes.d.ts +6 -6
  133. package/dist/server/agent-chat/prompt-resources.js +17 -16
  134. package/dist/server/agent-chat-plugin.d.ts +9 -0
  135. package/dist/server/agent-chat-plugin.js +31 -9
  136. package/dist/server/builder-design-systems.d.ts +33 -1
  137. package/dist/server/builder-design-systems.js +293 -11
  138. package/dist/server/design-token-utils.d.ts +11 -0
  139. package/dist/server/design-token-utils.js +68 -16
  140. package/dist/server/index.d.ts +1 -1
  141. package/dist/server/index.js +1 -1
  142. package/dist/server/onboarding-html.js +2 -1
  143. package/dist/shared/docs-url.d.ts +24 -0
  144. package/dist/shared/docs-url.js +39 -0
  145. package/dist/shared/index.d.ts +1 -0
  146. package/dist/shared/index.js +1 -0
  147. package/dist/templates/default/app/routes/_index.tsx +2 -1
  148. package/package.json +2 -2
  149. package/src/templates/default/app/routes/_index.tsx +2 -1
@@ -43,6 +43,8 @@ import { cn } from "@/lib/utils";
43
43
  interface GitHubLink {
44
44
  id: string;
45
45
  url: string;
46
+ ref?: string;
47
+ include?: string[];
46
48
  }
47
49
 
48
50
  interface UploadedFile {
@@ -73,6 +75,12 @@ interface BuilderIndexInput {
73
75
  projectName?: string;
74
76
  description?: string;
75
77
  githubRepoUrl?: string;
78
+ githubSources?: Array<{
79
+ repoUrl: string;
80
+ ref?: string;
81
+ include?: string[];
82
+ exclude?: string[];
83
+ }>;
76
84
  connectedProjectId?: string;
77
85
  codeFiles?: Array<{
78
86
  filename: string;
@@ -93,6 +101,8 @@ export default function DesignSystemSetup() {
93
101
  const [websiteUrl, setWebsiteUrl] = useState("");
94
102
  const [websiteUrls, setWebsiteUrls] = useState<string[]>([]);
95
103
  const [githubUrl, setGithubUrl] = useState("");
104
+ const [githubRef, setGithubRef] = useState("");
105
+ const [githubPaths, setGithubPaths] = useState("");
96
106
  const [githubLinks, setGithubLinks] = useState<GitHubLink[]>([]);
97
107
  const [codeFiles, setCodeFiles] = useState<UploadedFile[]>([]);
98
108
  const [docFiles, setDocFiles] = useState<UploadedFile[]>([]);
@@ -308,10 +318,24 @@ export default function DesignSystemSetup() {
308
318
  setValidationError(t("designSystemSetup.errors.githubUrl"));
309
319
  return;
310
320
  }
311
- setGithubLinks((prev) => [...prev, { id: crypto.randomUUID(), url }]);
321
+ const include = githubPaths
322
+ .split(/[\n,]/)
323
+ .map((path) => path.trim().replace(/^\/+|\/+$/g, ""))
324
+ .filter(Boolean);
325
+ setGithubLinks((prev) => [
326
+ ...prev,
327
+ {
328
+ id: crypto.randomUUID(),
329
+ url,
330
+ ...(githubRef.trim() ? { ref: githubRef.trim() } : {}),
331
+ ...(include.length > 0 ? { include: [...new Set(include)] } : {}),
332
+ },
333
+ ]);
312
334
  setGithubUrl("");
335
+ setGithubRef("");
336
+ setGithubPaths("");
313
337
  setValidationError(null);
314
- }, [githubUrl, t]);
338
+ }, [githubPaths, githubRef, githubUrl, t]);
315
339
 
316
340
  const removeGithubLink = useCallback((id: string) => {
317
341
  setGithubLinks((prev) => prev.filter((l) => l.id !== id));
@@ -441,12 +465,26 @@ export default function DesignSystemSetup() {
441
465
  const normalizedWebsiteUrls = pendingWebsiteUrl
442
466
  ? [...websiteUrls, pendingWebsiteUrl]
443
467
  : websiteUrls;
468
+ const pendingGithubInclude = githubPaths
469
+ .split(/[\n,]/)
470
+ .map((path) => path.trim().replace(/^\/+|\/+$/g, ""))
471
+ .filter(Boolean);
444
472
  const normalizedGithubLinks = pendingGithubUrl
445
- ? [...githubLinks, { id: "pending", url: pendingGithubUrl }]
473
+ ? [
474
+ ...githubLinks,
475
+ {
476
+ id: "pending",
477
+ url: pendingGithubUrl,
478
+ ...(githubRef.trim() ? { ref: githubRef.trim() } : {}),
479
+ ...(pendingGithubInclude.length > 0
480
+ ? { include: [...new Set(pendingGithubInclude)] }
481
+ : {}),
482
+ },
483
+ ]
446
484
  : githubLinks;
447
485
 
448
- const isSingleGithubSource =
449
- normalizedGithubLinks.length === 1 &&
486
+ const isGithubOnlySource =
487
+ normalizedGithubLinks.length > 0 &&
450
488
  normalizedWebsiteUrls.length === 0 &&
451
489
  codeFiles.length === 0 &&
452
490
  !builderIndexResult &&
@@ -455,10 +493,7 @@ export default function DesignSystemSetup() {
455
493
  assets.length === 0 &&
456
494
  !selectedProjectId;
457
495
 
458
- if (isSingleGithubSource) {
459
- const githubRepoUrl = normalizedGithubLinks[0]?.url;
460
- if (!githubRepoUrl) return;
461
-
496
+ if (isGithubOnlySource) {
462
497
  setValidationError(null);
463
498
  try {
464
499
  await indexSystemMutation.mutateAsync({
@@ -467,7 +502,11 @@ export default function DesignSystemSetup() {
467
502
  [notes.trim(), customInstructions.trim()]
468
503
  .filter(Boolean)
469
504
  .join("\n\n") || undefined,
470
- githubRepoUrl,
505
+ githubSources: normalizedGithubLinks.map((link) => ({
506
+ repoUrl: link.url,
507
+ ...(link.ref ? { ref: link.ref } : {}),
508
+ ...(link.include?.length ? { include: link.include } : {}),
509
+ })),
471
510
  });
472
511
  toast.success(t("designSystemSetup.githubIndexStarted"));
473
512
  navigate("/design-systems");
@@ -507,7 +546,15 @@ export default function DesignSystemSetup() {
507
546
 
508
547
  if (normalizedGithubLinks.length > 0) {
509
548
  parts.push(
510
- `\n## Connect Code: GitHub Repositories\nStart Builder DSI indexing for each repository with \`index-design-system-with-builder\`:\n${normalizedGithubLinks.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 Design flows. If Builder is not connected, stop and tell me to connect Builder (free tier available) from Settings instead of asking me to paste repository credentials into chat.`,
549
+ `\n## Connect Code: GitHub Repositories\nMake one call to \`index-design-system-with-builder\` with \`githubSources\` set to this JSON array:\n\n\`\`\`json\n${JSON.stringify(
550
+ normalizedGithubLinks.map((link) => ({
551
+ repoUrl: link.url,
552
+ ...(link.ref ? { ref: link.ref } : {}),
553
+ ...(link.include?.length ? { include: link.include } : {}),
554
+ })),
555
+ null,
556
+ 2,
557
+ )}\n\`\`\`\n\nBuilder is the source of truth for repo/code design-system indexing. The action creates one local selectable proxy design system for Design flows. If Builder is not connected, stop and tell me to connect Builder (free tier available) from Settings instead of asking me to paste repository credentials into chat.`,
511
558
  );
512
559
  }
513
560
 
@@ -629,6 +676,8 @@ export default function DesignSystemSetup() {
629
676
  websiteUrl,
630
677
  websiteUrls,
631
678
  githubUrl,
679
+ githubRef,
680
+ githubPaths,
632
681
  githubLinks,
633
682
  codeFiles,
634
683
  builderIndexResult,
@@ -935,6 +984,22 @@ export default function DesignSystemSetup() {
935
984
  {t("designSystemSetup.add")}
936
985
  </Button>
937
986
  </div>
987
+ <div className="grid gap-2 sm:grid-cols-2">
988
+ <Input
989
+ value={githubRef}
990
+ onChange={(e) => setGithubRef(e.target.value)}
991
+ placeholder={t("designSystemSetup.githubRef")}
992
+ aria-label={t("designSystemSetup.githubRef")}
993
+ className="bg-accent/50 border-border"
994
+ />
995
+ <Input
996
+ value={githubPaths}
997
+ onChange={(e) => setGithubPaths(e.target.value)}
998
+ placeholder={t("designSystemSetup.githubPaths")}
999
+ aria-label={t("designSystemSetup.githubPaths")}
1000
+ className="bg-accent/50 border-border"
1001
+ />
1002
+ </div>
938
1003
  <p className="mt-2 text-xs text-muted-foreground/80">
939
1004
  {t("designSystemSetup.privateRepoPrefix")}{" "}
940
1005
  <a
@@ -954,6 +1019,13 @@ export default function DesignSystemSetup() {
954
1019
  >
955
1020
  <IconCheck className="w-3.5 h-3.5 text-green-400/60 shrink-0" />
956
1021
  <span className="truncate flex-1">{link.url}</span>
1022
+ {link.ref || link.include?.length ? (
1023
+ <span className="shrink-0 text-[10px] text-muted-foreground/70">
1024
+ {[link.ref, link.include?.join(", ")]
1025
+ .filter(Boolean)
1026
+ .join(" · ")}
1027
+ </span>
1028
+ ) : null}
957
1029
  <button
958
1030
  onClick={() => removeGithubLink(link.id)}
959
1031
  className="text-muted-foreground/70 hover:text-muted-foreground shrink-0 cursor-pointer"
@@ -109,6 +109,8 @@ interface DesignSystemData {
109
109
  logos?: Array<{ url?: string; name?: string; variant?: string }>;
110
110
  defaults?: Record<string, unknown>;
111
111
  notes?: unknown;
112
+ /** The source system's own named vocabulary; absent on kits predating it. */
113
+ tokens?: unknown;
112
114
  }
113
115
 
114
116
  export default function DesignSystems() {
@@ -1105,10 +1107,22 @@ function getDetailTokens(
1105
1107
  const borders = data?.borders ?? {};
1106
1108
  const defaults = data?.defaults ?? {};
1107
1109
  const logos = data?.logos ?? [];
1110
+ const namedTokenCount = Array.isArray(data?.tokens) ? data.tokens.length : 0;
1108
1111
  return [
1109
1112
  ...objectPreviewItems(t("designSystems.tokenPreview.spacing"), spacing),
1110
1113
  ...objectPreviewItems(t("designSystems.tokenPreview.borders"), borders),
1111
1114
  ...objectPreviewItems(t("designSystems.tokenPreview.defaults"), defaults),
1115
+ // The seven color roles are a summary of an import, not its extent. Without
1116
+ // this the panel renders a 200-token system identically to a 7-token one,
1117
+ // which reads as "it only captured a few colors".
1118
+ namedTokenCount > 0
1119
+ ? {
1120
+ label: t("designSystems.tokenPreview.namedTokens"),
1121
+ value: t("designSystems.tokenPreview.savedCount", {
1122
+ count: namedTokenCount,
1123
+ }),
1124
+ }
1125
+ : null,
1112
1126
  logos.length > 0
1113
1127
  ? {
1114
1128
  label: t("designSystems.tokenPreview.logos"),
@@ -121,10 +121,12 @@ export async function loadDesignSystemGenerationContext(
121
121
  export function designIntakeQuestionDirectives(
122
122
  designId: string,
123
123
  designSystemId?: string | null,
124
+ referenceImageCount = 0,
124
125
  ): string[] {
125
126
  return [
126
127
  `This is a new UI-started design for design id "${designId}". The design shell already exists - DO NOT call create-design.`,
127
128
  ...designSystemGenerationDirectives(designSystemId),
129
+ ...referenceImageDirectives(referenceImageCount),
128
130
  "First, call `show-design-questions` with 4-6 tailored questions and then stop. Do NOT call generate-design or present-design-variants until the user submits or skips the questions.",
129
131
  "Make the questions feel like Claude Design intake: form factor, aesthetic direction, important features/content, special interactions/polish, and whether to explore variations. Omit or rephrase anything the user's prompt already answered.",
130
132
  "Use concise option chips with `allowOther: true`; include a practical `Decide for me` option where useful. Use `multiSelect: true` for feature/interactions questions.",
@@ -159,13 +161,33 @@ export function designVariantGenerationDirectives(
159
161
  ];
160
162
  }
161
163
 
164
+ /**
165
+ * An attached UI screenshot is the specification. Reproducing it is the whole
166
+ * job, so these directives ship in the same prompt as the image — the skill
167
+ * body is not in the system prompt and loses every conflict against directives
168
+ * that are.
169
+ */
170
+ export function referenceImageDirectives(
171
+ referenceImageCount: number,
172
+ ): string[] {
173
+ if (referenceImageCount < 1) return [];
174
+ return [
175
+ `The user attached ${referenceImageCount} reference image(s) to this message. Treat any image showing a UI as a layout specification to reproduce, not as loose inspiration.`,
176
+ "Match its regions and their positions, navigation pattern, information hierarchy, density, component grammar (tabs vs pills, cards vs rows, sidebar vs topbar), and approximate proportions. Briefly name what you see before building so a misread can be corrected early.",
177
+ "Do NOT substitute your own composition, palette, or font for something the image or the linked design system already specifies — including choices a generic quality heuristic would discourage. Deviate only where the image is genuinely unreadable, and say so when you do.",
178
+ "Do NOT call `show-design-questions` or `present-design-variants` about anything the image already answers; the direction is chosen. Generate the one design it specifies.",
179
+ ];
180
+ }
181
+
162
182
  export function designGenerationDirectives(
163
183
  designId: string,
164
184
  designSystemId?: string | null,
185
+ referenceImageCount = 0,
165
186
  ): string[] {
166
187
  return [
167
188
  `Use the \`generate-design --designId="${designId}"\` action with exactly one complete, renderable \`index.html\` file first. The design already exists - DO NOT call create-design.`,
168
189
  ...designSystemGenerationDirectives(designSystemId),
190
+ ...referenceImageDirectives(referenceImageCount),
169
191
  'If the user asked to explore variations, call `present-design-variants` with 2-5 concise directions. Prefer label, description, accentColor, and feature bullets; omit large content HTML when needed because the action can render compact representative screens. Wait for their chat pick, delete each unchosen variant screen at most once, call `get-design-snapshot` exactly once with `fileId` for the kept screen, then call `edit-design` exactly once on that same `fileId` in a bounded pass. Use `mode: "replace-file"` when expanding the representative placeholder into a complete but compact product UI in the chosen direction. Prioritize the primary workflow and render secondary details as visible controls, states, or affordances if the feature list is too large for one reliable edit. Do not repeat delete/snapshot cycles. Do not call `generate-design` after a variant pick. Stop after the first successful `edit-design` save. Otherwise generate one polished first direction.',
170
192
  'Responsive behavior is mandatory for every web design: use a mobile-first layout, include a viewport meta tag, stack or collapse desktop columns at narrow widths, and never rely on a fixed-width desktop shell. Default to a desktop primary artboard. For a Desktop or Both/responsive intake answer, pass `primaryViewport: "desktop"` and `canvasFrames` with width 1440 and height 1024; pass `primaryViewport: "mobile"` only when the user explicitly chooses a mobile-primary artboard.',
171
193
  "Keep the first pass bounded enough to finish quickly: one self-contained Alpine.js + Tailwind CDN HTML document, polished but concise. Add 3-6 tweaks only when they naturally fit the design.",
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-08-13
4
+ ---
5
+
6
+ A screen whose Alpine overlay would cover it on load — `x-cloak` without its hiding rule, or a broken Alpine script URL — is now caught when it is saved instead of shipping as a blank or covered design.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-08-13
4
+ ---
5
+
6
+ Attach a UI screenshot and the design is reproduced from it instead of being reinterpreted as three alternative directions.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-08-13
4
+ ---
5
+
6
+ Linking a design system means you never get generic direction cards: exploring variants without real HTML is now refused for that design rather than rendering placeholder screens that ignore your tokens.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: added
3
+ date: 2026-08-13
4
+ ---
5
+
6
+ The design audit now reports when a screen uses none of its linked design system's fonts, colors, or token names.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-08-13
4
+ ---
5
+
6
+ The design system preview now shows how many named tokens were captured, so a large imported system no longer looks like a handful of colors.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-08-13
4
+ ---
5
+
6
+ Your design system, original prompt, and reference screenshots now reach the turn that actually generates the design, instead of being spent on the questions step.
@@ -2,6 +2,8 @@ import {
2
2
  createBuilderDesignSystemProxyFields,
3
3
  localBuilderDesignSystemId,
4
4
  type BuilderDesignSystemIndexResult,
5
+ type BuilderDesignSystemGitHubSource,
6
+ type BuilderDesignSystemSourceKind,
5
7
  } from "@agent-native/core/server";
6
8
  import { and, eq, isNull } from "drizzle-orm";
7
9
  import { nanoid } from "nanoid";
@@ -14,12 +16,18 @@ export async function upsertBuilderProxyDesignSystem({
14
16
  orgId,
15
17
  projectName,
16
18
  description,
19
+ sourceKind,
20
+ githubSources,
21
+ localDesignSystemId: requestedLocalDesignSystemId,
17
22
  }: {
18
23
  result: BuilderDesignSystemIndexResult;
19
24
  ownerEmail: string;
20
25
  orgId?: string | null;
21
26
  projectName?: string;
22
27
  description?: string;
28
+ sourceKind?: BuilderDesignSystemSourceKind;
29
+ githubSources?: BuilderDesignSystemGitHubSource[];
30
+ localDesignSystemId?: string;
23
31
  }) {
24
32
  const db = getDb();
25
33
  const now = new Date().toISOString();
@@ -31,6 +39,9 @@ export async function upsertBuilderProxyDesignSystem({
31
39
  projectName,
32
40
  description,
33
41
  surface: "design",
42
+ sourceKind,
43
+ githubSources,
44
+ syncedAt: githubSources?.length ? now : undefined,
34
45
  });
35
46
  const [existing] = await db
36
47
  .select({
@@ -39,7 +50,12 @@ export async function upsertBuilderProxyDesignSystem({
39
50
  orgId: schema.designSystems.orgId,
40
51
  })
41
52
  .from(schema.designSystems)
42
- .where(eq(schema.designSystems.id, baseLocalDesignSystemId))
53
+ .where(
54
+ eq(
55
+ schema.designSystems.id,
56
+ requestedLocalDesignSystemId ?? baseLocalDesignSystemId,
57
+ ),
58
+ )
43
59
  .limit(1);
44
60
  const existingBelongsToScope =
45
61
  existing?.ownerEmail === ownerEmail &&
@@ -47,7 +63,7 @@ export async function upsertBuilderProxyDesignSystem({
47
63
  const localDesignSystemId =
48
64
  existing && !existingBelongsToScope
49
65
  ? `${baseLocalDesignSystemId}-${nanoid(8)}`
50
- : baseLocalDesignSystemId;
66
+ : (requestedLocalDesignSystemId ?? baseLocalDesignSystemId);
51
67
  if (existingBelongsToScope) {
52
68
  await db
53
69
  .update(schema.designSystems)
@@ -24,6 +24,7 @@ export const A11Y_FINDING_CATEGORIES = [
24
24
  "reduced-motion",
25
25
  "role",
26
26
  "token-drift",
27
+ "design-system-drift",
27
28
  "other",
28
29
  ] as const;
29
30
 
@@ -32,6 +32,8 @@ export type DesignHtmlIntegrityIssue =
32
32
  | "close-tag-orphaned"
33
33
  | "content-truncated"
34
34
  | "runtime-missing"
35
+ | "runtime-alpine-missing"
36
+ | "runtime-cloak-missing"
35
37
  | "url-backed-screen-replaced";
36
38
 
37
39
  /**
@@ -86,6 +88,10 @@ const DOCUMENT_SHAPE_MESSAGES: Partial<
86
88
  "an editor-managed <style>/<script> block appears more than once; there must be exactly one of each",
87
89
  "url-backed-screen-replaced":
88
90
  "this screen's content is its live route URL, and the write would replace it with document markup — that permanently unbinds the screen from the running app. Edit the app's own source instead",
91
+ "runtime-cloak-missing":
92
+ "this document uses x-cloak without the CSS rule that keeps Alpine-controlled content hidden before Alpine starts",
93
+ "runtime-alpine-missing":
94
+ "this document uses x-cloak but does not load Alpine.js, so the hidden state can never be removed",
89
95
  };
90
96
 
91
97
  export function describeDesignHtmlIntegrityIssue(
@@ -141,6 +147,19 @@ export function describeDesignHtmlIntegrityIssue(
141
147
  `<script src="…@tailwindcss/browser@4"> or a <style type="text/tailwindcss">). ` +
142
148
  `Utility classes will not apply and the design renders unstyled.`
143
149
  );
150
+ case "runtime-alpine-missing":
151
+ return (
152
+ `the document uses x-cloak on <${detail.tag ?? "element"}> at ${at}, ` +
153
+ `but no script source contains Alpine.js. The element will remain ` +
154
+ `hidden forever; load Alpine.js before relying on x-cloak.`
155
+ );
156
+ case "runtime-cloak-missing":
157
+ return (
158
+ `the document uses x-cloak on <${detail.tag ?? "element"}> at ${at}, ` +
159
+ `but no style block defines [x-cloak] { display: none !important; }. ` +
160
+ `Alpine-controlled overlays can flash or cover the entire screen before ` +
161
+ `Alpine starts. Add that exact hiding rule to the document.`
162
+ );
144
163
  default:
145
164
  return `the document structure is invalid (${detail.issue}) at ${at}.`;
146
165
  }
@@ -1077,6 +1096,85 @@ function collectManagedMarkerIssue(
1077
1096
  return null;
1078
1097
  }
1079
1098
 
1099
+ /**
1100
+ * The selector may sit anywhere in a comma-separated list, and any of the three
1101
+ * hidings below is a correct pre-Alpine hide. Matching only
1102
+ * `[x-cloak] { display: none }` rejects documents that render perfectly.
1103
+ */
1104
+ const X_CLOAK_RULE =
1105
+ /\[x-cloak\][^{}]*\{[^}]*(?:display\s*:\s*none|visibility\s*:\s*hidden|@apply[^;}]*\bhidden\b)/i;
1106
+ const ALPINE_RUNTIME = /\balpinejs\b/i;
1107
+ const INLINE_PRE_HIDE = /(?:display\s*:\s*none|visibility\s*:\s*hidden)/i;
1108
+
1109
+ /**
1110
+ * `x-cloak` is an Alpine convention, not a runtime feature: it only works
1111
+ * when the authored document also supplies the CSS rule that hides the node
1112
+ * before Alpine initializes. A missing rule is especially dangerous for
1113
+ * fixed overlays, which can make a correct screen look completely replaced.
1114
+ */
1115
+ function collectInteractiveRuntimeIssues(
1116
+ parsed: ParsedDocument,
1117
+ locate: Locator,
1118
+ ): DesignHtmlIntegrityIssueDetail[] {
1119
+ const cloaked = parsed.elements.find((element) =>
1120
+ element.attrs.some(
1121
+ (attribute) => attribute.name.toLowerCase() === "x-cloak",
1122
+ ),
1123
+ );
1124
+ if (!cloaked) return [];
1125
+
1126
+ const hasAlpineRuntime = parsed.elements.some(
1127
+ (element) =>
1128
+ element.tagName === "script" &&
1129
+ ALPINE_RUNTIME.test(attributeOf(element, "src") ?? ""),
1130
+ );
1131
+
1132
+ // A linked stylesheet is content this parser cannot read, so its rules are
1133
+ // unknown — not missing. Reporting "no rule defined" here would be the
1134
+ // coercion this whole module exists to prevent.
1135
+ const hasUnreadableStylesheet = parsed.elements.some(
1136
+ (element) =>
1137
+ element.tagName === "link" &&
1138
+ /\bstylesheet\b/i.test(attributeOf(element, "rel") ?? "") &&
1139
+ (attributeOf(element, "href") ?? "").trim().length > 0,
1140
+ );
1141
+
1142
+ const hasCloakRule =
1143
+ hasUnreadableStylesheet ||
1144
+ INLINE_PRE_HIDE.test(attributeOf(cloaked, "style") ?? "") ||
1145
+ parsed.elements.some((element) => {
1146
+ if (element.tagName !== "style") return false;
1147
+ const css = childrenOf(element)
1148
+ .filter((node) => node.nodeName === "#text")
1149
+ .map((node) => (node as DefaultTreeAdapterTypes.TextNode).value)
1150
+ .join("\n");
1151
+ return X_CLOAK_RULE.test(css);
1152
+ });
1153
+
1154
+ const attribute = cloaked.attrs.find(
1155
+ (entry) => entry.name.toLowerCase() === "x-cloak",
1156
+ );
1157
+ const offset =
1158
+ locationOf(cloaked)?.attrs?.[attribute?.name ?? ""]?.startOffset ??
1159
+ locationOf(cloaked)?.startOffset ??
1160
+ 0;
1161
+ const detail = {
1162
+ line: locate(offset).line,
1163
+ column: locate(offset).column,
1164
+ excerpt: locate(offset).excerpt,
1165
+ tag: cloaked.tagName,
1166
+ attribute: "x-cloak",
1167
+ };
1168
+ return [
1169
+ ...(hasAlpineRuntime
1170
+ ? []
1171
+ : [{ issue: "runtime-alpine-missing" as const, ...detail }]),
1172
+ ...(hasCloakRule
1173
+ ? []
1174
+ : [{ issue: "runtime-cloak-missing" as const, ...detail }]),
1175
+ ];
1176
+ }
1177
+
1080
1178
  /**
1081
1179
  * Reported, never enforced: legitimate fragments and token-only screens carry no
1082
1180
  * runtime of their own, so blocking here would reject valid work.
@@ -1142,10 +1240,45 @@ export function inspectDesignHtmlDocumentIntegrity(
1142
1240
  const marker = collectManagedMarkerIssue(parsed);
1143
1241
  if (marker) return { valid: false, issue: marker };
1144
1242
 
1243
+ const interactiveRuntime = collectInteractiveRuntimeIssues(parsed, locate);
1244
+ if (interactiveRuntime.length > 0) {
1245
+ return {
1246
+ valid: false,
1247
+ issue: interactiveRuntime[0]!.issue,
1248
+ detail: interactiveRuntime,
1249
+ };
1250
+ }
1251
+
1145
1252
  const advisory = collectAdvisoryIssues(parsed, locate);
1146
1253
  return advisory.length > 0 ? { valid: true, advisory } : { valid: true };
1147
1254
  }
1148
1255
 
1256
+ const RUNTIME_ISSUES: ReadonlySet<DesignHtmlIntegrityIssue> = new Set([
1257
+ "runtime-alpine-missing",
1258
+ "runtime-cloak-missing",
1259
+ ]);
1260
+
1261
+ /**
1262
+ * The runtime issues are the one class an edit may carry forward. A screen
1263
+ * saved before these checks existed still renders, and the person dragging on
1264
+ * the canvas did not author its markup and cannot add a CSS rule — refusing
1265
+ * their unrelated edit strands the screen. Block what the edit introduces;
1266
+ * the create path still refuses to author the defect in the first place.
1267
+ */
1268
+ function introducedRuntimeIssues(
1269
+ next: DesignHtmlIntegrityIssueDetail[],
1270
+ previousContent: string,
1271
+ ): DesignHtmlIntegrityIssueDetail[] {
1272
+ if (next.length === 0 || !previousContent.trim()) return next;
1273
+ const inherited = new Set(
1274
+ collectInteractiveRuntimeIssues(
1275
+ parseDocument(previousContent),
1276
+ createLocator(previousContent),
1277
+ ).map((entry) => entry.issue),
1278
+ );
1279
+ return next.filter((entry) => !inherited.has(entry.issue));
1280
+ }
1281
+
1149
1282
  /**
1150
1283
  * Fail closed only for document edits. Standalone Alpine fragments remain
1151
1284
  * supported. Existing malformed documents can still be repaired: a candidate
@@ -1186,6 +1319,19 @@ export function assertDesignHtmlEditIntegrity(args: {
1186
1319
  detail: structural,
1187
1320
  });
1188
1321
  }
1322
+ const interactiveRuntime = introducedRuntimeIssues(
1323
+ collectInteractiveRuntimeIssues(
1324
+ parseDocument(args.nextContent),
1325
+ createLocator(args.nextContent),
1326
+ ),
1327
+ args.previousContent,
1328
+ );
1329
+ if (interactiveRuntime.length > 0) {
1330
+ throw new DesignHtmlIntegrityError(interactiveRuntime[0]!.issue, {
1331
+ filename: args.filename,
1332
+ detail: interactiveRuntime,
1333
+ });
1334
+ }
1189
1335
  return;
1190
1336
  }
1191
1337
  if (previousIsDocument && !nextIsDocument) {
@@ -1195,6 +1341,17 @@ export function assertDesignHtmlEditIntegrity(args: {
1195
1341
  }
1196
1342
  const result = inspectDesignHtmlDocumentIntegrity(args.nextContent);
1197
1343
  if (!result.valid) {
1344
+ if (result.issue && RUNTIME_ISSUES.has(result.issue)) {
1345
+ const introduced = introducedRuntimeIssues(
1346
+ result.detail ?? [],
1347
+ args.previousContent,
1348
+ );
1349
+ if (introduced.length === 0) return;
1350
+ throw new DesignHtmlIntegrityError(introduced[0]!.issue, {
1351
+ filename: args.filename,
1352
+ detail: introduced,
1353
+ });
1354
+ }
1198
1355
  throw new DesignHtmlIntegrityError(result.issue ?? "document-root", {
1199
1356
  filename: args.filename,
1200
1357
  detail: result.detail,
@@ -1227,6 +1384,20 @@ export function assertDesignHtmlWellFormed(args: {
1227
1384
  detail: structural,
1228
1385
  });
1229
1386
  }
1387
+ // Fragments are checked too, unlike the document-shape rules above: a screen
1388
+ // is rendered as its own `srcdoc`, so nothing injects Alpine or a `[x-cloak]`
1389
+ // rule around it. A sketch that omits them is broken exactly as a full
1390
+ // document would be.
1391
+ const interactiveRuntime = collectInteractiveRuntimeIssues(
1392
+ parseDocument(args.content),
1393
+ createLocator(args.content),
1394
+ );
1395
+ if (interactiveRuntime.length > 0) {
1396
+ throw new DesignHtmlIntegrityError(interactiveRuntime[0]!.issue, {
1397
+ filename: args.filename,
1398
+ detail: interactiveRuntime,
1399
+ });
1400
+ }
1230
1401
  }
1231
1402
 
1232
1403
  export function assertDesignHtmlCreateIntegrity(args: {
@@ -194,5 +194,5 @@ export function formatShortcut(key: string): string {
194
194
  if (lower === "space") return "Space";
195
195
  return token.length === 1 ? token.toUpperCase() : token;
196
196
  })
197
- .join("+");
197
+ .join(" ");
198
198
  }
@@ -23,6 +23,7 @@ import {
23
23
  ErrorReportActions,
24
24
  type ErrorReportDebugItem,
25
25
  } from "@agent-native/core/client/ui";
26
+ import { docsUrl } from "@agent-native/core/shared";
26
27
  import {
27
28
  useSetHeaderActions,
28
29
  useSetPageTitle,
@@ -388,8 +389,10 @@ const ENABLE_PLAN_STATUS_FEATURE = false;
388
389
  const GITHUB_LIGHT_CANVAS_BACKGROUND = "#ffffff";
389
390
  const GITHUB_DARK_CANVAS_BACKGROUND = "#0d1117";
390
391
  const LOCAL_PLAN_OWNER_EMAIL = "local@agent-native.local";
391
- const PLAN_DOCS_URL = "https://www.agent-native.com/docs/template-plan";
392
- const LOCAL_FILES_DOCS_URL = `${PLAN_DOCS_URL}#local-files`;
392
+ const PLAN_DOCS_URL = docsUrl("template-plan");
393
+ const LOCAL_FILES_DOCS_URL = docsUrl("template-plan-local-and-desktop", {
394
+ hash: "local-files",
395
+ });
393
396
  const AUTO_DEV_COMMENT_EMAILS = new Set(["dev@local.test", "dev@local"]);
394
397
  const CURRENT_USER_FALLBACK_NAME = "You";
395
398
  const CURRENT_USER_FALLBACK_INITIALS = "You";
@@ -72,12 +72,16 @@ Builder indexing flow.
72
72
 
73
73
  ### Source: connected code, GitHub, or `design.md`
74
74
 
75
- For any other reusable source — connected code, a GitHub repo, local
76
- code/design files, or an optional `design.md` — use Builder-backed DSI
77
- indexing through `index-design-system-with-builder`. Pass readable `design.md`
78
- content as `designMd`, and use the returned local design system id in the rest
79
- of the Slides flow. Call `get-design-system` before generation so Builder docs
80
- and tokens are hydrated when available.
75
+ For any other reusable source - connected code, a GitHub repo, local
76
+ code/design files, or an optional `design.md` - use Builder-backed DSI
77
+ indexing through `index-design-system-with-builder`. Pass GitHub sources as one
78
+ `githubSources` array; each source may pin a branch/tag/commit and include
79
+ repository-relative files or folders. Pass readable `design.md` content as
80
+ `designMd`, and use the returned local design system id in the rest of the
81
+ Slides flow. Call `get-design-system` before generation so Builder docs and
82
+ tokens are hydrated when available. For a saved GitHub-backed system, call
83
+ `sync-design-system-with-builder --id <localDesignSystemId>` to replay its
84
+ persisted source scope after upstream changes.
81
85
 
82
86
  Never create a duplicate local design system from raw Figma or code sources.
83
87
  Builder owns the indexed brand kit; a second local copy drifts from it and