@getcoherent/cli 0.6.10 → 0.6.12

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.
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  CORE_CONSTRAINTS,
3
3
  DESIGN_QUALITY,
4
+ DESIGN_QUALITY_COMMON,
4
5
  DESIGN_THINKING,
5
6
  INTERACTION_PATTERNS,
6
7
  VISUAL_DEPTH,
@@ -13,7 +14,7 @@ import {
13
14
  routeToKey,
14
15
  savePlan,
15
16
  selectContextualRules
16
- } from "./chunk-O7OA76D3.js";
17
+ } from "./chunk-CLPILU3Z.js";
17
18
  import {
18
19
  __require
19
20
  } from "./chunk-3RG5ZIWI.js";
@@ -1369,10 +1370,10 @@ var ShadcnProvider = class {
1369
1370
  const componentPath = path.join(projectRoot, "components", "ui", `${name}.tsx`);
1370
1371
  if (!force && deps.existsSync(componentPath)) return;
1371
1372
  try {
1372
- await new Promise((resolve16, reject) => {
1373
+ await new Promise((resolve17, reject) => {
1373
1374
  deps.exec(`npx shadcn@latest add ${name} --yes --overwrite`, { cwd: projectRoot, timeout: 15e3 }, (err) => {
1374
1375
  if (err) reject(err);
1375
- else resolve16();
1376
+ else resolve17();
1376
1377
  });
1377
1378
  });
1378
1379
  } catch {
@@ -1413,13 +1414,13 @@ var ShadcnProvider = class {
1413
1414
  }
1414
1415
  if (toInstall.length === 0) return results;
1415
1416
  try {
1416
- await new Promise((resolve16, reject) => {
1417
+ await new Promise((resolve17, reject) => {
1417
1418
  deps.exec(
1418
1419
  `npx shadcn@latest add ${toInstall.join(" ")} --yes --overwrite`,
1419
1420
  { cwd: projectRoot, timeout: 3e4 },
1420
1421
  (err) => {
1421
1422
  if (err) reject(err);
1422
- else resolve16();
1423
+ else resolve17();
1423
1424
  }
1424
1425
  );
1425
1426
  });
@@ -1931,7 +1932,7 @@ function installPackages(projectRoot, packages) {
1931
1932
  if (packages.length === 0) return Promise.resolve(true);
1932
1933
  const safe = packages.filter((p) => SAFE_PKG_NAME.test(p));
1933
1934
  if (safe.length === 0) return Promise.resolve(true);
1934
- return new Promise((resolve16) => {
1935
+ return new Promise((resolve17) => {
1935
1936
  try {
1936
1937
  const hasPnpm = existsSync4(join3(projectRoot, "pnpm-lock.yaml"));
1937
1938
  if (hasPnpm) {
@@ -1942,10 +1943,10 @@ function installPackages(projectRoot, packages) {
1942
1943
  stdio: "pipe"
1943
1944
  });
1944
1945
  }
1945
- resolve16(true);
1946
+ resolve17(true);
1946
1947
  } catch (e) {
1947
1948
  if (process.env.COHERENT_DEBUG === "1") console.error("Failed to install packages:", e);
1948
- resolve16(false);
1949
+ resolve17(false);
1949
1950
  }
1950
1951
  });
1951
1952
  }
@@ -3372,6 +3373,7 @@ function generateV4GlobalsCss(config2) {
3372
3373
  --color-accent-foreground: var(--accent-foreground);
3373
3374
  --color-destructive: var(--destructive);
3374
3375
  --color-destructive-foreground: var(--destructive-foreground);
3376
+ --color-transparent: transparent;
3375
3377
  --color-border: var(--border);
3376
3378
  --color-input: var(--input);
3377
3379
  --color-ring: var(--ring);
@@ -3383,6 +3385,24 @@ function generateV4GlobalsCss(config2) {
3383
3385
  --color-warning: var(--warning);
3384
3386
  --color-error: var(--error);
3385
3387
  --color-info: var(--info);
3388
+ --color-black: #000;
3389
+ --color-white: #fff;
3390
+ --color-sidebar-background: var(--sidebar-background);
3391
+ --color-sidebar-foreground: var(--sidebar-foreground);
3392
+ --color-sidebar-primary: var(--sidebar-primary);
3393
+ --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
3394
+ --color-sidebar-accent: var(--sidebar-accent);
3395
+ --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
3396
+ --color-sidebar-border: var(--sidebar-border);
3397
+ --color-sidebar-ring: var(--sidebar-ring);
3398
+ --color-sidebar-muted: var(--sidebar-muted);
3399
+ --color-sidebar-muted-foreground: var(--sidebar-muted-foreground);
3400
+ --color-chart-1: var(--chart-1);
3401
+ --color-chart-2: var(--chart-2);
3402
+ --color-chart-3: var(--chart-3);
3403
+ --color-chart-4: var(--chart-4);
3404
+ --color-chart-5: var(--chart-5);
3405
+ --radius-xs: 0.125rem;
3386
3406
  --radius-sm: ${radius.sm || "0.25rem"};
3387
3407
  --radius-md: ${radius.md || "0.5rem"};
3388
3408
  --radius-lg: ${radius.lg || "0.75rem"};
@@ -3414,6 +3434,21 @@ function generateV4GlobalsCss(config2) {
3414
3434
  --warning: ${light.warning};
3415
3435
  --error: ${light.error};
3416
3436
  --info: ${light.info || light.primary};
3437
+ --sidebar-background: ${light.background};
3438
+ --sidebar-foreground: ${light.foreground};
3439
+ --sidebar-primary: ${light.primary};
3440
+ --sidebar-primary-foreground: ${contrastFg(light.primary)};
3441
+ --sidebar-accent: ${light.accent || light.muted};
3442
+ --sidebar-accent-foreground: ${light.foreground};
3443
+ --sidebar-border: ${light.border};
3444
+ --sidebar-ring: ${light.primary};
3445
+ --sidebar-muted: ${light.muted};
3446
+ --sidebar-muted-foreground: ${blendColors(light.foreground, light.background, 0.45)};
3447
+ --chart-1: ${light.primary};
3448
+ --chart-2: ${light.success};
3449
+ --chart-3: ${light.warning};
3450
+ --chart-4: ${light.error};
3451
+ --chart-5: ${light.info || light.primary};
3417
3452
  }
3418
3453
 
3419
3454
  .dark {
@@ -3440,6 +3475,21 @@ function generateV4GlobalsCss(config2) {
3440
3475
  --warning: ${dark.warning};
3441
3476
  --error: ${dark.error};
3442
3477
  --info: ${dark.info || dark.primary};
3478
+ --sidebar-background: ${dark.background};
3479
+ --sidebar-foreground: ${dark.foreground};
3480
+ --sidebar-primary: ${dark.primary};
3481
+ --sidebar-primary-foreground: ${contrastFg(dark.primary)};
3482
+ --sidebar-accent: ${dark.accent || dark.muted};
3483
+ --sidebar-accent-foreground: ${dark.foreground};
3484
+ --sidebar-border: ${dark.border};
3485
+ --sidebar-ring: ${dark.primary};
3486
+ --sidebar-muted: ${dark.muted};
3487
+ --sidebar-muted-foreground: ${blendColors(dark.foreground, dark.background, 0.45)};
3488
+ --chart-1: ${dark.primary};
3489
+ --chart-2: ${dark.success};
3490
+ --chart-3: ${dark.warning};
3491
+ --chart-4: ${dark.error};
3492
+ --chart-5: ${dark.info || dark.primary};
3443
3493
  }
3444
3494
 
3445
3495
  * {
@@ -3763,8 +3813,8 @@ async function createAppRouteGroupLayout(projectPath) {
3763
3813
  // src/commands/chat.ts
3764
3814
  import chalk14 from "chalk";
3765
3815
  import ora2 from "ora";
3766
- import { resolve as resolve9, relative as relative2, join as join11 } from "path";
3767
- import { existsSync as existsSync16, readFileSync as readFileSync11, mkdirSync as mkdirSync6, readdirSync as readdirSync3 } from "fs";
3816
+ import { resolve as resolve10, relative as relative2, join as join11 } from "path";
3817
+ import { existsSync as existsSync17, readFileSync as readFileSync12, mkdirSync as mkdirSync6, readdirSync as readdirSync4 } from "fs";
3768
3818
  import {
3769
3819
  DesignSystemManager as DesignSystemManager7,
3770
3820
  ComponentManager as ComponentManager5,
@@ -4919,6 +4969,17 @@ function needsGlobalsFix(projectRoot) {
4919
4969
  if (isTailwindV4(projectRoot)) {
4920
4970
  if (!content.includes("@theme inline")) return true;
4921
4971
  if (content.includes("@tailwind base")) return true;
4972
+ const REQUIRED_V4_TOKENS = [
4973
+ "--color-transparent",
4974
+ "--color-sidebar-background",
4975
+ "--color-chart-1",
4976
+ "--color-black",
4977
+ "--color-white",
4978
+ "--radius-xs"
4979
+ ];
4980
+ for (const token of REQUIRED_V4_TOKENS) {
4981
+ if (!content.includes(token)) return true;
4982
+ }
4922
4983
  return false;
4923
4984
  }
4924
4985
  if (content.includes(":root {") || content.includes(".dark {")) return true;
@@ -6077,19 +6138,21 @@ ${selectImport}`
6077
6138
  /(<TabsTrigger\b[^>]*className=")([^"]*)(")/g,
6078
6139
  (_m, pre, classes, post) => {
6079
6140
  const cleaned = classes.replace(/\b(border-input|border\b|outline\b)\s*/g, "").trim();
6080
- const withBorder0 = cleaned.includes("border-0") ? cleaned : `${cleaned} border-0`.trim();
6081
- if (withBorder0 !== classes.trim()) return `${pre}${withBorder0}${post}`;
6141
+ if (cleaned !== classes.trim()) return `${pre}${cleaned}${post}`;
6082
6142
  return _m;
6083
6143
  }
6084
6144
  );
6085
- fixed = fixed.replace(/<TabsTrigger\b(?![^>]*className=)(?![^>]*border-0)/g, '<TabsTrigger className="border-0"');
6086
6145
  if (fixed !== beforeTabsFix) {
6087
- fixes.push("added border-0 to TabsTrigger (Tailwind v4 border-transparent fix)");
6146
+ fixes.push("stripped border from TabsTrigger (shadcn handles active state)");
6088
6147
  }
6089
- const beforeTabsListFix = fixed;
6090
- fixed = fixed.replace(/<TabsList\b(?![^>]*variant=)/g, '<TabsList variant="line"');
6091
- if (fixed !== beforeTabsListFix) {
6092
- fixes.push('added variant="line" to TabsList (clean underline style)');
6148
+ const beforeJunkFix = fixed;
6149
+ fixed = fixed.replace(/className="([^"]*)"/g, (_match, classes) => {
6150
+ const cleaned = classes.split(/\s+/).filter((c) => c !== "-0").join(" ");
6151
+ if (cleaned !== classes.trim()) return `className="${cleaned}"`;
6152
+ return _match;
6153
+ });
6154
+ if (fixed !== beforeJunkFix) {
6155
+ fixes.push("removed junk classes (-0)");
6093
6156
  }
6094
6157
  fixed = fixed.replace(/className="([^"]*)"/g, (_match, inner) => {
6095
6158
  const cleaned = inner.replace(/\s{2,}/g, " ").trim();
@@ -6810,6 +6873,8 @@ function applyDefaults(request) {
6810
6873
  }
6811
6874
 
6812
6875
  // src/commands/chat/split-generator.ts
6876
+ import { existsSync as existsSync14, readFileSync as readFileSync9, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
6877
+ import { resolve as resolve6 } from "path";
6813
6878
  import { z } from "zod";
6814
6879
  import {
6815
6880
  loadManifest as loadManifest5,
@@ -7041,9 +7106,55 @@ ${groupLines.join("\n")}`];
7041
7106
  if (compLines.length > 0) {
7042
7107
  parts.push(`Shared Components:
7043
7108
  ${compLines.join("\n")}`);
7109
+ }
7110
+ const noteEntries = Object.entries(plan.pageNotes || {}).filter(
7111
+ ([, note]) => note.sections && note.sections.length > 0
7112
+ );
7113
+ if (noteEntries.length > 0) {
7114
+ const noteLines = noteEntries.map(([key, note]) => ` ${key}: ${note.sections.join(", ")}`);
7115
+ parts.push(`Page Sections:
7116
+ ${noteLines.join("\n")}`);
7044
7117
  }
7045
7118
  return parts.join("\n");
7046
7119
  }
7120
+ function readExistingAppPageForReference(projectRoot, plan) {
7121
+ if (!projectRoot) return null;
7122
+ if (plan?.pageNotes) {
7123
+ for (const [key, note] of Object.entries(plan.pageNotes)) {
7124
+ if (note.type !== "app") continue;
7125
+ for (const group of ["(app)", "(admin)", "(dashboard)"]) {
7126
+ const filePath = resolve6(projectRoot, "app", group, key, "page.tsx");
7127
+ if (existsSync14(filePath)) {
7128
+ const code = readFileSync9(filePath, "utf-8");
7129
+ const lines = code.split("\n");
7130
+ return lines.slice(0, 200).join("\n");
7131
+ }
7132
+ }
7133
+ }
7134
+ }
7135
+ const appDir = resolve6(projectRoot, "app");
7136
+ if (!existsSync14(appDir)) return null;
7137
+ try {
7138
+ const entries = readdirSync2(appDir);
7139
+ for (const entry of entries) {
7140
+ if (!entry.startsWith("(") || entry === "(auth)") continue;
7141
+ const groupDir = resolve6(appDir, entry);
7142
+ if (!statSync2(groupDir).isDirectory()) continue;
7143
+ const subDirs = readdirSync2(groupDir);
7144
+ for (const sub of subDirs) {
7145
+ const pagePath = resolve6(groupDir, sub, "page.tsx");
7146
+ if (existsSync14(pagePath)) {
7147
+ const code = readFileSync9(pagePath, "utf-8");
7148
+ const lines = code.split("\n");
7149
+ return lines.slice(0, 200).join("\n");
7150
+ }
7151
+ }
7152
+ }
7153
+ } catch {
7154
+ return null;
7155
+ }
7156
+ return null;
7157
+ }
7047
7158
  async function splitGeneratePages(spinner, message, modCtx, provider, parseOpts) {
7048
7159
  let pageNames = [];
7049
7160
  spinner.start("Phase 1/6 \u2014 Planning pages...");
@@ -7198,7 +7309,7 @@ async function splitGeneratePages(spinner, message, modCtx, provider, parseOpts)
7198
7309
  if (plan && plan.sharedComponents.length > 0) {
7199
7310
  spinner.start(`Phase 4.5/6 \u2014 Generating ${plan.sharedComponents.length} shared components from plan...`);
7200
7311
  try {
7201
- const { generateSharedComponentsFromPlan } = await import("./plan-generator-EWZYC45I.js");
7312
+ const { generateSharedComponentsFromPlan } = await import("./plan-generator-QUESV7GS.js");
7202
7313
  const generated = await generateSharedComponentsFromPlan(
7203
7314
  plan,
7204
7315
  styleContext,
@@ -7245,6 +7356,13 @@ async function splitGeneratePages(spinner, message, modCtx, provider, parseOpts)
7245
7356
  const routeNote = `EXISTING ROUTES in this project: ${allRoutes}. All internal links MUST point to one of these routes. If a target doesn't exist, use href="#".`;
7246
7357
  const alignmentNote = 'CRITICAL LAYOUT RULE: Every <section> must wrap its content in a container div matching the header width. Use the EXACT same container classes as shown in the style context (e.g. className="container max-w-6xl px-4" or className="max-w-6xl mx-auto px-4"). Inner content can use narrower max-w for text centering, but the outer section container MUST match.';
7247
7358
  const planSummaryNote = plan ? formatPlanSummary(plan) : "";
7359
+ const existingAppPageCode = readExistingAppPageForReference(parseOpts?.projectRoot ?? null, plan);
7360
+ const existingAppPageNote = existingAppPageCode ? `
7361
+ EXISTING APP PAGE (match these UI patterns for consistency):
7362
+ \`\`\`
7363
+ ${existingAppPageCode}
7364
+ \`\`\`
7365
+ ` : "";
7248
7366
  const existingPagesContext = buildExistingPagesContext(modCtx.config);
7249
7367
  const AI_CONCURRENCY = 3;
7250
7368
  let phase5Done = 0;
@@ -7267,6 +7385,7 @@ async function splitGeneratePages(spinner, message, modCtx, provider, parseOpts)
7267
7385
  alignmentNote,
7268
7386
  authNote,
7269
7387
  planSummaryNote,
7388
+ pageType !== "auth" ? existingAppPageNote : void 0,
7270
7389
  existingPagesContext,
7271
7390
  styleContext
7272
7391
  ].filter(Boolean).join("\n\n");
@@ -7427,7 +7546,7 @@ function extractAppNameFromPrompt(prompt) {
7427
7546
  }
7428
7547
 
7429
7548
  // src/commands/chat/modification-handler.ts
7430
- import { resolve as resolve7 } from "path";
7549
+ import { resolve as resolve8 } from "path";
7431
7550
  import { mkdir as mkdir4 } from "fs/promises";
7432
7551
  import { dirname as dirname6 } from "path";
7433
7552
  import chalk12 from "chalk";
@@ -7441,8 +7560,8 @@ import {
7441
7560
  } from "@getcoherent/core";
7442
7561
 
7443
7562
  // src/commands/chat/code-generator.ts
7444
- import { resolve as resolve6 } from "path";
7445
- import { existsSync as existsSync14, readdirSync as readdirSync2, readFileSync as readFileSync9 } from "fs";
7563
+ import { resolve as resolve7 } from "path";
7564
+ import { existsSync as existsSync15, readdirSync as readdirSync3, readFileSync as readFileSync10 } from "fs";
7446
7565
  import { mkdir as mkdir3 } from "fs/promises";
7447
7566
  import { dirname as dirname5 } from "path";
7448
7567
  import {
@@ -7507,8 +7626,8 @@ async function ensureComponentsInstalled(componentIds, cm, dsm, pm, projectRoot)
7507
7626
  for (const componentId of ids) {
7508
7627
  const isRegistered = !!cm.read(componentId);
7509
7628
  const fileName = toKebabCase(componentId) + ".tsx";
7510
- const filePath = resolve6(projectRoot, "components", "ui", fileName);
7511
- const fileExists = existsSync14(filePath);
7629
+ const filePath = resolve7(projectRoot, "components", "ui", fileName);
7630
+ const fileExists = existsSync15(filePath);
7512
7631
  if (isRegistered && fileExists) continue;
7513
7632
  const result = await provider.installComponent(componentId, projectRoot);
7514
7633
  if (result.success && result.componentDef) {
@@ -7532,7 +7651,7 @@ async function regenerateComponent(componentId, config2, projectRoot) {
7532
7651
  const generator = new ComponentGenerator2(config2);
7533
7652
  const code = await generator.generate(component);
7534
7653
  const fileName = toKebabCase(component.name) + ".tsx";
7535
- const filePath = resolve6(projectRoot, "components", "ui", fileName);
7654
+ const filePath = resolve7(projectRoot, "components", "ui", fileName);
7536
7655
  await writeFile(filePath, code);
7537
7656
  }
7538
7657
  async function regeneratePage(pageId, config2, projectRoot) {
@@ -7549,8 +7668,8 @@ async function regeneratePage(pageId, config2, projectRoot) {
7549
7668
  await writeFile(filePath, code);
7550
7669
  }
7551
7670
  async function canOverwriteShared(projectRoot, componentFile, storedHashes) {
7552
- const filePath = resolve6(projectRoot, componentFile);
7553
- if (!existsSync14(filePath)) return true;
7671
+ const filePath = resolve7(projectRoot, componentFile);
7672
+ if (!existsSync15(filePath)) return true;
7554
7673
  const storedHash = storedHashes[componentFile];
7555
7674
  if (!storedHash) return true;
7556
7675
  const edited = await isManuallyEdited(filePath, storedHash);
@@ -7567,7 +7686,7 @@ async function regenerateLayout(config2, projectRoot, options = { navChanged: fa
7567
7686
  if (!initialized) {
7568
7687
  const layout = config2.pages[0]?.layout || "centered";
7569
7688
  const code = await generator.generateLayout(layout, appType, { skipNav: true });
7570
- await writeFile(resolve6(projectRoot, "app", "layout.tsx"), code);
7689
+ await writeFile(resolve7(projectRoot, "app", "layout.tsx"), code);
7571
7690
  }
7572
7691
  if (config2.navigation?.enabled && appType === "multi-page") {
7573
7692
  const navType = config2.navigation.type || "header";
@@ -7623,17 +7742,17 @@ async function regenerateLayout(config2, projectRoot, options = { navChanged: fa
7623
7742
  }
7624
7743
  }
7625
7744
  async function scanAndInstallSharedDeps(projectRoot) {
7626
- const sharedDir = resolve6(projectRoot, "components", "shared");
7627
- if (!existsSync14(sharedDir)) return [];
7628
- const files = readdirSync2(sharedDir).filter((f) => f.endsWith(".tsx") || f.endsWith(".ts"));
7745
+ const sharedDir = resolve7(projectRoot, "components", "shared");
7746
+ if (!existsSync15(sharedDir)) return [];
7747
+ const files = readdirSync3(sharedDir).filter((f) => f.endsWith(".tsx") || f.endsWith(".ts"));
7629
7748
  const installed = [];
7630
7749
  const provider = getComponentProvider();
7631
7750
  for (const file of files) {
7632
- const code = readFileSync9(resolve6(sharedDir, file), "utf-8");
7751
+ const code = readFileSync10(resolve7(sharedDir, file), "utf-8");
7633
7752
  const importMatches = [...code.matchAll(/@\/components\/ui\/([a-z0-9-]+)/g)];
7634
7753
  for (const [, componentId] of importMatches) {
7635
- const uiPath = resolve6(projectRoot, "components", "ui", `${componentId}.tsx`);
7636
- if (!existsSync14(uiPath) && provider.has(componentId)) {
7754
+ const uiPath = resolve7(projectRoot, "components", "ui", `${componentId}.tsx`);
7755
+ if (!existsSync15(uiPath) && provider.has(componentId)) {
7637
7756
  try {
7638
7757
  await provider.installComponent(componentId, projectRoot);
7639
7758
  installed.push(componentId);
@@ -7645,10 +7764,10 @@ async function scanAndInstallSharedDeps(projectRoot) {
7645
7764
  return [...new Set(installed)];
7646
7765
  }
7647
7766
  async function ensureAppRouteGroupLayout(projectRoot, navType, forceUpdate = false) {
7648
- const layoutPath = resolve6(projectRoot, "app", "(app)", "layout.tsx");
7649
- if (existsSync14(layoutPath) && !forceUpdate) return;
7767
+ const layoutPath = resolve7(projectRoot, "app", "(app)", "layout.tsx");
7768
+ if (existsSync15(layoutPath) && !forceUpdate) return;
7650
7769
  const { mkdir: mkdirAsync } = await import("fs/promises");
7651
- await mkdirAsync(resolve6(projectRoot, "app", "(app)"), { recursive: true });
7770
+ await mkdirAsync(resolve7(projectRoot, "app", "(app)"), { recursive: true });
7652
7771
  const code = buildAppLayoutCode(navType);
7653
7772
  await writeFile(layoutPath, code);
7654
7773
  }
@@ -7736,9 +7855,9 @@ export default function GroupLayout({
7736
7855
  async function ensurePlanGroupLayouts(projectRoot, plan) {
7737
7856
  const { mkdir: mkdirAsync } = await import("fs/promises");
7738
7857
  for (const group of plan.groups) {
7739
- const groupDir = resolve6(projectRoot, "app", `(${group.id})`);
7858
+ const groupDir = resolve7(projectRoot, "app", `(${group.id})`);
7740
7859
  await mkdirAsync(groupDir, { recursive: true });
7741
- const layoutPath = resolve6(groupDir, "layout.tsx");
7860
+ const layoutPath = resolve7(groupDir, "layout.tsx");
7742
7861
  const code = buildGroupLayoutCode(group.layout, group.pages);
7743
7862
  await writeFile(layoutPath, code);
7744
7863
  }
@@ -7765,11 +7884,11 @@ async function regenerateFiles(modified, config2, projectRoot, options = { navCh
7765
7884
  }
7766
7885
  if (componentIds.size > 0) {
7767
7886
  const twGen = new TailwindConfigGenerator(config2);
7768
- const twPath = resolve6(projectRoot, "tailwind.config.ts");
7769
- const twCjsPath = resolve6(projectRoot, "tailwind.config.cjs");
7770
- if (existsSync14(twPath)) {
7887
+ const twPath = resolve7(projectRoot, "tailwind.config.ts");
7888
+ const twCjsPath = resolve7(projectRoot, "tailwind.config.cjs");
7889
+ if (existsSync15(twPath)) {
7771
7890
  await writeFile(twPath, await twGen.generate());
7772
- } else if (existsSync14(twCjsPath)) {
7891
+ } else if (existsSync15(twCjsPath)) {
7773
7892
  await writeFile(twCjsPath, await twGen.generateCjs());
7774
7893
  }
7775
7894
  }
@@ -8141,7 +8260,7 @@ async function applyModification(request, dsm, cm, pm, projectRoot, aiProvider,
8141
8260
  modified: []
8142
8261
  };
8143
8262
  }
8144
- const fullPath = resolve7(projectRoot, resolved.file);
8263
+ const fullPath = resolve8(projectRoot, resolved.file);
8145
8264
  let currentCode;
8146
8265
  try {
8147
8266
  currentCode = await readFile(fullPath);
@@ -8215,7 +8334,7 @@ async function applyModification(request, dsm, cm, pm, projectRoot, aiProvider,
8215
8334
  } catch {
8216
8335
  return { success: false, message: `Could not read ${pageFilePath}`, modified: [] };
8217
8336
  }
8218
- const sharedPath = resolve7(projectRoot, resolved.file);
8337
+ const sharedPath = resolve8(projectRoot, resolved.file);
8219
8338
  let sharedCode;
8220
8339
  try {
8221
8340
  sharedCode = await readFile(sharedPath);
@@ -8294,7 +8413,7 @@ async function applyModification(request, dsm, cm, pm, projectRoot, aiProvider,
8294
8413
  }
8295
8414
  let sourceCode;
8296
8415
  try {
8297
- sourceCode = await readFile(resolve7(projectRoot, sourcePath));
8416
+ sourceCode = await readFile(resolve8(projectRoot, sourcePath));
8298
8417
  } catch {
8299
8418
  return { success: false, message: `Could not read ${sourcePath}`, modified: [] };
8300
8419
  }
@@ -8314,7 +8433,7 @@ async function applyModification(request, dsm, cm, pm, projectRoot, aiProvider,
8314
8433
  description: `Extracted from ${sourcePageName}: ${blockHint}`,
8315
8434
  usedIn: []
8316
8435
  });
8317
- const sharedPath = resolve7(projectRoot, created.file);
8436
+ const sharedPath = resolve8(projectRoot, created.file);
8318
8437
  let sharedCode;
8319
8438
  try {
8320
8439
  sharedCode = await readFile(sharedPath);
@@ -8325,7 +8444,7 @@ async function applyModification(request, dsm, cm, pm, projectRoot, aiProvider,
8325
8444
  for (const pageName of allPagesToLink) {
8326
8445
  const relPath = routeToPath(pageName);
8327
8446
  if (!relPath) continue;
8328
- const fullPath = resolve7(projectRoot, relPath);
8447
+ const fullPath = resolve8(projectRoot, relPath);
8329
8448
  let linkPageCode;
8330
8449
  try {
8331
8450
  linkPageCode = await readFile(fullPath);
@@ -8659,7 +8778,10 @@ Rules:
8659
8778
  if (ai.editPageCode) {
8660
8779
  console.log(chalk12.dim(" \u270F\uFE0F Applying changes to existing page..."));
8661
8780
  const coreRules = CORE_CONSTRAINTS;
8662
- const qualityRules = DESIGN_QUALITY;
8781
+ const pageRoute = pageDef.route || `/${pageDef.id}`;
8782
+ const pageType = inferPageTypeFromRoute(pageRoute);
8783
+ const qualityRules = `${DESIGN_QUALITY_COMMON}
8784
+ ${getDesignQualityForType(pageType)}`;
8663
8785
  const contextualRules = selectContextualRules(instruction);
8664
8786
  const existingRoutes = dsm.getConfig().pages.map((p) => p.route).join(", ");
8665
8787
  const routeRules = `
@@ -8949,8 +9071,8 @@ function hasNavChanged(before, after) {
8949
9071
 
8950
9072
  // src/commands/chat/interactive.ts
8951
9073
  import chalk13 from "chalk";
8952
- import { resolve as resolve8 } from "path";
8953
- import { existsSync as existsSync15, readFileSync as readFileSync10, writeFileSync as writeFileSync8, mkdirSync as mkdirSync5 } from "fs";
9074
+ import { resolve as resolve9 } from "path";
9075
+ import { existsSync as existsSync16, readFileSync as readFileSync11, writeFileSync as writeFileSync8, mkdirSync as mkdirSync5 } from "fs";
8954
9076
  import { DesignSystemManager as DesignSystemManager6, ComponentManager as ComponentManager4, loadManifest as loadManifest7 } from "@getcoherent/core";
8955
9077
  var DEBUG3 = process.env.COHERENT_DEBUG === "1";
8956
9078
  async function interactiveChat(options, chatCommandFn) {
@@ -8970,13 +9092,13 @@ async function interactiveChat(options, chatCommandFn) {
8970
9092
  \u274C Invalid provider: ${options.provider}`));
8971
9093
  process.exit(1);
8972
9094
  }
8973
- const historyDir = resolve8(homedir2(), ".coherent");
8974
- const historyFile = resolve8(historyDir, "history");
9095
+ const historyDir = resolve9(homedir2(), ".coherent");
9096
+ const historyFile = resolve9(historyDir, "history");
8975
9097
  let history = [];
8976
9098
  try {
8977
9099
  mkdirSync5(historyDir, { recursive: true });
8978
- if (existsSync15(historyFile)) {
8979
- history = readFileSync10(historyFile, "utf-8").split("\n").filter(Boolean).slice(-200);
9100
+ if (existsSync16(historyFile)) {
9101
+ history = readFileSync11(historyFile, "utf-8").split("\n").filter(Boolean).slice(-200);
8980
9102
  }
8981
9103
  } catch (e) {
8982
9104
  if (DEBUG3) console.error("Failed to load REPL history:", e);
@@ -9147,7 +9269,7 @@ async function chatCommand(message, options) {
9147
9269
  const projectRoot = project.root;
9148
9270
  const configPath = project.configPath;
9149
9271
  const migrationGuard = join11(projectRoot, ".coherent", "migration-in-progress");
9150
- if (existsSync16(migrationGuard)) {
9272
+ if (existsSync17(migrationGuard)) {
9151
9273
  spinner.fail("Migration in progress");
9152
9274
  console.error(chalk14.red("\n\u274C A migration is in progress. Run `coherent migrate --rollback` to undo first."));
9153
9275
  bail("Migration in progress");
@@ -9207,7 +9329,7 @@ async function chatCommand(message, options) {
9207
9329
  }
9208
9330
  if (/switch to light mode|default to light|make.*light.*(default|theme)|light theme/i.test(message)) {
9209
9331
  spinner.start("Setting default theme to light...");
9210
- const layoutPath = resolve9(projectRoot, "app/layout.tsx");
9332
+ const layoutPath = resolve10(projectRoot, "app/layout.tsx");
9211
9333
  try {
9212
9334
  let layout = await readFile(layoutPath);
9213
9335
  layout = layout.replace(/className="dark"/, "");
@@ -9246,8 +9368,8 @@ async function chatCommand(message, options) {
9246
9368
  spinner.start("Parsing your request...");
9247
9369
  let manifest = await loadManifest8(project.root);
9248
9370
  const validShared = manifest.shared.filter((s) => {
9249
- const fp = resolve9(project.root, s.file);
9250
- return existsSync16(fp);
9371
+ const fp = resolve10(project.root, s.file);
9372
+ return existsSync17(fp);
9251
9373
  });
9252
9374
  if (validShared.length !== manifest.shared.length) {
9253
9375
  const cleaned = manifest.shared.length - validShared.length;
@@ -9451,9 +9573,9 @@ async function chatCommand(message, options) {
9451
9573
  if (manifest.shared.length > 0) {
9452
9574
  for (const entry of manifest.shared) {
9453
9575
  try {
9454
- const sharedPath = resolve9(projectRoot, entry.file);
9455
- if (existsSync16(sharedPath)) {
9456
- const sharedCode = readFileSync11(sharedPath, "utf-8");
9576
+ const sharedPath = resolve10(projectRoot, entry.file);
9577
+ if (existsSync17(sharedPath)) {
9578
+ const sharedCode = readFileSync12(sharedPath, "utf-8");
9457
9579
  const sharedImports = sharedCode.matchAll(/@\/components\/ui\/([a-z0-9-]+)/g);
9458
9580
  for (const m of sharedImports) {
9459
9581
  if (m[1]) allNeededComponentIds.add(m[1]);
@@ -9474,7 +9596,7 @@ async function chatCommand(message, options) {
9474
9596
  for (const componentId of allNeededComponentIds) {
9475
9597
  const isRegistered = !!cm.read(componentId);
9476
9598
  const filePath = join11(projectRoot, "components", "ui", `${componentId}.tsx`);
9477
- const fileExists = existsSync16(filePath);
9599
+ const fileExists = existsSync17(filePath);
9478
9600
  if (DEBUG4) console.log(chalk14.gray(` Checking ${componentId}: registered=${isRegistered} file=${fileExists}`));
9479
9601
  if (!isRegistered || !fileExists) {
9480
9602
  missingComponents.push(componentId);
@@ -9600,9 +9722,9 @@ async function chatCommand(message, options) {
9600
9722
  const route = page.route || `/${page.id || "page"}`;
9601
9723
  const pageFilePath = routeToFsPath(projectRoot, route, false);
9602
9724
  let pageCode = "";
9603
- if (existsSync16(pageFilePath)) {
9725
+ if (existsSync17(pageFilePath)) {
9604
9726
  try {
9605
- pageCode = readFileSync11(pageFilePath, "utf-8");
9727
+ pageCode = readFileSync12(pageFilePath, "utf-8");
9606
9728
  } catch {
9607
9729
  }
9608
9730
  }
@@ -9622,8 +9744,8 @@ async function chatCommand(message, options) {
9622
9744
  }
9623
9745
  const missingRoutes = [...allLinkedRoutes].filter((route) => {
9624
9746
  if (expandedExisting.has(route)) return false;
9625
- if (existsSync16(routeToFsPath(projectRoot, route, false))) return false;
9626
- if (existsSync16(routeToFsPath(projectRoot, route, true))) return false;
9747
+ if (existsSync17(routeToFsPath(projectRoot, route, false))) return false;
9748
+ if (existsSync17(routeToFsPath(projectRoot, route, true))) return false;
9627
9749
  return true;
9628
9750
  });
9629
9751
  const SCAFFOLD_AI_LIMIT = 10;
@@ -9687,8 +9809,8 @@ async function chatCommand(message, options) {
9687
9809
  const isAuth = isAuthRoute(linkedRoute);
9688
9810
  const filePath = routeToFsPath(projectRoot, linkedRoute, isAuth);
9689
9811
  if (isAuth) await ensureAuthRouteGroup(projectRoot);
9690
- const dir = resolve9(filePath, "..");
9691
- if (!existsSync16(dir)) {
9812
+ const dir = resolve10(filePath, "..");
9813
+ if (!existsSync17(dir)) {
9692
9814
  mkdirSync6(dir, { recursive: true });
9693
9815
  }
9694
9816
  const placeholderCode = `export default function ${pageName.replace(/\s/g, "")}Page() {
@@ -9721,7 +9843,7 @@ async function chatCommand(message, options) {
9721
9843
  for (const mod of result.modified) {
9722
9844
  if (mod.startsWith("app/") && mod.endsWith("/page.tsx")) {
9723
9845
  try {
9724
- const code = readFileSync11(resolve9(projectRoot, mod), "utf-8");
9846
+ const code = readFileSync12(resolve10(projectRoot, mod), "utf-8");
9725
9847
  const issues = validatePageQuality(code, allRoutes).filter(
9726
9848
  (i) => i.type === "BROKEN_INTERNAL_LINK"
9727
9849
  );
@@ -9751,7 +9873,7 @@ async function chatCommand(message, options) {
9751
9873
  dsm.updateConfig(latestConfig);
9752
9874
  if (DEBUG4) console.log(chalk14.dim(` [theme] Set defaultMode to "${targetMode}"`));
9753
9875
  }
9754
- const layoutPath = resolve9(projectRoot, "app", "layout.tsx");
9876
+ const layoutPath = resolve10(projectRoot, "app", "layout.tsx");
9755
9877
  try {
9756
9878
  let layoutCode = await readFile(layoutPath);
9757
9879
  if (targetMode === "dark" && !layoutCode.includes('className="dark"')) {
@@ -9801,16 +9923,16 @@ async function chatCommand(message, options) {
9801
9923
  }
9802
9924
  try {
9803
9925
  const updatedHashes = { ...storedHashes };
9804
- const sharedDir = resolve9(projectRoot, "components", "shared");
9805
- const layoutFile = resolve9(projectRoot, "app", "layout.tsx");
9926
+ const sharedDir = resolve10(projectRoot, "components", "shared");
9927
+ const layoutFile = resolve10(projectRoot, "app", "layout.tsx");
9806
9928
  const filesToHash = [layoutFile];
9807
- if (existsSync16(sharedDir)) {
9808
- for (const f of readdirSync3(sharedDir)) {
9809
- if (f.endsWith(".tsx")) filesToHash.push(resolve9(sharedDir, f));
9929
+ if (existsSync17(sharedDir)) {
9930
+ for (const f of readdirSync4(sharedDir)) {
9931
+ if (f.endsWith(".tsx")) filesToHash.push(resolve10(sharedDir, f));
9810
9932
  }
9811
9933
  }
9812
9934
  for (const filePath of filesToHash) {
9813
- if (existsSync16(filePath)) {
9935
+ if (existsSync17(filePath)) {
9814
9936
  const rel = relative2(projectRoot, filePath);
9815
9937
  updatedHashes[rel] = await computeFileHash(filePath);
9816
9938
  }
@@ -9842,7 +9964,7 @@ async function chatCommand(message, options) {
9842
9964
  console.log("");
9843
9965
  }
9844
9966
  if (uxRecommendations) {
9845
- const recPath = resolve9(projectRoot, "recommendations.md");
9967
+ const recPath = resolve10(projectRoot, "recommendations.md");
9846
9968
  const section = `
9847
9969
 
9848
9970
  ---
@@ -9852,7 +9974,7 @@ async function chatCommand(message, options) {
9852
9974
  ${uxRecommendations}
9853
9975
  `;
9854
9976
  try {
9855
- if (!existsSync16(recPath)) {
9977
+ if (!existsSync17(recPath)) {
9856
9978
  await writeFile(
9857
9979
  recPath,
9858
9980
  "# UX/UI Recommendations\n\nRecommendations are added here when you use `coherent chat` and the AI suggests improvements.\n"
@@ -9926,18 +10048,68 @@ ${uxRecommendations}
9926
10048
  import chalk15 from "chalk";
9927
10049
  import ora3 from "ora";
9928
10050
  import { spawn } from "child_process";
9929
- import { existsSync as existsSync19, rmSync as rmSync3, readFileSync as readFileSync14, writeFileSync as writeFileSync10, readdirSync as readdirSync5 } from "fs";
9930
- import { resolve as resolve10, join as join14 } from "path";
10051
+ import { existsSync as existsSync20, rmSync as rmSync3, readFileSync as readFileSync15, writeFileSync as writeFileSync10, readdirSync as readdirSync6 } from "fs";
10052
+ import { resolve as resolve11, join as join14 } from "path";
9931
10053
  import { readdir as readdir2 } from "fs/promises";
10054
+
10055
+ // src/utils/css-validator.ts
10056
+ var REQUIRED_THEME_TOKENS = [
10057
+ "--color-transparent",
10058
+ "--color-black",
10059
+ "--color-white",
10060
+ "--color-sidebar-background",
10061
+ "--color-sidebar-foreground",
10062
+ "--color-sidebar-primary",
10063
+ "--color-sidebar-primary-foreground",
10064
+ "--color-sidebar-accent",
10065
+ "--color-sidebar-accent-foreground",
10066
+ "--color-sidebar-border",
10067
+ "--color-sidebar-ring",
10068
+ "--color-sidebar-muted",
10069
+ "--color-sidebar-muted-foreground",
10070
+ "--color-chart-1",
10071
+ "--color-chart-2",
10072
+ "--color-chart-3",
10073
+ "--color-chart-4",
10074
+ "--color-chart-5",
10075
+ "--radius-xs"
10076
+ ];
10077
+ var VAR_REFERENCE_RE = /var\(--([^)]+)\)/;
10078
+ function validateV4GlobalsCss(css) {
10079
+ const issues = [];
10080
+ if (css.includes("@tailwind base") || css.includes("@tailwind components")) {
10081
+ issues.push("Stale v3 directive (@tailwind) found in v4 CSS \u2014 remove it");
10082
+ }
10083
+ const themeMatch = css.match(/@theme\s+inline\s*\{([^}]*(?:\{[^}]*\}[^}]*)*)\}/s);
10084
+ const themeBlock = themeMatch ? themeMatch[1] : "";
10085
+ for (const token of REQUIRED_THEME_TOKENS) {
10086
+ if (!themeBlock.includes(token)) {
10087
+ issues.push(`Missing @theme token: ${token}`);
10088
+ }
10089
+ }
10090
+ const themeLines = themeBlock.split("\n");
10091
+ for (const line of themeLines) {
10092
+ const varMatch = line.match(VAR_REFERENCE_RE);
10093
+ if (!varMatch) continue;
10094
+ const referencedVar = `--${varMatch[1]}`;
10095
+ const definedInRoot = css.includes(`${referencedVar}:`) || css.includes(`${referencedVar} :`);
10096
+ if (!definedInRoot) {
10097
+ issues.push(`@theme references var(${referencedVar}) but it is not defined in :root/.dark`);
10098
+ }
10099
+ }
10100
+ return issues;
10101
+ }
10102
+
10103
+ // src/commands/preview.ts
9932
10104
  import { DesignSystemManager as DesignSystemManager8, ComponentGenerator as ComponentGenerator3 } from "@getcoherent/core";
9933
10105
 
9934
10106
  // src/utils/file-watcher.ts
9935
- import { readFileSync as readFileSync13, writeFileSync as writeFileSync9, existsSync as existsSync18 } from "fs";
10107
+ import { readFileSync as readFileSync14, writeFileSync as writeFileSync9, existsSync as existsSync19 } from "fs";
9936
10108
  import { relative as relative4, join as join13 } from "path";
9937
10109
  import { loadManifest as loadManifest9, saveManifest as saveManifest3 } from "@getcoherent/core";
9938
10110
 
9939
10111
  // src/utils/component-integrity.ts
9940
- import { existsSync as existsSync17, readFileSync as readFileSync12, readdirSync as readdirSync4 } from "fs";
10112
+ import { existsSync as existsSync18, readFileSync as readFileSync13, readdirSync as readdirSync5 } from "fs";
9941
10113
  import { join as join12, relative as relative3 } from "path";
9942
10114
  function extractExportedComponentNames(code) {
9943
10115
  const names = [];
@@ -9965,13 +10137,13 @@ function arraysEqual(a, b) {
9965
10137
  function findPagesImporting(projectRoot, componentName, componentFile) {
9966
10138
  const results = [];
9967
10139
  const appDir = join12(projectRoot, "app");
9968
- if (!existsSync17(appDir)) return results;
10140
+ if (!existsSync18(appDir)) return results;
9969
10141
  const pageFiles = collectFiles(appDir, (name) => name === "page.tsx" || name === "page.jsx");
9970
10142
  const componentImportPath = componentFile.replace(/\.tsx$/, "").replace(/\.jsx$/, "");
9971
10143
  for (const absPath of pageFiles) {
9972
10144
  if (absPath.includes("design-system")) continue;
9973
10145
  try {
9974
- const code = readFileSync12(absPath, "utf-8");
10146
+ const code = readFileSync13(absPath, "utf-8");
9975
10147
  const hasNamedImport = new RegExp(`import\\s+\\{[^}]*\\b${componentName}\\b[^}]*\\}\\s+from\\s+['"]`).test(code);
9976
10148
  const hasDefaultImport = new RegExp(`import\\s+${componentName}\\s+from\\s+['"]`).test(code);
9977
10149
  const hasPathImport = code.includes(`@/${componentImportPath}`);
@@ -9985,9 +10157,9 @@ function findPagesImporting(projectRoot, componentName, componentFile) {
9985
10157
  }
9986
10158
  function isUsedInLayout(projectRoot, componentName) {
9987
10159
  const layoutPath = join12(projectRoot, "app", "layout.tsx");
9988
- if (!existsSync17(layoutPath)) return false;
10160
+ if (!existsSync18(layoutPath)) return false;
9989
10161
  try {
9990
- const code = readFileSync12(layoutPath, "utf-8");
10162
+ const code = readFileSync13(layoutPath, "utf-8");
9991
10163
  return code.includes(componentName);
9992
10164
  } catch {
9993
10165
  return false;
@@ -9996,7 +10168,7 @@ function isUsedInLayout(projectRoot, componentName) {
9996
10168
  function findUnregisteredComponents(projectRoot, manifest) {
9997
10169
  const results = [];
9998
10170
  const componentsDir = join12(projectRoot, "components");
9999
- if (!existsSync17(componentsDir)) return results;
10171
+ if (!existsSync18(componentsDir)) return results;
10000
10172
  const registeredFiles = new Set(manifest.shared.map((s) => s.file));
10001
10173
  const registeredNames = new Set(manifest.shared.map((s) => s.name));
10002
10174
  const files = collectFiles(
@@ -10008,7 +10180,7 @@ function findUnregisteredComponents(projectRoot, manifest) {
10008
10180
  const relFile = relative3(projectRoot, absPath);
10009
10181
  if (registeredFiles.has(relFile)) continue;
10010
10182
  try {
10011
- const code = readFileSync12(absPath, "utf-8");
10183
+ const code = readFileSync13(absPath, "utf-8");
10012
10184
  const exports = extractExportedComponentNames(code);
10013
10185
  for (const name of exports) {
10014
10186
  if (registeredNames.has(name)) continue;
@@ -10024,13 +10196,13 @@ function findUnregisteredComponents(projectRoot, manifest) {
10024
10196
  function findInlineDuplicates(projectRoot, manifest) {
10025
10197
  const results = [];
10026
10198
  const appDir = join12(projectRoot, "app");
10027
- if (!existsSync17(appDir)) return results;
10199
+ if (!existsSync18(appDir)) return results;
10028
10200
  const pageFiles = collectFiles(appDir, (name) => name === "page.tsx" || name === "page.jsx");
10029
10201
  for (const absPath of pageFiles) {
10030
10202
  if (absPath.includes("design-system")) continue;
10031
10203
  let code;
10032
10204
  try {
10033
- code = readFileSync12(absPath, "utf-8");
10205
+ code = readFileSync13(absPath, "utf-8");
10034
10206
  } catch {
10035
10207
  continue;
10036
10208
  }
@@ -10054,7 +10226,7 @@ function findInlineDuplicates(projectRoot, manifest) {
10054
10226
  }
10055
10227
  function findComponentFileByExportName(projectRoot, componentName) {
10056
10228
  const componentsDir = join12(projectRoot, "components");
10057
- if (!existsSync17(componentsDir)) return null;
10229
+ if (!existsSync18(componentsDir)) return null;
10058
10230
  const files = collectFiles(
10059
10231
  componentsDir,
10060
10232
  (name) => (name.endsWith(".tsx") || name.endsWith(".jsx")) && !name.startsWith("."),
@@ -10062,7 +10234,7 @@ function findComponentFileByExportName(projectRoot, componentName) {
10062
10234
  );
10063
10235
  for (const absPath of files) {
10064
10236
  try {
10065
- const code = readFileSync12(absPath, "utf-8");
10237
+ const code = readFileSync13(absPath, "utf-8");
10066
10238
  const exports = extractExportedComponentNames(code);
10067
10239
  if (exports.includes(componentName)) {
10068
10240
  return relative3(projectRoot, absPath);
@@ -10076,7 +10248,7 @@ function removeOrphanedEntries(projectRoot, manifest) {
10076
10248
  const removed = [];
10077
10249
  const valid = manifest.shared.filter((entry) => {
10078
10250
  const filePath = join12(projectRoot, entry.file);
10079
- if (existsSync17(filePath)) return true;
10251
+ if (existsSync18(filePath)) return true;
10080
10252
  removed.push({ id: entry.id, name: entry.name });
10081
10253
  return false;
10082
10254
  });
@@ -10095,7 +10267,7 @@ function reconcileComponents(projectRoot, manifest) {
10095
10267
  const m = { ...manifest, shared: [...manifest.shared], nextId: manifest.nextId };
10096
10268
  m.shared = m.shared.filter((entry) => {
10097
10269
  const filePath = join12(projectRoot, entry.file);
10098
- if (!existsSync17(filePath)) {
10270
+ if (!existsSync18(filePath)) {
10099
10271
  const newPath = findComponentFileByExportName(projectRoot, entry.name);
10100
10272
  if (newPath) {
10101
10273
  result.updated.push({ id: entry.id, field: "file", from: entry.file, to: newPath });
@@ -10107,7 +10279,7 @@ function reconcileComponents(projectRoot, manifest) {
10107
10279
  }
10108
10280
  let code;
10109
10281
  try {
10110
- code = readFileSync12(join12(projectRoot, entry.file), "utf-8");
10282
+ code = readFileSync13(join12(projectRoot, entry.file), "utf-8");
10111
10283
  } catch {
10112
10284
  return true;
10113
10285
  }
@@ -10184,7 +10356,7 @@ function collectFiles(dir, filter, skipDirs = []) {
10184
10356
  function walk(d) {
10185
10357
  let entries;
10186
10358
  try {
10187
- entries = readdirSync4(d, { withFileTypes: true });
10359
+ entries = readdirSync5(d, { withFileTypes: true });
10188
10360
  } catch {
10189
10361
  return;
10190
10362
  }
@@ -10229,8 +10401,8 @@ function findInlineDuplicatesOfShared(content, manifest) {
10229
10401
  function getWatcherConfig(projectRoot) {
10230
10402
  try {
10231
10403
  const pkgPath = join13(projectRoot, "package.json");
10232
- if (!existsSync18(pkgPath)) return defaultWatcherConfig();
10233
- const pkg = JSON.parse(readFileSync13(pkgPath, "utf-8"));
10404
+ if (!existsSync19(pkgPath)) return defaultWatcherConfig();
10405
+ const pkg = JSON.parse(readFileSync14(pkgPath, "utf-8"));
10234
10406
  const c = pkg?.coherent?.watcher ?? {};
10235
10407
  return {
10236
10408
  enabled: c.enabled !== false,
@@ -10258,7 +10430,7 @@ async function handleFileChange(projectRoot, filePath) {
10258
10430
  if (relativePath.includes("node_modules") || relativePath.includes(".next")) return;
10259
10431
  let content;
10260
10432
  try {
10261
- content = readFileSync13(filePath, "utf-8");
10433
+ content = readFileSync14(filePath, "utf-8");
10262
10434
  } catch {
10263
10435
  return;
10264
10436
  }
@@ -10331,7 +10503,7 @@ async function detectNewComponent(projectRoot, filePath) {
10331
10503
  const manifest = await loadManifest9(projectRoot);
10332
10504
  const alreadyRegistered = manifest.shared.some((s) => s.file === relativePath);
10333
10505
  if (alreadyRegistered) return;
10334
- const code = readFileSync13(filePath, "utf-8");
10506
+ const code = readFileSync14(filePath, "utf-8");
10335
10507
  const exports = extractExportedComponentNames(code);
10336
10508
  if (exports.length > 0) {
10337
10509
  const alreadyByName = exports.every((n) => manifest.shared.some((s) => s.name === n));
@@ -10371,7 +10543,7 @@ function startFileWatcher(projectRoot) {
10371
10543
  watcher.on("unlink", (fp) => handleFileDelete(projectRoot, fp));
10372
10544
  });
10373
10545
  const manifestPath = join13(projectRoot, "coherent.components.json");
10374
- if (existsSync18(manifestPath)) {
10546
+ if (existsSync19(manifestPath)) {
10375
10547
  import("chokidar").then((chokidar) => {
10376
10548
  manifestWatcher = chokidar.default.watch(manifestPath, { ignoreInitial: true });
10377
10549
  manifestWatcher.on("change", () => handleManifestChange(projectRoot));
@@ -10385,7 +10557,7 @@ function startFileWatcher(projectRoot) {
10385
10557
 
10386
10558
  // src/commands/preview.ts
10387
10559
  function getPackageManager(projectRoot) {
10388
- const hasPnpm = existsSync19(resolve10(projectRoot, "pnpm-lock.yaml"));
10560
+ const hasPnpm = existsSync20(resolve11(projectRoot, "pnpm-lock.yaml"));
10389
10561
  return hasPnpm ? "pnpm" : "npm";
10390
10562
  }
10391
10563
  function runInstall(projectRoot) {
@@ -10407,23 +10579,23 @@ function runInstall(projectRoot) {
10407
10579
  });
10408
10580
  }
10409
10581
  function checkProjectInitialized(projectRoot) {
10410
- const configPath = resolve10(projectRoot, "design-system.config.ts");
10411
- const packageJsonPath = resolve10(projectRoot, "package.json");
10412
- if (!existsSync19(configPath)) {
10582
+ const configPath = resolve11(projectRoot, "design-system.config.ts");
10583
+ const packageJsonPath = resolve11(projectRoot, "package.json");
10584
+ if (!existsSync20(configPath)) {
10413
10585
  return false;
10414
10586
  }
10415
- if (!existsSync19(packageJsonPath)) {
10587
+ if (!existsSync20(packageJsonPath)) {
10416
10588
  return false;
10417
10589
  }
10418
10590
  return true;
10419
10591
  }
10420
10592
  function checkDependenciesInstalled(projectRoot) {
10421
- const nodeModulesPath = resolve10(projectRoot, "node_modules");
10422
- return existsSync19(nodeModulesPath);
10593
+ const nodeModulesPath = resolve11(projectRoot, "node_modules");
10594
+ return existsSync20(nodeModulesPath);
10423
10595
  }
10424
10596
  function clearStaleCache(projectRoot) {
10425
10597
  const nextDir = join14(projectRoot, ".next");
10426
- if (existsSync19(nextDir)) {
10598
+ if (existsSync20(nextDir)) {
10427
10599
  rmSync3(nextDir, { recursive: true, force: true });
10428
10600
  console.log(chalk15.dim(" \u2714 Cleared stale build cache"));
10429
10601
  }
@@ -10439,7 +10611,7 @@ async function preflightDependencyCheck(projectRoot) {
10439
10611
  }
10440
10612
  async function listPageFiles(appDir) {
10441
10613
  const out = [];
10442
- if (!existsSync19(appDir)) return out;
10614
+ if (!existsSync20(appDir)) return out;
10443
10615
  async function walk(dir) {
10444
10616
  const entries = await readdir2(dir, { withFileTypes: true });
10445
10617
  for (const e of entries) {
@@ -10455,7 +10627,7 @@ async function validateSyntax(projectRoot) {
10455
10627
  const appDir = join14(projectRoot, "app");
10456
10628
  const pages = await listPageFiles(appDir);
10457
10629
  for (const file of pages) {
10458
- const content = readFileSync14(file, "utf-8");
10630
+ const content = readFileSync15(file, "utf-8");
10459
10631
  const fixed = fixUnescapedLtInJsx(sanitizeMetadataStrings(ensureUseClientIfNeeded(content)));
10460
10632
  if (fixed !== content) {
10461
10633
  writeFileSync10(file, fixed, "utf-8");
@@ -10466,16 +10638,16 @@ async function validateSyntax(projectRoot) {
10466
10638
  async function fixMissingComponentExports(projectRoot) {
10467
10639
  const appDir = join14(projectRoot, "app");
10468
10640
  const uiDir = join14(projectRoot, "components", "ui");
10469
- if (!existsSync19(appDir) || !existsSync19(uiDir)) return;
10641
+ if (!existsSync20(appDir) || !existsSync20(uiDir)) return;
10470
10642
  const pages = await listPageFiles(appDir);
10471
10643
  const sharedDir = join14(projectRoot, "components", "shared");
10472
- if (existsSync19(sharedDir)) {
10473
- const sharedFiles = readdirSync5(sharedDir).filter((f) => f.endsWith(".tsx") || f.endsWith(".ts")).map((f) => join14(sharedDir, f));
10644
+ if (existsSync20(sharedDir)) {
10645
+ const sharedFiles = readdirSync6(sharedDir).filter((f) => f.endsWith(".tsx") || f.endsWith(".ts")).map((f) => join14(sharedDir, f));
10474
10646
  pages.push(...sharedFiles);
10475
10647
  }
10476
10648
  const neededExports = /* @__PURE__ */ new Map();
10477
10649
  for (const file of pages) {
10478
- const content = readFileSync14(file, "utf-8");
10650
+ const content = readFileSync15(file, "utf-8");
10479
10651
  const importRe = /import\s*\{([^}]+)\}\s*from\s*['"]@\/components\/ui\/([^'"]+)['"]/g;
10480
10652
  let m;
10481
10653
  while ((m = importRe.exec(content)) !== null) {
@@ -10496,7 +10668,7 @@ async function fixMissingComponentExports(projectRoot) {
10496
10668
  const provider = getComponentProvider();
10497
10669
  for (const [componentId, needed] of neededExports) {
10498
10670
  const componentFile = join14(uiDir, `${componentId}.tsx`);
10499
- if (!existsSync19(componentFile)) {
10671
+ if (!existsSync20(componentFile)) {
10500
10672
  if (provider.has(componentId)) {
10501
10673
  try {
10502
10674
  const result = await provider.installComponent(componentId, projectRoot);
@@ -10519,7 +10691,7 @@ async function fixMissingComponentExports(projectRoot) {
10519
10691
  }
10520
10692
  continue;
10521
10693
  }
10522
- const content = readFileSync14(componentFile, "utf-8");
10694
+ const content = readFileSync15(componentFile, "utf-8");
10523
10695
  const exportRe = /export\s+(?:const|function|class)\s+(\w+)|export\s*\{([^}]+)\}/g;
10524
10696
  const existingExports = /* @__PURE__ */ new Set();
10525
10697
  let em;
@@ -10554,7 +10726,7 @@ async function fixMissingComponentExports(projectRoot) {
10554
10726
  }
10555
10727
  async function backfillPageAnalysis(projectRoot) {
10556
10728
  const configPath = join14(projectRoot, "design-system.config.ts");
10557
- if (!existsSync19(configPath)) return;
10729
+ if (!existsSync20(configPath)) return;
10558
10730
  try {
10559
10731
  const mgr = new DesignSystemManager8(configPath);
10560
10732
  const config2 = mgr.getConfig();
@@ -10571,8 +10743,8 @@ async function backfillPageAnalysis(projectRoot) {
10571
10743
  } else {
10572
10744
  filePath = join14(projectRoot, "app", route.slice(1), "page.tsx");
10573
10745
  }
10574
- if (!existsSync19(filePath)) continue;
10575
- const code = readFileSync14(filePath, "utf-8");
10746
+ if (!existsSync20(filePath)) continue;
10747
+ const code = readFileSync15(filePath, "utf-8");
10576
10748
  if (code.length < 50) continue;
10577
10749
  page.pageAnalysis = analyzePageCode(code);
10578
10750
  changed = true;
@@ -10722,12 +10894,12 @@ async function openBrowser(url) {
10722
10894
  }
10723
10895
  }
10724
10896
  function startDevServer(projectRoot) {
10725
- const packageJsonPath = resolve10(projectRoot, "package.json");
10726
- if (!existsSync19(packageJsonPath)) {
10897
+ const packageJsonPath = resolve11(projectRoot, "package.json");
10898
+ if (!existsSync20(packageJsonPath)) {
10727
10899
  throw new Error('package.json not found. Run "coherent init" first.');
10728
10900
  }
10729
- const hasPnpm = existsSync19(resolve10(projectRoot, "pnpm-lock.yaml"));
10730
- const hasNpm = existsSync19(resolve10(projectRoot, "package-lock.json"));
10901
+ const hasPnpm = existsSync20(resolve11(projectRoot, "pnpm-lock.yaml"));
10902
+ const hasNpm = existsSync20(resolve11(projectRoot, "package-lock.json"));
10731
10903
  const command = hasPnpm ? "pnpm" : hasNpm ? "npm" : "npx";
10732
10904
  const args = hasPnpm ? ["dev", "--turbo"] : hasNpm ? ["run", "dev", "--", "--turbo"] : ["next", "dev", "--turbo"];
10733
10905
  const child = spawn(command, args, {
@@ -10774,7 +10946,7 @@ async function previewCommand() {
10774
10946
  if (needsGlobalsFix(projectRoot)) {
10775
10947
  spinner.text = "Fixing globals.css...";
10776
10948
  try {
10777
- const dsm = new DesignSystemManager8(resolve10(projectRoot, "design-system.config.ts"));
10949
+ const dsm = new DesignSystemManager8(resolve11(projectRoot, "design-system.config.ts"));
10778
10950
  await dsm.load();
10779
10951
  const config2 = dsm.getConfig();
10780
10952
  fixGlobalsCss(projectRoot, config2);
@@ -10783,6 +10955,20 @@ async function previewCommand() {
10783
10955
  spinner.warn("Could not auto-fix globals.css");
10784
10956
  }
10785
10957
  }
10958
+ if (isTailwindV4(projectRoot)) {
10959
+ const globalsPath = resolve11(projectRoot, "app", "globals.css");
10960
+ if (existsSync20(globalsPath)) {
10961
+ const globalsContent = readFileSync15(globalsPath, "utf-8");
10962
+ const cssIssues = validateV4GlobalsCss(globalsContent);
10963
+ if (cssIssues.length > 0) {
10964
+ console.log(chalk15.yellow("\n\u26A0\uFE0F globals.css validation warnings:"));
10965
+ for (const issue of cssIssues) {
10966
+ console.log(chalk15.yellow(` \u2022 ${issue}`));
10967
+ }
10968
+ console.log(chalk15.dim(' Run "coherent chat" to regenerate globals.css\n'));
10969
+ }
10970
+ }
10971
+ }
10786
10972
  spinner.text = "Pre-flight: dependencies and syntax...";
10787
10973
  await preflightDependencyCheck(projectRoot);
10788
10974
  clearStaleCache(projectRoot);
@@ -10813,8 +10999,8 @@ async function previewCommand() {
10813
10999
  import chalk16 from "chalk";
10814
11000
  import ora4 from "ora";
10815
11001
  import { spawn as spawn2 } from "child_process";
10816
- import { existsSync as existsSync20, rmSync as rmSync4, readdirSync as readdirSync6 } from "fs";
10817
- import { resolve as resolve11, join as join15, dirname as dirname7 } from "path";
11002
+ import { existsSync as existsSync21, rmSync as rmSync4, readdirSync as readdirSync7 } from "fs";
11003
+ import { resolve as resolve12, join as join15, dirname as dirname7 } from "path";
10818
11004
  import { readdir as readdir3, readFile as readFile6, writeFile as writeFile5, mkdir as mkdir5, copyFile as copyFile2 } from "fs/promises";
10819
11005
  var COPY_EXCLUDE = /* @__PURE__ */ new Set([
10820
11006
  "node_modules",
@@ -10848,17 +11034,17 @@ async function copyDir(src, dest) {
10848
11034
  }
10849
11035
  }
10850
11036
  function checkProjectInitialized2(projectRoot) {
10851
- return existsSync20(resolve11(projectRoot, "design-system.config.ts")) && existsSync20(resolve11(projectRoot, "package.json"));
11037
+ return existsSync21(resolve12(projectRoot, "design-system.config.ts")) && existsSync21(resolve12(projectRoot, "package.json"));
10852
11038
  }
10853
11039
  function getPackageManager2(projectRoot) {
10854
- if (existsSync20(resolve11(projectRoot, "pnpm-lock.yaml"))) return "pnpm";
10855
- if (existsSync20(resolve11(projectRoot, "package-lock.json"))) return "npm";
11040
+ if (existsSync21(resolve12(projectRoot, "pnpm-lock.yaml"))) return "pnpm";
11041
+ if (existsSync21(resolve12(projectRoot, "package-lock.json"))) return "npm";
10856
11042
  return "npx";
10857
11043
  }
10858
11044
  async function patchNextConfigForExport(outRoot) {
10859
11045
  for (const name of ["next.config.ts", "next.config.mjs", "next.config.js"]) {
10860
11046
  const p = join15(outRoot, name);
10861
- if (!existsSync20(p)) continue;
11047
+ if (!existsSync21(p)) continue;
10862
11048
  let content = await readFile6(p, "utf-8");
10863
11049
  if (content.includes("ignoreDuringBuilds")) return;
10864
11050
  content = content.replace(
@@ -10873,9 +11059,9 @@ async function buildProduction(projectRoot) {
10873
11059
  const pm = getPackageManager2(projectRoot);
10874
11060
  const command = pm === "pnpm" ? "pnpm" : pm === "npm" ? "npm" : "npx";
10875
11061
  const args = pm === "npx" ? ["next", "build"] : ["run", "build"];
10876
- return new Promise((resolve16, reject) => {
11062
+ return new Promise((resolve17, reject) => {
10877
11063
  const child = spawn2(command, args, { cwd: projectRoot, stdio: "inherit", shell: true });
10878
- child.on("exit", (code) => code === 0 ? resolve16() : reject(new Error(`Build failed with exit code ${code}`)));
11064
+ child.on("exit", (code) => code === 0 ? resolve17() : reject(new Error(`Build failed with exit code ${code}`)));
10879
11065
  child.on("error", (error) => reject(new Error(`Failed to start build: ${error.message}`)));
10880
11066
  });
10881
11067
  }
@@ -10900,7 +11086,7 @@ EXPOSE 3000
10900
11086
  `;
10901
11087
  async function ensureReadmeDeploySection(outRoot) {
10902
11088
  const readmePath = join15(outRoot, "README.md");
10903
- if (!existsSync20(readmePath)) return;
11089
+ if (!existsSync21(readmePath)) return;
10904
11090
  try {
10905
11091
  let content = await readFile6(readmePath, "utf-8");
10906
11092
  if (/##\s+Deploy\b/m.test(content)) return;
@@ -10925,16 +11111,16 @@ async function countPages(outRoot) {
10925
11111
  }
10926
11112
  }
10927
11113
  const appDir = join15(outRoot, "app");
10928
- if (existsSync20(appDir)) await walk(appDir);
11114
+ if (existsSync21(appDir)) await walk(appDir);
10929
11115
  return n;
10930
11116
  }
10931
11117
  function countComponents(outRoot) {
10932
11118
  let n = 0;
10933
11119
  for (const sub of ["ui", "shared"]) {
10934
11120
  const dir = join15(outRoot, "components", sub);
10935
- if (!existsSync20(dir)) continue;
11121
+ if (!existsSync21(dir)) continue;
10936
11122
  try {
10937
- n += readdirSync6(dir).filter((f) => f.endsWith(".tsx") || f.endsWith(".jsx")).length;
11123
+ n += readdirSync7(dir).filter((f) => f.endsWith(".tsx") || f.endsWith(".jsx")).length;
10938
11124
  } catch {
10939
11125
  }
10940
11126
  }
@@ -10943,7 +11129,7 @@ function countComponents(outRoot) {
10943
11129
  var IMPORT_FROM_REGEX2 = /from\s+['"]([^'"]+)['"]/g;
10944
11130
  async function collectImportedPackages2(dir, extensions) {
10945
11131
  const packages = /* @__PURE__ */ new Set();
10946
- if (!existsSync20(dir)) return packages;
11132
+ if (!existsSync21(dir)) return packages;
10947
11133
  async function walk(d) {
10948
11134
  const entries = await readdir3(d, { withFileTypes: true });
10949
11135
  for (const e of entries) {
@@ -10971,7 +11157,7 @@ async function collectImportedPackages2(dir, extensions) {
10971
11157
  }
10972
11158
  async function findMissingDepsInExport(outRoot) {
10973
11159
  const pkgPath = join15(outRoot, "package.json");
10974
- if (!existsSync20(pkgPath)) return [];
11160
+ if (!existsSync21(pkgPath)) return [];
10975
11161
  let pkg;
10976
11162
  try {
10977
11163
  pkg = JSON.parse(await readFile6(pkgPath, "utf-8"));
@@ -10992,25 +11178,25 @@ async function stripCoherentArtifacts(outputDir) {
10992
11178
  const removed = [];
10993
11179
  for (const p of ["app/design-system", "app/api/design-system"]) {
10994
11180
  const full = join15(outputDir, p);
10995
- if (existsSync20(full)) {
11181
+ if (existsSync21(full)) {
10996
11182
  rmSync4(full, { recursive: true, force: true });
10997
11183
  removed.push(p);
10998
11184
  }
10999
11185
  }
11000
11186
  const appNavPath = join15(outputDir, "app", "AppNav.tsx");
11001
- if (existsSync20(appNavPath)) {
11187
+ if (existsSync21(appNavPath)) {
11002
11188
  rmSync4(appNavPath, { force: true });
11003
11189
  removed.push("app/AppNav.tsx");
11004
11190
  }
11005
11191
  const layoutPath = join15(outputDir, "app", "layout.tsx");
11006
- if (existsSync20(layoutPath)) {
11192
+ if (existsSync21(layoutPath)) {
11007
11193
  let layout = await readFile6(layoutPath, "utf-8");
11008
11194
  layout = layout.replace(/import\s*\{?\s*AppNav\s*\}?\s*from\s*['"][^'"]+['"]\s*\n?/g, "");
11009
11195
  layout = layout.replace(/\s*<AppNav\s*\/?\s*>\s*/g, "\n");
11010
11196
  await writeFile5(layoutPath, layout, "utf-8");
11011
11197
  }
11012
11198
  const sharedHeaderPath = join15(outputDir, "components", "shared", "header.tsx");
11013
- if (existsSync20(sharedHeaderPath)) {
11199
+ if (existsSync21(sharedHeaderPath)) {
11014
11200
  let header = await readFile6(sharedHeaderPath, "utf-8");
11015
11201
  header = header.replace(/<Link\s[^>]*href="\/design-system"[^>]*>[\s\S]*?<\/Link>/g, "");
11016
11202
  header = header.replace(/\n\s*<>\s*\n/, "\n");
@@ -11018,7 +11204,7 @@ async function stripCoherentArtifacts(outputDir) {
11018
11204
  await writeFile5(sharedHeaderPath, header, "utf-8");
11019
11205
  }
11020
11206
  const guardPath2 = join15(outputDir, "app", "ShowWhenNotAuthRoute.tsx");
11021
- if (existsSync20(guardPath2)) {
11207
+ if (existsSync21(guardPath2)) {
11022
11208
  let guard = await readFile6(guardPath2, "utf-8");
11023
11209
  guard = guard.replace(/['"],?\s*'\/design-system['"],?\s*/g, "");
11024
11210
  const pathsMatch = guard.match(/HIDDEN_PATHS\s*=\s*\[([^\]]*)\]/);
@@ -11026,7 +11212,7 @@ async function stripCoherentArtifacts(outputDir) {
11026
11212
  if (remaining.length === 0) {
11027
11213
  rmSync4(guardPath2, { force: true });
11028
11214
  removed.push("app/ShowWhenNotAuthRoute.tsx");
11029
- if (existsSync20(layoutPath)) {
11215
+ if (existsSync21(layoutPath)) {
11030
11216
  let layout = await readFile6(layoutPath, "utf-8");
11031
11217
  layout = layout.replace(/import\s+\w+\s+from\s*['"]\.\/ShowWhenNotAuthRoute['"]\s*\n?/g, "");
11032
11218
  layout = layout.replace(/\s*<ShowWhenNotAuthRoute>\s*\n?/g, "\n");
@@ -11047,14 +11233,14 @@ async function stripCoherentArtifacts(outputDir) {
11047
11233
  "recommendations.md"
11048
11234
  ]) {
11049
11235
  const full = join15(outputDir, name);
11050
- if (existsSync20(full)) {
11236
+ if (existsSync21(full)) {
11051
11237
  rmSync4(full, { force: true });
11052
11238
  removed.push(name);
11053
11239
  }
11054
11240
  }
11055
11241
  for (const dir of [".claude", ".coherent"]) {
11056
11242
  const full = join15(outputDir, dir);
11057
- if (existsSync20(full)) {
11243
+ if (existsSync21(full)) {
11058
11244
  rmSync4(full, { recursive: true, force: true });
11059
11245
  removed.push(dir + "/");
11060
11246
  }
@@ -11062,7 +11248,7 @@ async function stripCoherentArtifacts(outputDir) {
11062
11248
  return removed;
11063
11249
  }
11064
11250
  async function exportCommand(options = {}) {
11065
- const outputDir = resolve11(process.cwd(), options.output ?? "./export");
11251
+ const outputDir = resolve12(process.cwd(), options.output ?? "./export");
11066
11252
  const doBuild = options.build !== false;
11067
11253
  const keepDs = options.keepDs === true;
11068
11254
  const spinner = ora4("Preparing export...").start();
@@ -11078,7 +11264,7 @@ async function exportCommand(options = {}) {
11078
11264
  process.exit(1);
11079
11265
  }
11080
11266
  spinner.text = "Copying project...";
11081
- if (existsSync20(outputDir)) rmSync4(outputDir, { recursive: true, force: true });
11267
+ if (existsSync21(outputDir)) rmSync4(outputDir, { recursive: true, force: true });
11082
11268
  await copyDir(projectRoot, outputDir);
11083
11269
  spinner.succeed("Project copied");
11084
11270
  if (!keepDs) {
@@ -11253,8 +11439,8 @@ async function regenerateDocsCommand() {
11253
11439
 
11254
11440
  // src/commands/fix.ts
11255
11441
  import chalk19 from "chalk";
11256
- import { readdirSync as readdirSync7, readFileSync as readFileSync15, existsSync as existsSync21, writeFileSync as writeFileSync11, rmSync as rmSync5, mkdirSync as mkdirSync7 } from "fs";
11257
- import { resolve as resolve12, join as join16 } from "path";
11442
+ import { readdirSync as readdirSync8, readFileSync as readFileSync16, existsSync as existsSync22, writeFileSync as writeFileSync11, rmSync as rmSync5, mkdirSync as mkdirSync7 } from "fs";
11443
+ import { resolve as resolve13, join as join16 } from "path";
11258
11444
  import {
11259
11445
  DesignSystemManager as DesignSystemManager11,
11260
11446
  ComponentManager as ComponentManager6,
@@ -11278,7 +11464,7 @@ function extractComponentIdsFromCode2(code) {
11278
11464
  function listTsxFiles(dir) {
11279
11465
  const files = [];
11280
11466
  try {
11281
- const entries = readdirSync7(dir, { withFileTypes: true });
11467
+ const entries = readdirSync8(dir, { withFileTypes: true });
11282
11468
  for (const e of entries) {
11283
11469
  const full = join16(dir, e.name);
11284
11470
  if (e.isDirectory() && e.name !== "node_modules" && !e.name.startsWith(".")) {
@@ -11310,7 +11496,7 @@ async function fixCommand(opts = {}) {
11310
11496
  }
11311
11497
  if (!skipCache) {
11312
11498
  const nextDir = join16(projectRoot, ".next");
11313
- if (existsSync21(nextDir)) {
11499
+ if (existsSync22(nextDir)) {
11314
11500
  if (!dryRun) rmSync5(nextDir, { recursive: true, force: true });
11315
11501
  fixes.push("Cleared build cache");
11316
11502
  console.log(chalk19.green(" \u2714 Cleared build cache"));
@@ -11332,12 +11518,12 @@ async function fixCommand(opts = {}) {
11332
11518
  }
11333
11519
  }
11334
11520
  }
11335
- const appDir = resolve12(projectRoot, "app");
11521
+ const appDir = resolve13(projectRoot, "app");
11336
11522
  const allTsxFiles = listTsxFiles(appDir);
11337
- const componentsTsxFiles = listTsxFiles(resolve12(projectRoot, "components"));
11523
+ const componentsTsxFiles = listTsxFiles(resolve13(projectRoot, "components"));
11338
11524
  const allComponentIds = /* @__PURE__ */ new Set();
11339
11525
  for (const file of [...allTsxFiles, ...componentsTsxFiles]) {
11340
- const content = readFileSync15(file, "utf-8");
11526
+ const content = readFileSync16(file, "utf-8");
11341
11527
  extractComponentIdsFromCode2(content).forEach((id) => allComponentIds.add(id));
11342
11528
  }
11343
11529
  let dsm = null;
@@ -11356,8 +11542,8 @@ async function fixCommand(opts = {}) {
11356
11542
  missingComponents.push(id);
11357
11543
  } else {
11358
11544
  const fileName = toKebabCase(id) + ".tsx";
11359
- const filePath = resolve12(projectRoot, "components", "ui", fileName);
11360
- if (!existsSync21(filePath)) missingFiles.push(id);
11545
+ const filePath = resolve13(projectRoot, "components", "ui", fileName);
11546
+ if (!existsSync22(filePath)) missingFiles.push(id);
11361
11547
  }
11362
11548
  }
11363
11549
  const provider = getComponentProvider();
@@ -11386,8 +11572,8 @@ async function fixCommand(opts = {}) {
11386
11572
  const generator = new ComponentGenerator4(updatedConfig);
11387
11573
  const code = await generator.generate(component);
11388
11574
  const fileName = toKebabCase(component.name) + ".tsx";
11389
- const filePath = resolve12(projectRoot, "components", "ui", fileName);
11390
- mkdirSync7(resolve12(projectRoot, "components", "ui"), { recursive: true });
11575
+ const filePath = resolve13(projectRoot, "components", "ui", fileName);
11576
+ mkdirSync7(resolve13(projectRoot, "components", "ui"), { recursive: true });
11391
11577
  await writeFile(filePath, code);
11392
11578
  }
11393
11579
  }
@@ -11409,7 +11595,7 @@ async function fixCommand(opts = {}) {
11409
11595
  const userTsxFiles = allTsxFiles.filter((f) => !f.includes("/design-system/"));
11410
11596
  let syntaxFixed = 0;
11411
11597
  for (const file of userTsxFiles) {
11412
- const content = readFileSync15(file, "utf-8");
11598
+ const content = readFileSync16(file, "utf-8");
11413
11599
  const fixed = fixUnescapedLtInJsx(
11414
11600
  fixEscapedClosingQuotes(sanitizeMetadataStrings(ensureUseClientIfNeeded(content)))
11415
11601
  );
@@ -11427,7 +11613,7 @@ async function fixCommand(opts = {}) {
11427
11613
  let qualityFixCount = 0;
11428
11614
  const qualityFixDetails = [];
11429
11615
  for (const file of userTsxFiles) {
11430
- const content = readFileSync15(file, "utf-8");
11616
+ const content = readFileSync16(file, "utf-8");
11431
11617
  const { code: autoFixed, fixes: fileFixes } = await autoFixCode(content);
11432
11618
  if (autoFixed !== content) {
11433
11619
  if (!dryRun) writeFileSync11(file, autoFixed, "utf-8");
@@ -11446,7 +11632,7 @@ async function fixCommand(opts = {}) {
11446
11632
  let totalWarnings = 0;
11447
11633
  const fileIssues = [];
11448
11634
  for (const file of allTsxFiles) {
11449
- const code = dryRun ? readFileSync15(file, "utf-8") : readFileSync15(file, "utf-8");
11635
+ const code = dryRun ? readFileSync16(file, "utf-8") : readFileSync16(file, "utf-8");
11450
11636
  const relativePath = file.replace(projectRoot + "/", "");
11451
11637
  const baseName = file.split("/").pop() || "";
11452
11638
  const isAuthPage = relativePath.includes("(auth)");
@@ -11568,17 +11754,17 @@ async function fixCommand(opts = {}) {
11568
11754
 
11569
11755
  // src/commands/check.ts
11570
11756
  import chalk20 from "chalk";
11571
- import { resolve as resolve13 } from "path";
11572
- import { readdirSync as readdirSync8, readFileSync as readFileSync16, statSync as statSync2, existsSync as existsSync22 } from "fs";
11757
+ import { resolve as resolve14 } from "path";
11758
+ import { readdirSync as readdirSync9, readFileSync as readFileSync17, statSync as statSync3, existsSync as existsSync23 } from "fs";
11573
11759
  import { loadManifest as loadManifest11 } from "@getcoherent/core";
11574
11760
  var EXCLUDED_DIRS = /* @__PURE__ */ new Set(["node_modules", "design-system"]);
11575
11761
  function findTsxFiles(dir) {
11576
11762
  const results = [];
11577
11763
  try {
11578
- const entries = readdirSync8(dir);
11764
+ const entries = readdirSync9(dir);
11579
11765
  for (const entry of entries) {
11580
- const full = resolve13(dir, entry);
11581
- const stat = statSync2(full);
11766
+ const full = resolve14(dir, entry);
11767
+ const stat = statSync3(full);
11582
11768
  if (stat.isDirectory() && !entry.startsWith(".") && !EXCLUDED_DIRS.has(entry)) {
11583
11769
  results.push(...findTsxFiles(full));
11584
11770
  } else if (entry.endsWith(".tsx")) {
@@ -11612,7 +11798,7 @@ async function checkCommand(opts = {}) {
11612
11798
  } catch {
11613
11799
  }
11614
11800
  if (!skipPages) {
11615
- const appDir = resolve13(projectRoot, "app");
11801
+ const appDir = resolve14(projectRoot, "app");
11616
11802
  const files = findTsxFiles(appDir);
11617
11803
  result.pages.total = files.length;
11618
11804
  if (!opts.json) console.log(chalk20.cyan("\n \u{1F4C4} Pages") + chalk20.dim(` (${files.length} scanned)
@@ -11626,7 +11812,7 @@ async function checkCommand(opts = {}) {
11626
11812
  "NATIVE_TABLE"
11627
11813
  ]);
11628
11814
  for (const file of files) {
11629
- const code = readFileSync16(file, "utf-8");
11815
+ const code = readFileSync17(file, "utf-8");
11630
11816
  const relativePath = file.replace(projectRoot + "/", "");
11631
11817
  const baseName = file.split("/").pop() || "";
11632
11818
  const isAuthPage = relativePath.includes("(auth)");
@@ -11668,7 +11854,7 @@ async function checkCommand(opts = {}) {
11668
11854
  routeSet.add("/");
11669
11855
  routeSet.add("#");
11670
11856
  for (const file of files) {
11671
- const code = readFileSync16(file, "utf-8");
11857
+ const code = readFileSync17(file, "utf-8");
11672
11858
  const relativePath = file.replace(projectRoot + "/", "");
11673
11859
  const lines = code.split("\n");
11674
11860
  const linkHrefRe = /href\s*=\s*["'](\/[a-z0-9/-]*)["']/gi;
@@ -11700,8 +11886,8 @@ async function checkCommand(opts = {}) {
11700
11886
  const manifest = await loadManifest11(project.root);
11701
11887
  if (manifest.shared.length > 0) {
11702
11888
  for (const entry of manifest.shared) {
11703
- const fullPath = resolve13(project.root, entry.file);
11704
- if (!existsSync22(fullPath)) {
11889
+ const fullPath = resolve14(project.root, entry.file);
11890
+ if (!existsSync23(fullPath)) {
11705
11891
  result.pages.withErrors++;
11706
11892
  if (!opts.json) console.log(chalk20.red(`
11707
11893
  \u2717 Missing shared component file: ${entry.id} (${entry.file})`));
@@ -11725,8 +11911,8 @@ async function checkCommand(opts = {}) {
11725
11911
  let _staleUsedIn = 0;
11726
11912
  let _nameMismatch = 0;
11727
11913
  for (const entry of manifest.shared) {
11728
- const filePath = resolve13(projectRoot, entry.file);
11729
- const fileExists = existsSync22(filePath);
11914
+ const filePath = resolve14(projectRoot, entry.file);
11915
+ const fileExists = existsSync23(filePath);
11730
11916
  if (!fileExists) {
11731
11917
  _orphaned++;
11732
11918
  if (!opts.json) {
@@ -11736,7 +11922,7 @@ async function checkCommand(opts = {}) {
11736
11922
  continue;
11737
11923
  }
11738
11924
  try {
11739
- const code = readFileSync16(filePath, "utf-8");
11925
+ const code = readFileSync17(filePath, "utf-8");
11740
11926
  const actualExports = extractExportedComponentNames(code);
11741
11927
  if (actualExports.length > 0 && !actualExports.includes(entry.name)) {
11742
11928
  _nameMismatch++;
@@ -11804,7 +11990,7 @@ async function checkCommand(opts = {}) {
11804
11990
  id: e.id,
11805
11991
  name: e.name,
11806
11992
  type: e.type,
11807
- status: existsSync22(resolve13(projectRoot, e.file)) ? "ok" : "unused",
11993
+ status: existsSync23(resolve14(projectRoot, e.file)) ? "ok" : "unused",
11808
11994
  message: "",
11809
11995
  suggestions: void 0
11810
11996
  }))
@@ -11899,8 +12085,8 @@ import {
11899
12085
  generateSharedComponent as generateSharedComponent5,
11900
12086
  integrateSharedLayoutIntoRootLayout as integrateSharedLayoutIntoRootLayout3
11901
12087
  } from "@getcoherent/core";
11902
- import { existsSync as existsSync23 } from "fs";
11903
- import { resolve as resolve14 } from "path";
12088
+ import { existsSync as existsSync24 } from "fs";
12089
+ import { resolve as resolve15 } from "path";
11904
12090
 
11905
12091
  // src/utils/ds-files.ts
11906
12092
  import { mkdir as mkdir6, writeFile as writeFile6 } from "fs/promises";
@@ -12030,8 +12216,8 @@ function createComponentsCommand() {
12030
12216
  const updated = await integrateSharedLayoutIntoRootLayout3(project.root);
12031
12217
  if (updated) console.log(chalk26.cyan(" Updated app/layout.tsx to use shared layout components.\n"));
12032
12218
  }
12033
- const sharedPagePath = resolve14(project.root, "app/design-system/shared/page.tsx");
12034
- if (!existsSync23(sharedPagePath)) {
12219
+ const sharedPagePath = resolve15(project.root, "app/design-system/shared/page.tsx");
12220
+ if (!existsSync24(sharedPagePath)) {
12035
12221
  try {
12036
12222
  const dsm = new DesignSystemManager12(project.configPath);
12037
12223
  await dsm.load();
@@ -12057,8 +12243,8 @@ function createComponentsCommand() {
12057
12243
  import chalk27 from "chalk";
12058
12244
  import ora6 from "ora";
12059
12245
  import { writeFile as writeFile7, mkdir as mkdir7 } from "fs/promises";
12060
- import { resolve as resolve15, join as join18, dirname as dirname9 } from "path";
12061
- import { existsSync as existsSync24 } from "fs";
12246
+ import { resolve as resolve16, join as join18, dirname as dirname9 } from "path";
12247
+ import { existsSync as existsSync25 } from "fs";
12062
12248
  import {
12063
12249
  FigmaClient,
12064
12250
  parseFigmaFileResponse,
@@ -12282,7 +12468,7 @@ async function importFigmaAction(urlOrKey, opts) {
12282
12468
  if (dryRun) stats.filesWritten.push(FIGMA_COMPONENT_MAP_FILENAME);
12283
12469
  else
12284
12470
  await writeFile7(
12285
- resolve15(projectRoot, FIGMA_COMPONENT_MAP_FILENAME),
12471
+ resolve16(projectRoot, FIGMA_COMPONENT_MAP_FILENAME),
12286
12472
  JSON.stringify(componentMapObj, null, 2),
12287
12473
  "utf-8"
12288
12474
  );
@@ -12305,9 +12491,9 @@ async function importFigmaAction(urlOrKey, opts) {
12305
12491
  const fullConfig = buildFigmaImportConfig(mergedConfig, pageDefs, intermediate.fileName);
12306
12492
  if (!dryRun) {
12307
12493
  spinner.start("Updating design-system.config.ts...");
12308
- const configPath = resolve15(projectRoot, DESIGN_SYSTEM_CONFIG_PATH);
12494
+ const configPath = resolve16(projectRoot, DESIGN_SYSTEM_CONFIG_PATH);
12309
12495
  const dsm = new DesignSystemManager13(configPath);
12310
- if (existsSync24(configPath)) {
12496
+ if (existsSync25(configPath)) {
12311
12497
  await dsm.load();
12312
12498
  const existing = dsm.getConfig();
12313
12499
  dsm.updateConfig({
@@ -12337,7 +12523,7 @@ export const config = ${JSON.stringify(fullConfig, null, 2)} as const
12337
12523
  spinner.succeed("design-system.config.ts updated");
12338
12524
  spinner.start("Ensuring root layout...");
12339
12525
  const layoutPath = join18(projectRoot, "app/layout.tsx");
12340
- if (!existsSync24(layoutPath)) {
12526
+ if (!existsSync25(layoutPath)) {
12341
12527
  await mkdir7(dirname9(layoutPath), { recursive: true });
12342
12528
  await writeFile7(layoutPath, MINIMAL_ROOT_LAYOUT, "utf-8");
12343
12529
  stats.filesWritten.push("app/layout.tsx");
@@ -12427,7 +12613,7 @@ async function dsRegenerateCommand() {
12427
12613
  // src/commands/update.ts
12428
12614
  import chalk29 from "chalk";
12429
12615
  import ora8 from "ora";
12430
- import { readFileSync as readFileSync17, existsSync as existsSync25 } from "fs";
12616
+ import { readFileSync as readFileSync18, existsSync as existsSync26 } from "fs";
12431
12617
  import { join as join19 } from "path";
12432
12618
  import { DesignSystemManager as DesignSystemManager15, CLI_VERSION as CLI_VERSION4 } from "@getcoherent/core";
12433
12619
 
@@ -12598,9 +12784,9 @@ var EXPECTED_CSS_VARS = [
12598
12784
  ];
12599
12785
  function checkMissingCssVars(projectRoot) {
12600
12786
  const globalsPath = join19(projectRoot, "app", "globals.css");
12601
- if (!existsSync25(globalsPath)) return [];
12787
+ if (!existsSync26(globalsPath)) return [];
12602
12788
  try {
12603
- const content = readFileSync17(globalsPath, "utf-8");
12789
+ const content = readFileSync18(globalsPath, "utf-8");
12604
12790
  return EXPECTED_CSS_VARS.filter((v) => !content.includes(v));
12605
12791
  } catch {
12606
12792
  return [];
@@ -12608,9 +12794,9 @@ function checkMissingCssVars(projectRoot) {
12608
12794
  }
12609
12795
  function patchGlobalsCss(projectRoot, missingVars) {
12610
12796
  const globalsPath = join19(projectRoot, "app", "globals.css");
12611
- if (!existsSync25(globalsPath) || missingVars.length === 0) return;
12797
+ if (!existsSync26(globalsPath) || missingVars.length === 0) return;
12612
12798
  const { writeFileSync: writeFileSync14 } = __require("fs");
12613
- let content = readFileSync17(globalsPath, "utf-8");
12799
+ let content = readFileSync18(globalsPath, "utf-8");
12614
12800
  const defaultValues = {
12615
12801
  "--chart-1": "220 70% 50%",
12616
12802
  "--chart-2": "160 60% 45%",
@@ -12688,7 +12874,7 @@ async function undoCommand(options) {
12688
12874
  // src/commands/sync.ts
12689
12875
  import chalk31 from "chalk";
12690
12876
  import ora9 from "ora";
12691
- import { existsSync as existsSync26, readFileSync as readFileSync18 } from "fs";
12877
+ import { existsSync as existsSync27, readFileSync as readFileSync19 } from "fs";
12692
12878
  import { join as join20, relative as relative5, dirname as dirname10 } from "path";
12693
12879
  import { readdir as readdir4, readFile as readFile7 } from "fs/promises";
12694
12880
  import { DesignSystemManager as DesignSystemManager16 } from "@getcoherent/core";
@@ -12697,8 +12883,8 @@ function extractTokensFromProject(projectRoot) {
12697
12883
  const lightColors = {};
12698
12884
  const darkColors = {};
12699
12885
  const globalsPath = join20(projectRoot, "app", "globals.css");
12700
- if (existsSync26(globalsPath)) {
12701
- const css = readFileSync18(globalsPath, "utf-8");
12886
+ if (existsSync27(globalsPath)) {
12887
+ const css = readFileSync19(globalsPath, "utf-8");
12702
12888
  const rootMatch = css.match(/:root\s*\{([^}]+)\}/s);
12703
12889
  if (rootMatch) parseVarsInto(rootMatch[1], lightColors);
12704
12890
  const darkMatch = css.match(/\.dark\s*\{([^}]+)\}/s);
@@ -12706,8 +12892,8 @@ function extractTokensFromProject(projectRoot) {
12706
12892
  }
12707
12893
  const layoutPath = join20(projectRoot, "app", "layout.tsx");
12708
12894
  let layoutCode = "";
12709
- if (existsSync26(layoutPath)) {
12710
- layoutCode = readFileSync18(layoutPath, "utf-8");
12895
+ if (existsSync27(layoutPath)) {
12896
+ layoutCode = readFileSync19(layoutPath, "utf-8");
12711
12897
  const rootInline = layoutCode.match(/:root\s*\{([^}]+)\}/s);
12712
12898
  if (rootInline && Object.keys(lightColors).length === 0) {
12713
12899
  parseVarsInto(rootInline[1], lightColors);
@@ -12725,7 +12911,7 @@ function extractTokensFromProject(projectRoot) {
12725
12911
  defaultMode = "dark";
12726
12912
  }
12727
12913
  let radius;
12728
- const allCss = [existsSync26(globalsPath) ? readFileSync18(globalsPath, "utf-8") : "", layoutCode].join("\n");
12914
+ const allCss = [existsSync27(globalsPath) ? readFileSync19(globalsPath, "utf-8") : "", layoutCode].join("\n");
12729
12915
  const radiusMatch = allCss.match(/--radius:\s*([^;]+);/);
12730
12916
  if (radiusMatch) radius = radiusMatch[1].trim();
12731
12917
  return {
@@ -12749,7 +12935,7 @@ function parseVarsInto(block, target) {
12749
12935
  async function detectCustomComponents(projectRoot, allPageCode) {
12750
12936
  const results = [];
12751
12937
  const componentsDir = join20(projectRoot, "components");
12752
- if (!existsSync26(componentsDir)) return results;
12938
+ if (!existsSync27(componentsDir)) return results;
12753
12939
  const files = [];
12754
12940
  await walkForTsx(componentsDir, files, ["ui"]);
12755
12941
  const fileResults = await Promise.all(
@@ -12928,7 +13114,7 @@ async function syncCommand(options = {}) {
12928
13114
  const spinner = ora9("Scanning project files...").start();
12929
13115
  try {
12930
13116
  const appDir = join20(project.root, "app");
12931
- if (!existsSync26(appDir)) {
13117
+ if (!existsSync27(appDir)) {
12932
13118
  spinner.fail("No app/ directory found");
12933
13119
  process.exit(1);
12934
13120
  }
@@ -13155,7 +13341,7 @@ async function syncCommand(options = {}) {
13155
13341
  // src/commands/migrate.ts
13156
13342
  import chalk32 from "chalk";
13157
13343
  import ora10 from "ora";
13158
- import { existsSync as existsSync27, mkdirSync as mkdirSync8, cpSync, rmSync as rmSync6, writeFileSync as writeFileSync12, readFileSync as readFileSync19, readdirSync as readdirSync9 } from "fs";
13344
+ import { existsSync as existsSync28, mkdirSync as mkdirSync8, cpSync, rmSync as rmSync6, writeFileSync as writeFileSync12, readFileSync as readFileSync20, readdirSync as readdirSync10 } from "fs";
13159
13345
  import { join as join21 } from "path";
13160
13346
  function backupDir(projectRoot) {
13161
13347
  const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
@@ -13168,11 +13354,11 @@ function createBackup2(projectRoot) {
13168
13354
  const uiDir = join21(projectRoot, "components", "ui");
13169
13355
  const dest = backupDir(projectRoot);
13170
13356
  mkdirSync8(dest, { recursive: true });
13171
- if (existsSync27(uiDir)) {
13357
+ if (existsSync28(uiDir)) {
13172
13358
  cpSync(uiDir, join21(dest, "components-ui"), { recursive: true });
13173
13359
  }
13174
13360
  const configPath = join21(projectRoot, "design-system.config.ts");
13175
- if (existsSync27(configPath)) {
13361
+ if (existsSync28(configPath)) {
13176
13362
  cpSync(configPath, join21(dest, "design-system.config.ts"));
13177
13363
  }
13178
13364
  return dest;
@@ -13184,24 +13370,24 @@ function setGuard(projectRoot, backupPath) {
13184
13370
  }
13185
13371
  function clearGuard(projectRoot) {
13186
13372
  const guard = guardPath(projectRoot);
13187
- if (existsSync27(guard)) rmSync6(guard);
13373
+ if (existsSync28(guard)) rmSync6(guard);
13188
13374
  }
13189
13375
  function rollback(projectRoot) {
13190
13376
  const guard = guardPath(projectRoot);
13191
- if (!existsSync27(guard)) return false;
13377
+ if (!existsSync28(guard)) return false;
13192
13378
  try {
13193
- const data = JSON.parse(readFileSync19(guard, "utf-8"));
13379
+ const data = JSON.parse(readFileSync20(guard, "utf-8"));
13194
13380
  const backup = data.backup;
13195
- if (!existsSync27(backup)) return false;
13381
+ if (!existsSync28(backup)) return false;
13196
13382
  const uiBackup = join21(backup, "components-ui");
13197
13383
  const uiDir = join21(projectRoot, "components", "ui");
13198
- if (existsSync27(uiBackup)) {
13199
- if (existsSync27(uiDir)) rmSync6(uiDir, { recursive: true });
13384
+ if (existsSync28(uiBackup)) {
13385
+ if (existsSync28(uiDir)) rmSync6(uiDir, { recursive: true });
13200
13386
  cpSync(uiBackup, uiDir, { recursive: true });
13201
13387
  }
13202
13388
  const configBackup = join21(backup, "design-system.config.ts");
13203
13389
  const configDest = join21(projectRoot, "design-system.config.ts");
13204
- if (existsSync27(configBackup)) {
13390
+ if (existsSync28(configBackup)) {
13205
13391
  cpSync(configBackup, configDest);
13206
13392
  }
13207
13393
  clearGuard(projectRoot);
@@ -13229,19 +13415,19 @@ async function migrateAction(options) {
13229
13415
  return;
13230
13416
  }
13231
13417
  const guard = guardPath(projectRoot);
13232
- if (existsSync27(guard)) {
13418
+ if (existsSync28(guard)) {
13233
13419
  console.log(chalk32.yellow("A migration is already in progress."));
13234
13420
  console.log(chalk32.dim("Run `coherent migrate --rollback` to undo, or delete .coherent/migration-in-progress"));
13235
13421
  return;
13236
13422
  }
13237
13423
  const uiDir = join21(projectRoot, "components", "ui");
13238
- if (!existsSync27(uiDir)) {
13424
+ if (!existsSync28(uiDir)) {
13239
13425
  console.log(chalk32.yellow("No components/ui directory found. Nothing to migrate."));
13240
13426
  return;
13241
13427
  }
13242
13428
  const provider = getComponentProvider();
13243
13429
  const managedIds = new Set(provider.listNames());
13244
- const files = readdirSync9(uiDir).filter((f) => f.endsWith(".tsx"));
13430
+ const files = readdirSync10(uiDir).filter((f) => f.endsWith(".tsx"));
13245
13431
  const migratable = files.map((f) => f.replace(".tsx", "")).filter((id) => managedIds.has(id));
13246
13432
  if (migratable.length === 0) {
13247
13433
  console.log(chalk32.green("All components are already up to date."));
@@ -13262,7 +13448,7 @@ Found ${migratable.length} component(s) to migrate:`));
13262
13448
  try {
13263
13449
  for (const id of migratable) {
13264
13450
  const filePath = join21(uiDir, `${id}.tsx`);
13265
- if (existsSync27(filePath)) rmSync6(filePath);
13451
+ if (existsSync28(filePath)) rmSync6(filePath);
13266
13452
  }
13267
13453
  const results = await provider.installBatch(migratable, projectRoot, { force: true });
13268
13454
  let migrated = 0;
@@ -13284,7 +13470,7 @@ Found ${migratable.length} component(s) to migrate:`));
13284
13470
  }
13285
13471
 
13286
13472
  // src/utils/update-notifier.ts
13287
- import { existsSync as existsSync28, mkdirSync as mkdirSync9, readFileSync as readFileSync20, writeFileSync as writeFileSync13 } from "fs";
13473
+ import { existsSync as existsSync29, mkdirSync as mkdirSync9, readFileSync as readFileSync21, writeFileSync as writeFileSync13 } from "fs";
13288
13474
  import { join as join22 } from "path";
13289
13475
  import { homedir } from "os";
13290
13476
  import chalk33 from "chalk";
@@ -13296,8 +13482,8 @@ var CACHE_FILE = join22(CACHE_DIR, "update-check.json");
13296
13482
  var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
13297
13483
  function readCache() {
13298
13484
  try {
13299
- if (!existsSync28(CACHE_FILE)) return null;
13300
- const raw = readFileSync20(CACHE_FILE, "utf-8");
13485
+ if (!existsSync29(CACHE_FILE)) return null;
13486
+ const raw = readFileSync21(CACHE_FILE, "utf-8");
13301
13487
  return JSON.parse(raw);
13302
13488
  } catch (e) {
13303
13489
  if (DEBUG5) console.error("Failed to read update cache:", e);
@@ -13306,7 +13492,7 @@ function readCache() {
13306
13492
  }
13307
13493
  function writeCache(data) {
13308
13494
  try {
13309
- if (!existsSync28(CACHE_DIR)) mkdirSync9(CACHE_DIR, { recursive: true });
13495
+ if (!existsSync29(CACHE_DIR)) mkdirSync9(CACHE_DIR, { recursive: true });
13310
13496
  writeFileSync13(CACHE_FILE, JSON.stringify(data), "utf-8");
13311
13497
  } catch (e) {
13312
13498
  if (DEBUG5) console.error("Failed to write update cache:", e);