@getcoherent/cli 0.6.9 → 0.6.11
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-
|
|
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((
|
|
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
|
|
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((
|
|
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
|
|
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((
|
|
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
|
-
|
|
1946
|
+
resolve17(true);
|
|
1946
1947
|
} catch (e) {
|
|
1947
1948
|
if (process.env.COHERENT_DEBUG === "1") console.error("Failed to install packages:", e);
|
|
1948
|
-
|
|
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);
|
|
@@ -3763,8 +3765,8 @@ async function createAppRouteGroupLayout(projectPath) {
|
|
|
3763
3765
|
// src/commands/chat.ts
|
|
3764
3766
|
import chalk14 from "chalk";
|
|
3765
3767
|
import ora2 from "ora";
|
|
3766
|
-
import { resolve as
|
|
3767
|
-
import { existsSync as
|
|
3768
|
+
import { resolve as resolve10, relative as relative2, join as join11 } from "path";
|
|
3769
|
+
import { existsSync as existsSync17, readFileSync as readFileSync12, mkdirSync as mkdirSync6, readdirSync as readdirSync4 } from "fs";
|
|
3768
3770
|
import {
|
|
3769
3771
|
DesignSystemManager as DesignSystemManager7,
|
|
3770
3772
|
ComponentManager as ComponentManager5,
|
|
@@ -4919,6 +4921,7 @@ function needsGlobalsFix(projectRoot) {
|
|
|
4919
4921
|
if (isTailwindV4(projectRoot)) {
|
|
4920
4922
|
if (!content.includes("@theme inline")) return true;
|
|
4921
4923
|
if (content.includes("@tailwind base")) return true;
|
|
4924
|
+
if (!content.includes("--color-transparent")) return true;
|
|
4922
4925
|
return false;
|
|
4923
4926
|
}
|
|
4924
4927
|
if (content.includes(":root {") || content.includes(".dark {")) return true;
|
|
@@ -6084,14 +6087,6 @@ ${selectImport}`
|
|
|
6084
6087
|
if (fixed !== beforeTabsFix) {
|
|
6085
6088
|
fixes.push("stripped border from TabsTrigger (shadcn handles active state)");
|
|
6086
6089
|
}
|
|
6087
|
-
const beforeTabsListFix = fixed;
|
|
6088
|
-
fixed = fixed.replace(
|
|
6089
|
-
/<TabsList\b(?![^>]*variant=)/g,
|
|
6090
|
-
'<TabsList variant="line"'
|
|
6091
|
-
);
|
|
6092
|
-
if (fixed !== beforeTabsListFix) {
|
|
6093
|
-
fixes.push('added variant="line" to TabsList (clean underline style)');
|
|
6094
|
-
}
|
|
6095
6090
|
fixed = fixed.replace(/className="([^"]*)"/g, (_match, inner) => {
|
|
6096
6091
|
const cleaned = inner.replace(/\s{2,}/g, " ").trim();
|
|
6097
6092
|
return `className="${cleaned}"`;
|
|
@@ -6811,6 +6806,8 @@ function applyDefaults(request) {
|
|
|
6811
6806
|
}
|
|
6812
6807
|
|
|
6813
6808
|
// src/commands/chat/split-generator.ts
|
|
6809
|
+
import { existsSync as existsSync14, readFileSync as readFileSync9, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
|
|
6810
|
+
import { resolve as resolve6 } from "path";
|
|
6814
6811
|
import { z } from "zod";
|
|
6815
6812
|
import {
|
|
6816
6813
|
loadManifest as loadManifest5,
|
|
@@ -7042,9 +7039,55 @@ ${groupLines.join("\n")}`];
|
|
|
7042
7039
|
if (compLines.length > 0) {
|
|
7043
7040
|
parts.push(`Shared Components:
|
|
7044
7041
|
${compLines.join("\n")}`);
|
|
7042
|
+
}
|
|
7043
|
+
const noteEntries = Object.entries(plan.pageNotes || {}).filter(
|
|
7044
|
+
([, note]) => note.sections && note.sections.length > 0
|
|
7045
|
+
);
|
|
7046
|
+
if (noteEntries.length > 0) {
|
|
7047
|
+
const noteLines = noteEntries.map(([key, note]) => ` ${key}: ${note.sections.join(", ")}`);
|
|
7048
|
+
parts.push(`Page Sections:
|
|
7049
|
+
${noteLines.join("\n")}`);
|
|
7045
7050
|
}
|
|
7046
7051
|
return parts.join("\n");
|
|
7047
7052
|
}
|
|
7053
|
+
function readExistingAppPageForReference(projectRoot, plan) {
|
|
7054
|
+
if (!projectRoot) return null;
|
|
7055
|
+
if (plan?.pageNotes) {
|
|
7056
|
+
for (const [key, note] of Object.entries(plan.pageNotes)) {
|
|
7057
|
+
if (note.type !== "app") continue;
|
|
7058
|
+
for (const group of ["(app)", "(admin)", "(dashboard)"]) {
|
|
7059
|
+
const filePath = resolve6(projectRoot, "app", group, key, "page.tsx");
|
|
7060
|
+
if (existsSync14(filePath)) {
|
|
7061
|
+
const code = readFileSync9(filePath, "utf-8");
|
|
7062
|
+
const lines = code.split("\n");
|
|
7063
|
+
return lines.slice(0, 200).join("\n");
|
|
7064
|
+
}
|
|
7065
|
+
}
|
|
7066
|
+
}
|
|
7067
|
+
}
|
|
7068
|
+
const appDir = resolve6(projectRoot, "app");
|
|
7069
|
+
if (!existsSync14(appDir)) return null;
|
|
7070
|
+
try {
|
|
7071
|
+
const entries = readdirSync2(appDir);
|
|
7072
|
+
for (const entry of entries) {
|
|
7073
|
+
if (!entry.startsWith("(") || entry === "(auth)") continue;
|
|
7074
|
+
const groupDir = resolve6(appDir, entry);
|
|
7075
|
+
if (!statSync2(groupDir).isDirectory()) continue;
|
|
7076
|
+
const subDirs = readdirSync2(groupDir);
|
|
7077
|
+
for (const sub of subDirs) {
|
|
7078
|
+
const pagePath = resolve6(groupDir, sub, "page.tsx");
|
|
7079
|
+
if (existsSync14(pagePath)) {
|
|
7080
|
+
const code = readFileSync9(pagePath, "utf-8");
|
|
7081
|
+
const lines = code.split("\n");
|
|
7082
|
+
return lines.slice(0, 200).join("\n");
|
|
7083
|
+
}
|
|
7084
|
+
}
|
|
7085
|
+
}
|
|
7086
|
+
} catch {
|
|
7087
|
+
return null;
|
|
7088
|
+
}
|
|
7089
|
+
return null;
|
|
7090
|
+
}
|
|
7048
7091
|
async function splitGeneratePages(spinner, message, modCtx, provider, parseOpts) {
|
|
7049
7092
|
let pageNames = [];
|
|
7050
7093
|
spinner.start("Phase 1/6 \u2014 Planning pages...");
|
|
@@ -7199,7 +7242,7 @@ async function splitGeneratePages(spinner, message, modCtx, provider, parseOpts)
|
|
|
7199
7242
|
if (plan && plan.sharedComponents.length > 0) {
|
|
7200
7243
|
spinner.start(`Phase 4.5/6 \u2014 Generating ${plan.sharedComponents.length} shared components from plan...`);
|
|
7201
7244
|
try {
|
|
7202
|
-
const { generateSharedComponentsFromPlan } = await import("./plan-generator-
|
|
7245
|
+
const { generateSharedComponentsFromPlan } = await import("./plan-generator-QUESV7GS.js");
|
|
7203
7246
|
const generated = await generateSharedComponentsFromPlan(
|
|
7204
7247
|
plan,
|
|
7205
7248
|
styleContext,
|
|
@@ -7246,6 +7289,13 @@ async function splitGeneratePages(spinner, message, modCtx, provider, parseOpts)
|
|
|
7246
7289
|
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="#".`;
|
|
7247
7290
|
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.';
|
|
7248
7291
|
const planSummaryNote = plan ? formatPlanSummary(plan) : "";
|
|
7292
|
+
const existingAppPageCode = readExistingAppPageForReference(parseOpts?.projectRoot ?? null, plan);
|
|
7293
|
+
const existingAppPageNote = existingAppPageCode ? `
|
|
7294
|
+
EXISTING APP PAGE (match these UI patterns for consistency):
|
|
7295
|
+
\`\`\`
|
|
7296
|
+
${existingAppPageCode}
|
|
7297
|
+
\`\`\`
|
|
7298
|
+
` : "";
|
|
7249
7299
|
const existingPagesContext = buildExistingPagesContext(modCtx.config);
|
|
7250
7300
|
const AI_CONCURRENCY = 3;
|
|
7251
7301
|
let phase5Done = 0;
|
|
@@ -7268,6 +7318,7 @@ async function splitGeneratePages(spinner, message, modCtx, provider, parseOpts)
|
|
|
7268
7318
|
alignmentNote,
|
|
7269
7319
|
authNote,
|
|
7270
7320
|
planSummaryNote,
|
|
7321
|
+
pageType !== "auth" ? existingAppPageNote : void 0,
|
|
7271
7322
|
existingPagesContext,
|
|
7272
7323
|
styleContext
|
|
7273
7324
|
].filter(Boolean).join("\n\n");
|
|
@@ -7428,7 +7479,7 @@ function extractAppNameFromPrompt(prompt) {
|
|
|
7428
7479
|
}
|
|
7429
7480
|
|
|
7430
7481
|
// src/commands/chat/modification-handler.ts
|
|
7431
|
-
import { resolve as
|
|
7482
|
+
import { resolve as resolve8 } from "path";
|
|
7432
7483
|
import { mkdir as mkdir4 } from "fs/promises";
|
|
7433
7484
|
import { dirname as dirname6 } from "path";
|
|
7434
7485
|
import chalk12 from "chalk";
|
|
@@ -7442,8 +7493,8 @@ import {
|
|
|
7442
7493
|
} from "@getcoherent/core";
|
|
7443
7494
|
|
|
7444
7495
|
// src/commands/chat/code-generator.ts
|
|
7445
|
-
import { resolve as
|
|
7446
|
-
import { existsSync as
|
|
7496
|
+
import { resolve as resolve7 } from "path";
|
|
7497
|
+
import { existsSync as existsSync15, readdirSync as readdirSync3, readFileSync as readFileSync10 } from "fs";
|
|
7447
7498
|
import { mkdir as mkdir3 } from "fs/promises";
|
|
7448
7499
|
import { dirname as dirname5 } from "path";
|
|
7449
7500
|
import {
|
|
@@ -7508,8 +7559,8 @@ async function ensureComponentsInstalled(componentIds, cm, dsm, pm, projectRoot)
|
|
|
7508
7559
|
for (const componentId of ids) {
|
|
7509
7560
|
const isRegistered = !!cm.read(componentId);
|
|
7510
7561
|
const fileName = toKebabCase(componentId) + ".tsx";
|
|
7511
|
-
const filePath =
|
|
7512
|
-
const fileExists =
|
|
7562
|
+
const filePath = resolve7(projectRoot, "components", "ui", fileName);
|
|
7563
|
+
const fileExists = existsSync15(filePath);
|
|
7513
7564
|
if (isRegistered && fileExists) continue;
|
|
7514
7565
|
const result = await provider.installComponent(componentId, projectRoot);
|
|
7515
7566
|
if (result.success && result.componentDef) {
|
|
@@ -7533,7 +7584,7 @@ async function regenerateComponent(componentId, config2, projectRoot) {
|
|
|
7533
7584
|
const generator = new ComponentGenerator2(config2);
|
|
7534
7585
|
const code = await generator.generate(component);
|
|
7535
7586
|
const fileName = toKebabCase(component.name) + ".tsx";
|
|
7536
|
-
const filePath =
|
|
7587
|
+
const filePath = resolve7(projectRoot, "components", "ui", fileName);
|
|
7537
7588
|
await writeFile(filePath, code);
|
|
7538
7589
|
}
|
|
7539
7590
|
async function regeneratePage(pageId, config2, projectRoot) {
|
|
@@ -7550,8 +7601,8 @@ async function regeneratePage(pageId, config2, projectRoot) {
|
|
|
7550
7601
|
await writeFile(filePath, code);
|
|
7551
7602
|
}
|
|
7552
7603
|
async function canOverwriteShared(projectRoot, componentFile, storedHashes) {
|
|
7553
|
-
const filePath =
|
|
7554
|
-
if (!
|
|
7604
|
+
const filePath = resolve7(projectRoot, componentFile);
|
|
7605
|
+
if (!existsSync15(filePath)) return true;
|
|
7555
7606
|
const storedHash = storedHashes[componentFile];
|
|
7556
7607
|
if (!storedHash) return true;
|
|
7557
7608
|
const edited = await isManuallyEdited(filePath, storedHash);
|
|
@@ -7568,7 +7619,7 @@ async function regenerateLayout(config2, projectRoot, options = { navChanged: fa
|
|
|
7568
7619
|
if (!initialized) {
|
|
7569
7620
|
const layout = config2.pages[0]?.layout || "centered";
|
|
7570
7621
|
const code = await generator.generateLayout(layout, appType, { skipNav: true });
|
|
7571
|
-
await writeFile(
|
|
7622
|
+
await writeFile(resolve7(projectRoot, "app", "layout.tsx"), code);
|
|
7572
7623
|
}
|
|
7573
7624
|
if (config2.navigation?.enabled && appType === "multi-page") {
|
|
7574
7625
|
const navType = config2.navigation.type || "header";
|
|
@@ -7624,17 +7675,17 @@ async function regenerateLayout(config2, projectRoot, options = { navChanged: fa
|
|
|
7624
7675
|
}
|
|
7625
7676
|
}
|
|
7626
7677
|
async function scanAndInstallSharedDeps(projectRoot) {
|
|
7627
|
-
const sharedDir =
|
|
7628
|
-
if (!
|
|
7629
|
-
const files =
|
|
7678
|
+
const sharedDir = resolve7(projectRoot, "components", "shared");
|
|
7679
|
+
if (!existsSync15(sharedDir)) return [];
|
|
7680
|
+
const files = readdirSync3(sharedDir).filter((f) => f.endsWith(".tsx") || f.endsWith(".ts"));
|
|
7630
7681
|
const installed = [];
|
|
7631
7682
|
const provider = getComponentProvider();
|
|
7632
7683
|
for (const file of files) {
|
|
7633
|
-
const code =
|
|
7684
|
+
const code = readFileSync10(resolve7(sharedDir, file), "utf-8");
|
|
7634
7685
|
const importMatches = [...code.matchAll(/@\/components\/ui\/([a-z0-9-]+)/g)];
|
|
7635
7686
|
for (const [, componentId] of importMatches) {
|
|
7636
|
-
const uiPath =
|
|
7637
|
-
if (!
|
|
7687
|
+
const uiPath = resolve7(projectRoot, "components", "ui", `${componentId}.tsx`);
|
|
7688
|
+
if (!existsSync15(uiPath) && provider.has(componentId)) {
|
|
7638
7689
|
try {
|
|
7639
7690
|
await provider.installComponent(componentId, projectRoot);
|
|
7640
7691
|
installed.push(componentId);
|
|
@@ -7646,10 +7697,10 @@ async function scanAndInstallSharedDeps(projectRoot) {
|
|
|
7646
7697
|
return [...new Set(installed)];
|
|
7647
7698
|
}
|
|
7648
7699
|
async function ensureAppRouteGroupLayout(projectRoot, navType, forceUpdate = false) {
|
|
7649
|
-
const layoutPath =
|
|
7650
|
-
if (
|
|
7700
|
+
const layoutPath = resolve7(projectRoot, "app", "(app)", "layout.tsx");
|
|
7701
|
+
if (existsSync15(layoutPath) && !forceUpdate) return;
|
|
7651
7702
|
const { mkdir: mkdirAsync } = await import("fs/promises");
|
|
7652
|
-
await mkdirAsync(
|
|
7703
|
+
await mkdirAsync(resolve7(projectRoot, "app", "(app)"), { recursive: true });
|
|
7653
7704
|
const code = buildAppLayoutCode(navType);
|
|
7654
7705
|
await writeFile(layoutPath, code);
|
|
7655
7706
|
}
|
|
@@ -7737,9 +7788,9 @@ export default function GroupLayout({
|
|
|
7737
7788
|
async function ensurePlanGroupLayouts(projectRoot, plan) {
|
|
7738
7789
|
const { mkdir: mkdirAsync } = await import("fs/promises");
|
|
7739
7790
|
for (const group of plan.groups) {
|
|
7740
|
-
const groupDir =
|
|
7791
|
+
const groupDir = resolve7(projectRoot, "app", `(${group.id})`);
|
|
7741
7792
|
await mkdirAsync(groupDir, { recursive: true });
|
|
7742
|
-
const layoutPath =
|
|
7793
|
+
const layoutPath = resolve7(groupDir, "layout.tsx");
|
|
7743
7794
|
const code = buildGroupLayoutCode(group.layout, group.pages);
|
|
7744
7795
|
await writeFile(layoutPath, code);
|
|
7745
7796
|
}
|
|
@@ -7766,11 +7817,11 @@ async function regenerateFiles(modified, config2, projectRoot, options = { navCh
|
|
|
7766
7817
|
}
|
|
7767
7818
|
if (componentIds.size > 0) {
|
|
7768
7819
|
const twGen = new TailwindConfigGenerator(config2);
|
|
7769
|
-
const twPath =
|
|
7770
|
-
const twCjsPath =
|
|
7771
|
-
if (
|
|
7820
|
+
const twPath = resolve7(projectRoot, "tailwind.config.ts");
|
|
7821
|
+
const twCjsPath = resolve7(projectRoot, "tailwind.config.cjs");
|
|
7822
|
+
if (existsSync15(twPath)) {
|
|
7772
7823
|
await writeFile(twPath, await twGen.generate());
|
|
7773
|
-
} else if (
|
|
7824
|
+
} else if (existsSync15(twCjsPath)) {
|
|
7774
7825
|
await writeFile(twCjsPath, await twGen.generateCjs());
|
|
7775
7826
|
}
|
|
7776
7827
|
}
|
|
@@ -8142,7 +8193,7 @@ async function applyModification(request, dsm, cm, pm, projectRoot, aiProvider,
|
|
|
8142
8193
|
modified: []
|
|
8143
8194
|
};
|
|
8144
8195
|
}
|
|
8145
|
-
const fullPath =
|
|
8196
|
+
const fullPath = resolve8(projectRoot, resolved.file);
|
|
8146
8197
|
let currentCode;
|
|
8147
8198
|
try {
|
|
8148
8199
|
currentCode = await readFile(fullPath);
|
|
@@ -8216,7 +8267,7 @@ async function applyModification(request, dsm, cm, pm, projectRoot, aiProvider,
|
|
|
8216
8267
|
} catch {
|
|
8217
8268
|
return { success: false, message: `Could not read ${pageFilePath}`, modified: [] };
|
|
8218
8269
|
}
|
|
8219
|
-
const sharedPath =
|
|
8270
|
+
const sharedPath = resolve8(projectRoot, resolved.file);
|
|
8220
8271
|
let sharedCode;
|
|
8221
8272
|
try {
|
|
8222
8273
|
sharedCode = await readFile(sharedPath);
|
|
@@ -8295,7 +8346,7 @@ async function applyModification(request, dsm, cm, pm, projectRoot, aiProvider,
|
|
|
8295
8346
|
}
|
|
8296
8347
|
let sourceCode;
|
|
8297
8348
|
try {
|
|
8298
|
-
sourceCode = await readFile(
|
|
8349
|
+
sourceCode = await readFile(resolve8(projectRoot, sourcePath));
|
|
8299
8350
|
} catch {
|
|
8300
8351
|
return { success: false, message: `Could not read ${sourcePath}`, modified: [] };
|
|
8301
8352
|
}
|
|
@@ -8315,7 +8366,7 @@ async function applyModification(request, dsm, cm, pm, projectRoot, aiProvider,
|
|
|
8315
8366
|
description: `Extracted from ${sourcePageName}: ${blockHint}`,
|
|
8316
8367
|
usedIn: []
|
|
8317
8368
|
});
|
|
8318
|
-
const sharedPath =
|
|
8369
|
+
const sharedPath = resolve8(projectRoot, created.file);
|
|
8319
8370
|
let sharedCode;
|
|
8320
8371
|
try {
|
|
8321
8372
|
sharedCode = await readFile(sharedPath);
|
|
@@ -8326,7 +8377,7 @@ async function applyModification(request, dsm, cm, pm, projectRoot, aiProvider,
|
|
|
8326
8377
|
for (const pageName of allPagesToLink) {
|
|
8327
8378
|
const relPath = routeToPath(pageName);
|
|
8328
8379
|
if (!relPath) continue;
|
|
8329
|
-
const fullPath =
|
|
8380
|
+
const fullPath = resolve8(projectRoot, relPath);
|
|
8330
8381
|
let linkPageCode;
|
|
8331
8382
|
try {
|
|
8332
8383
|
linkPageCode = await readFile(fullPath);
|
|
@@ -8660,7 +8711,10 @@ Rules:
|
|
|
8660
8711
|
if (ai.editPageCode) {
|
|
8661
8712
|
console.log(chalk12.dim(" \u270F\uFE0F Applying changes to existing page..."));
|
|
8662
8713
|
const coreRules = CORE_CONSTRAINTS;
|
|
8663
|
-
const
|
|
8714
|
+
const pageRoute = pageDef.route || `/${pageDef.id}`;
|
|
8715
|
+
const pageType = inferPageTypeFromRoute(pageRoute);
|
|
8716
|
+
const qualityRules = `${DESIGN_QUALITY_COMMON}
|
|
8717
|
+
${getDesignQualityForType(pageType)}`;
|
|
8664
8718
|
const contextualRules = selectContextualRules(instruction);
|
|
8665
8719
|
const existingRoutes = dsm.getConfig().pages.map((p) => p.route).join(", ");
|
|
8666
8720
|
const routeRules = `
|
|
@@ -8950,8 +9004,8 @@ function hasNavChanged(before, after) {
|
|
|
8950
9004
|
|
|
8951
9005
|
// src/commands/chat/interactive.ts
|
|
8952
9006
|
import chalk13 from "chalk";
|
|
8953
|
-
import { resolve as
|
|
8954
|
-
import { existsSync as
|
|
9007
|
+
import { resolve as resolve9 } from "path";
|
|
9008
|
+
import { existsSync as existsSync16, readFileSync as readFileSync11, writeFileSync as writeFileSync8, mkdirSync as mkdirSync5 } from "fs";
|
|
8955
9009
|
import { DesignSystemManager as DesignSystemManager6, ComponentManager as ComponentManager4, loadManifest as loadManifest7 } from "@getcoherent/core";
|
|
8956
9010
|
var DEBUG3 = process.env.COHERENT_DEBUG === "1";
|
|
8957
9011
|
async function interactiveChat(options, chatCommandFn) {
|
|
@@ -8971,13 +9025,13 @@ async function interactiveChat(options, chatCommandFn) {
|
|
|
8971
9025
|
\u274C Invalid provider: ${options.provider}`));
|
|
8972
9026
|
process.exit(1);
|
|
8973
9027
|
}
|
|
8974
|
-
const historyDir =
|
|
8975
|
-
const historyFile =
|
|
9028
|
+
const historyDir = resolve9(homedir2(), ".coherent");
|
|
9029
|
+
const historyFile = resolve9(historyDir, "history");
|
|
8976
9030
|
let history = [];
|
|
8977
9031
|
try {
|
|
8978
9032
|
mkdirSync5(historyDir, { recursive: true });
|
|
8979
|
-
if (
|
|
8980
|
-
history =
|
|
9033
|
+
if (existsSync16(historyFile)) {
|
|
9034
|
+
history = readFileSync11(historyFile, "utf-8").split("\n").filter(Boolean).slice(-200);
|
|
8981
9035
|
}
|
|
8982
9036
|
} catch (e) {
|
|
8983
9037
|
if (DEBUG3) console.error("Failed to load REPL history:", e);
|
|
@@ -9148,7 +9202,7 @@ async function chatCommand(message, options) {
|
|
|
9148
9202
|
const projectRoot = project.root;
|
|
9149
9203
|
const configPath = project.configPath;
|
|
9150
9204
|
const migrationGuard = join11(projectRoot, ".coherent", "migration-in-progress");
|
|
9151
|
-
if (
|
|
9205
|
+
if (existsSync17(migrationGuard)) {
|
|
9152
9206
|
spinner.fail("Migration in progress");
|
|
9153
9207
|
console.error(chalk14.red("\n\u274C A migration is in progress. Run `coherent migrate --rollback` to undo first."));
|
|
9154
9208
|
bail("Migration in progress");
|
|
@@ -9208,7 +9262,7 @@ async function chatCommand(message, options) {
|
|
|
9208
9262
|
}
|
|
9209
9263
|
if (/switch to light mode|default to light|make.*light.*(default|theme)|light theme/i.test(message)) {
|
|
9210
9264
|
spinner.start("Setting default theme to light...");
|
|
9211
|
-
const layoutPath =
|
|
9265
|
+
const layoutPath = resolve10(projectRoot, "app/layout.tsx");
|
|
9212
9266
|
try {
|
|
9213
9267
|
let layout = await readFile(layoutPath);
|
|
9214
9268
|
layout = layout.replace(/className="dark"/, "");
|
|
@@ -9247,8 +9301,8 @@ async function chatCommand(message, options) {
|
|
|
9247
9301
|
spinner.start("Parsing your request...");
|
|
9248
9302
|
let manifest = await loadManifest8(project.root);
|
|
9249
9303
|
const validShared = manifest.shared.filter((s) => {
|
|
9250
|
-
const fp =
|
|
9251
|
-
return
|
|
9304
|
+
const fp = resolve10(project.root, s.file);
|
|
9305
|
+
return existsSync17(fp);
|
|
9252
9306
|
});
|
|
9253
9307
|
if (validShared.length !== manifest.shared.length) {
|
|
9254
9308
|
const cleaned = manifest.shared.length - validShared.length;
|
|
@@ -9452,9 +9506,9 @@ async function chatCommand(message, options) {
|
|
|
9452
9506
|
if (manifest.shared.length > 0) {
|
|
9453
9507
|
for (const entry of manifest.shared) {
|
|
9454
9508
|
try {
|
|
9455
|
-
const sharedPath =
|
|
9456
|
-
if (
|
|
9457
|
-
const sharedCode =
|
|
9509
|
+
const sharedPath = resolve10(projectRoot, entry.file);
|
|
9510
|
+
if (existsSync17(sharedPath)) {
|
|
9511
|
+
const sharedCode = readFileSync12(sharedPath, "utf-8");
|
|
9458
9512
|
const sharedImports = sharedCode.matchAll(/@\/components\/ui\/([a-z0-9-]+)/g);
|
|
9459
9513
|
for (const m of sharedImports) {
|
|
9460
9514
|
if (m[1]) allNeededComponentIds.add(m[1]);
|
|
@@ -9475,7 +9529,7 @@ async function chatCommand(message, options) {
|
|
|
9475
9529
|
for (const componentId of allNeededComponentIds) {
|
|
9476
9530
|
const isRegistered = !!cm.read(componentId);
|
|
9477
9531
|
const filePath = join11(projectRoot, "components", "ui", `${componentId}.tsx`);
|
|
9478
|
-
const fileExists =
|
|
9532
|
+
const fileExists = existsSync17(filePath);
|
|
9479
9533
|
if (DEBUG4) console.log(chalk14.gray(` Checking ${componentId}: registered=${isRegistered} file=${fileExists}`));
|
|
9480
9534
|
if (!isRegistered || !fileExists) {
|
|
9481
9535
|
missingComponents.push(componentId);
|
|
@@ -9601,9 +9655,9 @@ async function chatCommand(message, options) {
|
|
|
9601
9655
|
const route = page.route || `/${page.id || "page"}`;
|
|
9602
9656
|
const pageFilePath = routeToFsPath(projectRoot, route, false);
|
|
9603
9657
|
let pageCode = "";
|
|
9604
|
-
if (
|
|
9658
|
+
if (existsSync17(pageFilePath)) {
|
|
9605
9659
|
try {
|
|
9606
|
-
pageCode =
|
|
9660
|
+
pageCode = readFileSync12(pageFilePath, "utf-8");
|
|
9607
9661
|
} catch {
|
|
9608
9662
|
}
|
|
9609
9663
|
}
|
|
@@ -9623,8 +9677,8 @@ async function chatCommand(message, options) {
|
|
|
9623
9677
|
}
|
|
9624
9678
|
const missingRoutes = [...allLinkedRoutes].filter((route) => {
|
|
9625
9679
|
if (expandedExisting.has(route)) return false;
|
|
9626
|
-
if (
|
|
9627
|
-
if (
|
|
9680
|
+
if (existsSync17(routeToFsPath(projectRoot, route, false))) return false;
|
|
9681
|
+
if (existsSync17(routeToFsPath(projectRoot, route, true))) return false;
|
|
9628
9682
|
return true;
|
|
9629
9683
|
});
|
|
9630
9684
|
const SCAFFOLD_AI_LIMIT = 10;
|
|
@@ -9688,8 +9742,8 @@ async function chatCommand(message, options) {
|
|
|
9688
9742
|
const isAuth = isAuthRoute(linkedRoute);
|
|
9689
9743
|
const filePath = routeToFsPath(projectRoot, linkedRoute, isAuth);
|
|
9690
9744
|
if (isAuth) await ensureAuthRouteGroup(projectRoot);
|
|
9691
|
-
const dir =
|
|
9692
|
-
if (!
|
|
9745
|
+
const dir = resolve10(filePath, "..");
|
|
9746
|
+
if (!existsSync17(dir)) {
|
|
9693
9747
|
mkdirSync6(dir, { recursive: true });
|
|
9694
9748
|
}
|
|
9695
9749
|
const placeholderCode = `export default function ${pageName.replace(/\s/g, "")}Page() {
|
|
@@ -9722,7 +9776,7 @@ async function chatCommand(message, options) {
|
|
|
9722
9776
|
for (const mod of result.modified) {
|
|
9723
9777
|
if (mod.startsWith("app/") && mod.endsWith("/page.tsx")) {
|
|
9724
9778
|
try {
|
|
9725
|
-
const code =
|
|
9779
|
+
const code = readFileSync12(resolve10(projectRoot, mod), "utf-8");
|
|
9726
9780
|
const issues = validatePageQuality(code, allRoutes).filter(
|
|
9727
9781
|
(i) => i.type === "BROKEN_INTERNAL_LINK"
|
|
9728
9782
|
);
|
|
@@ -9752,7 +9806,7 @@ async function chatCommand(message, options) {
|
|
|
9752
9806
|
dsm.updateConfig(latestConfig);
|
|
9753
9807
|
if (DEBUG4) console.log(chalk14.dim(` [theme] Set defaultMode to "${targetMode}"`));
|
|
9754
9808
|
}
|
|
9755
|
-
const layoutPath =
|
|
9809
|
+
const layoutPath = resolve10(projectRoot, "app", "layout.tsx");
|
|
9756
9810
|
try {
|
|
9757
9811
|
let layoutCode = await readFile(layoutPath);
|
|
9758
9812
|
if (targetMode === "dark" && !layoutCode.includes('className="dark"')) {
|
|
@@ -9802,16 +9856,16 @@ async function chatCommand(message, options) {
|
|
|
9802
9856
|
}
|
|
9803
9857
|
try {
|
|
9804
9858
|
const updatedHashes = { ...storedHashes };
|
|
9805
|
-
const sharedDir =
|
|
9806
|
-
const layoutFile =
|
|
9859
|
+
const sharedDir = resolve10(projectRoot, "components", "shared");
|
|
9860
|
+
const layoutFile = resolve10(projectRoot, "app", "layout.tsx");
|
|
9807
9861
|
const filesToHash = [layoutFile];
|
|
9808
|
-
if (
|
|
9809
|
-
for (const f of
|
|
9810
|
-
if (f.endsWith(".tsx")) filesToHash.push(
|
|
9862
|
+
if (existsSync17(sharedDir)) {
|
|
9863
|
+
for (const f of readdirSync4(sharedDir)) {
|
|
9864
|
+
if (f.endsWith(".tsx")) filesToHash.push(resolve10(sharedDir, f));
|
|
9811
9865
|
}
|
|
9812
9866
|
}
|
|
9813
9867
|
for (const filePath of filesToHash) {
|
|
9814
|
-
if (
|
|
9868
|
+
if (existsSync17(filePath)) {
|
|
9815
9869
|
const rel = relative2(projectRoot, filePath);
|
|
9816
9870
|
updatedHashes[rel] = await computeFileHash(filePath);
|
|
9817
9871
|
}
|
|
@@ -9843,7 +9897,7 @@ async function chatCommand(message, options) {
|
|
|
9843
9897
|
console.log("");
|
|
9844
9898
|
}
|
|
9845
9899
|
if (uxRecommendations) {
|
|
9846
|
-
const recPath =
|
|
9900
|
+
const recPath = resolve10(projectRoot, "recommendations.md");
|
|
9847
9901
|
const section = `
|
|
9848
9902
|
|
|
9849
9903
|
---
|
|
@@ -9853,7 +9907,7 @@ async function chatCommand(message, options) {
|
|
|
9853
9907
|
${uxRecommendations}
|
|
9854
9908
|
`;
|
|
9855
9909
|
try {
|
|
9856
|
-
if (!
|
|
9910
|
+
if (!existsSync17(recPath)) {
|
|
9857
9911
|
await writeFile(
|
|
9858
9912
|
recPath,
|
|
9859
9913
|
"# UX/UI Recommendations\n\nRecommendations are added here when you use `coherent chat` and the AI suggests improvements.\n"
|
|
@@ -9927,18 +9981,18 @@ ${uxRecommendations}
|
|
|
9927
9981
|
import chalk15 from "chalk";
|
|
9928
9982
|
import ora3 from "ora";
|
|
9929
9983
|
import { spawn } from "child_process";
|
|
9930
|
-
import { existsSync as
|
|
9931
|
-
import { resolve as
|
|
9984
|
+
import { existsSync as existsSync20, rmSync as rmSync3, readFileSync as readFileSync15, writeFileSync as writeFileSync10, readdirSync as readdirSync6 } from "fs";
|
|
9985
|
+
import { resolve as resolve11, join as join14 } from "path";
|
|
9932
9986
|
import { readdir as readdir2 } from "fs/promises";
|
|
9933
9987
|
import { DesignSystemManager as DesignSystemManager8, ComponentGenerator as ComponentGenerator3 } from "@getcoherent/core";
|
|
9934
9988
|
|
|
9935
9989
|
// src/utils/file-watcher.ts
|
|
9936
|
-
import { readFileSync as
|
|
9990
|
+
import { readFileSync as readFileSync14, writeFileSync as writeFileSync9, existsSync as existsSync19 } from "fs";
|
|
9937
9991
|
import { relative as relative4, join as join13 } from "path";
|
|
9938
9992
|
import { loadManifest as loadManifest9, saveManifest as saveManifest3 } from "@getcoherent/core";
|
|
9939
9993
|
|
|
9940
9994
|
// src/utils/component-integrity.ts
|
|
9941
|
-
import { existsSync as
|
|
9995
|
+
import { existsSync as existsSync18, readFileSync as readFileSync13, readdirSync as readdirSync5 } from "fs";
|
|
9942
9996
|
import { join as join12, relative as relative3 } from "path";
|
|
9943
9997
|
function extractExportedComponentNames(code) {
|
|
9944
9998
|
const names = [];
|
|
@@ -9966,13 +10020,13 @@ function arraysEqual(a, b) {
|
|
|
9966
10020
|
function findPagesImporting(projectRoot, componentName, componentFile) {
|
|
9967
10021
|
const results = [];
|
|
9968
10022
|
const appDir = join12(projectRoot, "app");
|
|
9969
|
-
if (!
|
|
10023
|
+
if (!existsSync18(appDir)) return results;
|
|
9970
10024
|
const pageFiles = collectFiles(appDir, (name) => name === "page.tsx" || name === "page.jsx");
|
|
9971
10025
|
const componentImportPath = componentFile.replace(/\.tsx$/, "").replace(/\.jsx$/, "");
|
|
9972
10026
|
for (const absPath of pageFiles) {
|
|
9973
10027
|
if (absPath.includes("design-system")) continue;
|
|
9974
10028
|
try {
|
|
9975
|
-
const code =
|
|
10029
|
+
const code = readFileSync13(absPath, "utf-8");
|
|
9976
10030
|
const hasNamedImport = new RegExp(`import\\s+\\{[^}]*\\b${componentName}\\b[^}]*\\}\\s+from\\s+['"]`).test(code);
|
|
9977
10031
|
const hasDefaultImport = new RegExp(`import\\s+${componentName}\\s+from\\s+['"]`).test(code);
|
|
9978
10032
|
const hasPathImport = code.includes(`@/${componentImportPath}`);
|
|
@@ -9986,9 +10040,9 @@ function findPagesImporting(projectRoot, componentName, componentFile) {
|
|
|
9986
10040
|
}
|
|
9987
10041
|
function isUsedInLayout(projectRoot, componentName) {
|
|
9988
10042
|
const layoutPath = join12(projectRoot, "app", "layout.tsx");
|
|
9989
|
-
if (!
|
|
10043
|
+
if (!existsSync18(layoutPath)) return false;
|
|
9990
10044
|
try {
|
|
9991
|
-
const code =
|
|
10045
|
+
const code = readFileSync13(layoutPath, "utf-8");
|
|
9992
10046
|
return code.includes(componentName);
|
|
9993
10047
|
} catch {
|
|
9994
10048
|
return false;
|
|
@@ -9997,7 +10051,7 @@ function isUsedInLayout(projectRoot, componentName) {
|
|
|
9997
10051
|
function findUnregisteredComponents(projectRoot, manifest) {
|
|
9998
10052
|
const results = [];
|
|
9999
10053
|
const componentsDir = join12(projectRoot, "components");
|
|
10000
|
-
if (!
|
|
10054
|
+
if (!existsSync18(componentsDir)) return results;
|
|
10001
10055
|
const registeredFiles = new Set(manifest.shared.map((s) => s.file));
|
|
10002
10056
|
const registeredNames = new Set(manifest.shared.map((s) => s.name));
|
|
10003
10057
|
const files = collectFiles(
|
|
@@ -10009,7 +10063,7 @@ function findUnregisteredComponents(projectRoot, manifest) {
|
|
|
10009
10063
|
const relFile = relative3(projectRoot, absPath);
|
|
10010
10064
|
if (registeredFiles.has(relFile)) continue;
|
|
10011
10065
|
try {
|
|
10012
|
-
const code =
|
|
10066
|
+
const code = readFileSync13(absPath, "utf-8");
|
|
10013
10067
|
const exports = extractExportedComponentNames(code);
|
|
10014
10068
|
for (const name of exports) {
|
|
10015
10069
|
if (registeredNames.has(name)) continue;
|
|
@@ -10025,13 +10079,13 @@ function findUnregisteredComponents(projectRoot, manifest) {
|
|
|
10025
10079
|
function findInlineDuplicates(projectRoot, manifest) {
|
|
10026
10080
|
const results = [];
|
|
10027
10081
|
const appDir = join12(projectRoot, "app");
|
|
10028
|
-
if (!
|
|
10082
|
+
if (!existsSync18(appDir)) return results;
|
|
10029
10083
|
const pageFiles = collectFiles(appDir, (name) => name === "page.tsx" || name === "page.jsx");
|
|
10030
10084
|
for (const absPath of pageFiles) {
|
|
10031
10085
|
if (absPath.includes("design-system")) continue;
|
|
10032
10086
|
let code;
|
|
10033
10087
|
try {
|
|
10034
|
-
code =
|
|
10088
|
+
code = readFileSync13(absPath, "utf-8");
|
|
10035
10089
|
} catch {
|
|
10036
10090
|
continue;
|
|
10037
10091
|
}
|
|
@@ -10055,7 +10109,7 @@ function findInlineDuplicates(projectRoot, manifest) {
|
|
|
10055
10109
|
}
|
|
10056
10110
|
function findComponentFileByExportName(projectRoot, componentName) {
|
|
10057
10111
|
const componentsDir = join12(projectRoot, "components");
|
|
10058
|
-
if (!
|
|
10112
|
+
if (!existsSync18(componentsDir)) return null;
|
|
10059
10113
|
const files = collectFiles(
|
|
10060
10114
|
componentsDir,
|
|
10061
10115
|
(name) => (name.endsWith(".tsx") || name.endsWith(".jsx")) && !name.startsWith("."),
|
|
@@ -10063,7 +10117,7 @@ function findComponentFileByExportName(projectRoot, componentName) {
|
|
|
10063
10117
|
);
|
|
10064
10118
|
for (const absPath of files) {
|
|
10065
10119
|
try {
|
|
10066
|
-
const code =
|
|
10120
|
+
const code = readFileSync13(absPath, "utf-8");
|
|
10067
10121
|
const exports = extractExportedComponentNames(code);
|
|
10068
10122
|
if (exports.includes(componentName)) {
|
|
10069
10123
|
return relative3(projectRoot, absPath);
|
|
@@ -10077,7 +10131,7 @@ function removeOrphanedEntries(projectRoot, manifest) {
|
|
|
10077
10131
|
const removed = [];
|
|
10078
10132
|
const valid = manifest.shared.filter((entry) => {
|
|
10079
10133
|
const filePath = join12(projectRoot, entry.file);
|
|
10080
|
-
if (
|
|
10134
|
+
if (existsSync18(filePath)) return true;
|
|
10081
10135
|
removed.push({ id: entry.id, name: entry.name });
|
|
10082
10136
|
return false;
|
|
10083
10137
|
});
|
|
@@ -10096,7 +10150,7 @@ function reconcileComponents(projectRoot, manifest) {
|
|
|
10096
10150
|
const m = { ...manifest, shared: [...manifest.shared], nextId: manifest.nextId };
|
|
10097
10151
|
m.shared = m.shared.filter((entry) => {
|
|
10098
10152
|
const filePath = join12(projectRoot, entry.file);
|
|
10099
|
-
if (!
|
|
10153
|
+
if (!existsSync18(filePath)) {
|
|
10100
10154
|
const newPath = findComponentFileByExportName(projectRoot, entry.name);
|
|
10101
10155
|
if (newPath) {
|
|
10102
10156
|
result.updated.push({ id: entry.id, field: "file", from: entry.file, to: newPath });
|
|
@@ -10108,7 +10162,7 @@ function reconcileComponents(projectRoot, manifest) {
|
|
|
10108
10162
|
}
|
|
10109
10163
|
let code;
|
|
10110
10164
|
try {
|
|
10111
|
-
code =
|
|
10165
|
+
code = readFileSync13(join12(projectRoot, entry.file), "utf-8");
|
|
10112
10166
|
} catch {
|
|
10113
10167
|
return true;
|
|
10114
10168
|
}
|
|
@@ -10185,7 +10239,7 @@ function collectFiles(dir, filter, skipDirs = []) {
|
|
|
10185
10239
|
function walk(d) {
|
|
10186
10240
|
let entries;
|
|
10187
10241
|
try {
|
|
10188
|
-
entries =
|
|
10242
|
+
entries = readdirSync5(d, { withFileTypes: true });
|
|
10189
10243
|
} catch {
|
|
10190
10244
|
return;
|
|
10191
10245
|
}
|
|
@@ -10230,8 +10284,8 @@ function findInlineDuplicatesOfShared(content, manifest) {
|
|
|
10230
10284
|
function getWatcherConfig(projectRoot) {
|
|
10231
10285
|
try {
|
|
10232
10286
|
const pkgPath = join13(projectRoot, "package.json");
|
|
10233
|
-
if (!
|
|
10234
|
-
const pkg = JSON.parse(
|
|
10287
|
+
if (!existsSync19(pkgPath)) return defaultWatcherConfig();
|
|
10288
|
+
const pkg = JSON.parse(readFileSync14(pkgPath, "utf-8"));
|
|
10235
10289
|
const c = pkg?.coherent?.watcher ?? {};
|
|
10236
10290
|
return {
|
|
10237
10291
|
enabled: c.enabled !== false,
|
|
@@ -10259,7 +10313,7 @@ async function handleFileChange(projectRoot, filePath) {
|
|
|
10259
10313
|
if (relativePath.includes("node_modules") || relativePath.includes(".next")) return;
|
|
10260
10314
|
let content;
|
|
10261
10315
|
try {
|
|
10262
|
-
content =
|
|
10316
|
+
content = readFileSync14(filePath, "utf-8");
|
|
10263
10317
|
} catch {
|
|
10264
10318
|
return;
|
|
10265
10319
|
}
|
|
@@ -10332,7 +10386,7 @@ async function detectNewComponent(projectRoot, filePath) {
|
|
|
10332
10386
|
const manifest = await loadManifest9(projectRoot);
|
|
10333
10387
|
const alreadyRegistered = manifest.shared.some((s) => s.file === relativePath);
|
|
10334
10388
|
if (alreadyRegistered) return;
|
|
10335
|
-
const code =
|
|
10389
|
+
const code = readFileSync14(filePath, "utf-8");
|
|
10336
10390
|
const exports = extractExportedComponentNames(code);
|
|
10337
10391
|
if (exports.length > 0) {
|
|
10338
10392
|
const alreadyByName = exports.every((n) => manifest.shared.some((s) => s.name === n));
|
|
@@ -10372,7 +10426,7 @@ function startFileWatcher(projectRoot) {
|
|
|
10372
10426
|
watcher.on("unlink", (fp) => handleFileDelete(projectRoot, fp));
|
|
10373
10427
|
});
|
|
10374
10428
|
const manifestPath = join13(projectRoot, "coherent.components.json");
|
|
10375
|
-
if (
|
|
10429
|
+
if (existsSync19(manifestPath)) {
|
|
10376
10430
|
import("chokidar").then((chokidar) => {
|
|
10377
10431
|
manifestWatcher = chokidar.default.watch(manifestPath, { ignoreInitial: true });
|
|
10378
10432
|
manifestWatcher.on("change", () => handleManifestChange(projectRoot));
|
|
@@ -10386,7 +10440,7 @@ function startFileWatcher(projectRoot) {
|
|
|
10386
10440
|
|
|
10387
10441
|
// src/commands/preview.ts
|
|
10388
10442
|
function getPackageManager(projectRoot) {
|
|
10389
|
-
const hasPnpm =
|
|
10443
|
+
const hasPnpm = existsSync20(resolve11(projectRoot, "pnpm-lock.yaml"));
|
|
10390
10444
|
return hasPnpm ? "pnpm" : "npm";
|
|
10391
10445
|
}
|
|
10392
10446
|
function runInstall(projectRoot) {
|
|
@@ -10408,23 +10462,23 @@ function runInstall(projectRoot) {
|
|
|
10408
10462
|
});
|
|
10409
10463
|
}
|
|
10410
10464
|
function checkProjectInitialized(projectRoot) {
|
|
10411
|
-
const configPath =
|
|
10412
|
-
const packageJsonPath =
|
|
10413
|
-
if (!
|
|
10465
|
+
const configPath = resolve11(projectRoot, "design-system.config.ts");
|
|
10466
|
+
const packageJsonPath = resolve11(projectRoot, "package.json");
|
|
10467
|
+
if (!existsSync20(configPath)) {
|
|
10414
10468
|
return false;
|
|
10415
10469
|
}
|
|
10416
|
-
if (!
|
|
10470
|
+
if (!existsSync20(packageJsonPath)) {
|
|
10417
10471
|
return false;
|
|
10418
10472
|
}
|
|
10419
10473
|
return true;
|
|
10420
10474
|
}
|
|
10421
10475
|
function checkDependenciesInstalled(projectRoot) {
|
|
10422
|
-
const nodeModulesPath =
|
|
10423
|
-
return
|
|
10476
|
+
const nodeModulesPath = resolve11(projectRoot, "node_modules");
|
|
10477
|
+
return existsSync20(nodeModulesPath);
|
|
10424
10478
|
}
|
|
10425
10479
|
function clearStaleCache(projectRoot) {
|
|
10426
10480
|
const nextDir = join14(projectRoot, ".next");
|
|
10427
|
-
if (
|
|
10481
|
+
if (existsSync20(nextDir)) {
|
|
10428
10482
|
rmSync3(nextDir, { recursive: true, force: true });
|
|
10429
10483
|
console.log(chalk15.dim(" \u2714 Cleared stale build cache"));
|
|
10430
10484
|
}
|
|
@@ -10440,7 +10494,7 @@ async function preflightDependencyCheck(projectRoot) {
|
|
|
10440
10494
|
}
|
|
10441
10495
|
async function listPageFiles(appDir) {
|
|
10442
10496
|
const out = [];
|
|
10443
|
-
if (!
|
|
10497
|
+
if (!existsSync20(appDir)) return out;
|
|
10444
10498
|
async function walk(dir) {
|
|
10445
10499
|
const entries = await readdir2(dir, { withFileTypes: true });
|
|
10446
10500
|
for (const e of entries) {
|
|
@@ -10456,7 +10510,7 @@ async function validateSyntax(projectRoot) {
|
|
|
10456
10510
|
const appDir = join14(projectRoot, "app");
|
|
10457
10511
|
const pages = await listPageFiles(appDir);
|
|
10458
10512
|
for (const file of pages) {
|
|
10459
|
-
const content =
|
|
10513
|
+
const content = readFileSync15(file, "utf-8");
|
|
10460
10514
|
const fixed = fixUnescapedLtInJsx(sanitizeMetadataStrings(ensureUseClientIfNeeded(content)));
|
|
10461
10515
|
if (fixed !== content) {
|
|
10462
10516
|
writeFileSync10(file, fixed, "utf-8");
|
|
@@ -10467,16 +10521,16 @@ async function validateSyntax(projectRoot) {
|
|
|
10467
10521
|
async function fixMissingComponentExports(projectRoot) {
|
|
10468
10522
|
const appDir = join14(projectRoot, "app");
|
|
10469
10523
|
const uiDir = join14(projectRoot, "components", "ui");
|
|
10470
|
-
if (!
|
|
10524
|
+
if (!existsSync20(appDir) || !existsSync20(uiDir)) return;
|
|
10471
10525
|
const pages = await listPageFiles(appDir);
|
|
10472
10526
|
const sharedDir = join14(projectRoot, "components", "shared");
|
|
10473
|
-
if (
|
|
10474
|
-
const sharedFiles =
|
|
10527
|
+
if (existsSync20(sharedDir)) {
|
|
10528
|
+
const sharedFiles = readdirSync6(sharedDir).filter((f) => f.endsWith(".tsx") || f.endsWith(".ts")).map((f) => join14(sharedDir, f));
|
|
10475
10529
|
pages.push(...sharedFiles);
|
|
10476
10530
|
}
|
|
10477
10531
|
const neededExports = /* @__PURE__ */ new Map();
|
|
10478
10532
|
for (const file of pages) {
|
|
10479
|
-
const content =
|
|
10533
|
+
const content = readFileSync15(file, "utf-8");
|
|
10480
10534
|
const importRe = /import\s*\{([^}]+)\}\s*from\s*['"]@\/components\/ui\/([^'"]+)['"]/g;
|
|
10481
10535
|
let m;
|
|
10482
10536
|
while ((m = importRe.exec(content)) !== null) {
|
|
@@ -10497,7 +10551,7 @@ async function fixMissingComponentExports(projectRoot) {
|
|
|
10497
10551
|
const provider = getComponentProvider();
|
|
10498
10552
|
for (const [componentId, needed] of neededExports) {
|
|
10499
10553
|
const componentFile = join14(uiDir, `${componentId}.tsx`);
|
|
10500
|
-
if (!
|
|
10554
|
+
if (!existsSync20(componentFile)) {
|
|
10501
10555
|
if (provider.has(componentId)) {
|
|
10502
10556
|
try {
|
|
10503
10557
|
const result = await provider.installComponent(componentId, projectRoot);
|
|
@@ -10520,7 +10574,7 @@ async function fixMissingComponentExports(projectRoot) {
|
|
|
10520
10574
|
}
|
|
10521
10575
|
continue;
|
|
10522
10576
|
}
|
|
10523
|
-
const content =
|
|
10577
|
+
const content = readFileSync15(componentFile, "utf-8");
|
|
10524
10578
|
const exportRe = /export\s+(?:const|function|class)\s+(\w+)|export\s*\{([^}]+)\}/g;
|
|
10525
10579
|
const existingExports = /* @__PURE__ */ new Set();
|
|
10526
10580
|
let em;
|
|
@@ -10555,7 +10609,7 @@ async function fixMissingComponentExports(projectRoot) {
|
|
|
10555
10609
|
}
|
|
10556
10610
|
async function backfillPageAnalysis(projectRoot) {
|
|
10557
10611
|
const configPath = join14(projectRoot, "design-system.config.ts");
|
|
10558
|
-
if (!
|
|
10612
|
+
if (!existsSync20(configPath)) return;
|
|
10559
10613
|
try {
|
|
10560
10614
|
const mgr = new DesignSystemManager8(configPath);
|
|
10561
10615
|
const config2 = mgr.getConfig();
|
|
@@ -10572,8 +10626,8 @@ async function backfillPageAnalysis(projectRoot) {
|
|
|
10572
10626
|
} else {
|
|
10573
10627
|
filePath = join14(projectRoot, "app", route.slice(1), "page.tsx");
|
|
10574
10628
|
}
|
|
10575
|
-
if (!
|
|
10576
|
-
const code =
|
|
10629
|
+
if (!existsSync20(filePath)) continue;
|
|
10630
|
+
const code = readFileSync15(filePath, "utf-8");
|
|
10577
10631
|
if (code.length < 50) continue;
|
|
10578
10632
|
page.pageAnalysis = analyzePageCode(code);
|
|
10579
10633
|
changed = true;
|
|
@@ -10723,12 +10777,12 @@ async function openBrowser(url) {
|
|
|
10723
10777
|
}
|
|
10724
10778
|
}
|
|
10725
10779
|
function startDevServer(projectRoot) {
|
|
10726
|
-
const packageJsonPath =
|
|
10727
|
-
if (!
|
|
10780
|
+
const packageJsonPath = resolve11(projectRoot, "package.json");
|
|
10781
|
+
if (!existsSync20(packageJsonPath)) {
|
|
10728
10782
|
throw new Error('package.json not found. Run "coherent init" first.');
|
|
10729
10783
|
}
|
|
10730
|
-
const hasPnpm =
|
|
10731
|
-
const hasNpm =
|
|
10784
|
+
const hasPnpm = existsSync20(resolve11(projectRoot, "pnpm-lock.yaml"));
|
|
10785
|
+
const hasNpm = existsSync20(resolve11(projectRoot, "package-lock.json"));
|
|
10732
10786
|
const command = hasPnpm ? "pnpm" : hasNpm ? "npm" : "npx";
|
|
10733
10787
|
const args = hasPnpm ? ["dev", "--turbo"] : hasNpm ? ["run", "dev", "--", "--turbo"] : ["next", "dev", "--turbo"];
|
|
10734
10788
|
const child = spawn(command, args, {
|
|
@@ -10775,7 +10829,7 @@ async function previewCommand() {
|
|
|
10775
10829
|
if (needsGlobalsFix(projectRoot)) {
|
|
10776
10830
|
spinner.text = "Fixing globals.css...";
|
|
10777
10831
|
try {
|
|
10778
|
-
const dsm = new DesignSystemManager8(
|
|
10832
|
+
const dsm = new DesignSystemManager8(resolve11(projectRoot, "design-system.config.ts"));
|
|
10779
10833
|
await dsm.load();
|
|
10780
10834
|
const config2 = dsm.getConfig();
|
|
10781
10835
|
fixGlobalsCss(projectRoot, config2);
|
|
@@ -10814,8 +10868,8 @@ async function previewCommand() {
|
|
|
10814
10868
|
import chalk16 from "chalk";
|
|
10815
10869
|
import ora4 from "ora";
|
|
10816
10870
|
import { spawn as spawn2 } from "child_process";
|
|
10817
|
-
import { existsSync as
|
|
10818
|
-
import { resolve as
|
|
10871
|
+
import { existsSync as existsSync21, rmSync as rmSync4, readdirSync as readdirSync7 } from "fs";
|
|
10872
|
+
import { resolve as resolve12, join as join15, dirname as dirname7 } from "path";
|
|
10819
10873
|
import { readdir as readdir3, readFile as readFile6, writeFile as writeFile5, mkdir as mkdir5, copyFile as copyFile2 } from "fs/promises";
|
|
10820
10874
|
var COPY_EXCLUDE = /* @__PURE__ */ new Set([
|
|
10821
10875
|
"node_modules",
|
|
@@ -10849,17 +10903,17 @@ async function copyDir(src, dest) {
|
|
|
10849
10903
|
}
|
|
10850
10904
|
}
|
|
10851
10905
|
function checkProjectInitialized2(projectRoot) {
|
|
10852
|
-
return
|
|
10906
|
+
return existsSync21(resolve12(projectRoot, "design-system.config.ts")) && existsSync21(resolve12(projectRoot, "package.json"));
|
|
10853
10907
|
}
|
|
10854
10908
|
function getPackageManager2(projectRoot) {
|
|
10855
|
-
if (
|
|
10856
|
-
if (
|
|
10909
|
+
if (existsSync21(resolve12(projectRoot, "pnpm-lock.yaml"))) return "pnpm";
|
|
10910
|
+
if (existsSync21(resolve12(projectRoot, "package-lock.json"))) return "npm";
|
|
10857
10911
|
return "npx";
|
|
10858
10912
|
}
|
|
10859
10913
|
async function patchNextConfigForExport(outRoot) {
|
|
10860
10914
|
for (const name of ["next.config.ts", "next.config.mjs", "next.config.js"]) {
|
|
10861
10915
|
const p = join15(outRoot, name);
|
|
10862
|
-
if (!
|
|
10916
|
+
if (!existsSync21(p)) continue;
|
|
10863
10917
|
let content = await readFile6(p, "utf-8");
|
|
10864
10918
|
if (content.includes("ignoreDuringBuilds")) return;
|
|
10865
10919
|
content = content.replace(
|
|
@@ -10874,9 +10928,9 @@ async function buildProduction(projectRoot) {
|
|
|
10874
10928
|
const pm = getPackageManager2(projectRoot);
|
|
10875
10929
|
const command = pm === "pnpm" ? "pnpm" : pm === "npm" ? "npm" : "npx";
|
|
10876
10930
|
const args = pm === "npx" ? ["next", "build"] : ["run", "build"];
|
|
10877
|
-
return new Promise((
|
|
10931
|
+
return new Promise((resolve17, reject) => {
|
|
10878
10932
|
const child = spawn2(command, args, { cwd: projectRoot, stdio: "inherit", shell: true });
|
|
10879
|
-
child.on("exit", (code) => code === 0 ?
|
|
10933
|
+
child.on("exit", (code) => code === 0 ? resolve17() : reject(new Error(`Build failed with exit code ${code}`)));
|
|
10880
10934
|
child.on("error", (error) => reject(new Error(`Failed to start build: ${error.message}`)));
|
|
10881
10935
|
});
|
|
10882
10936
|
}
|
|
@@ -10901,7 +10955,7 @@ EXPOSE 3000
|
|
|
10901
10955
|
`;
|
|
10902
10956
|
async function ensureReadmeDeploySection(outRoot) {
|
|
10903
10957
|
const readmePath = join15(outRoot, "README.md");
|
|
10904
|
-
if (!
|
|
10958
|
+
if (!existsSync21(readmePath)) return;
|
|
10905
10959
|
try {
|
|
10906
10960
|
let content = await readFile6(readmePath, "utf-8");
|
|
10907
10961
|
if (/##\s+Deploy\b/m.test(content)) return;
|
|
@@ -10926,16 +10980,16 @@ async function countPages(outRoot) {
|
|
|
10926
10980
|
}
|
|
10927
10981
|
}
|
|
10928
10982
|
const appDir = join15(outRoot, "app");
|
|
10929
|
-
if (
|
|
10983
|
+
if (existsSync21(appDir)) await walk(appDir);
|
|
10930
10984
|
return n;
|
|
10931
10985
|
}
|
|
10932
10986
|
function countComponents(outRoot) {
|
|
10933
10987
|
let n = 0;
|
|
10934
10988
|
for (const sub of ["ui", "shared"]) {
|
|
10935
10989
|
const dir = join15(outRoot, "components", sub);
|
|
10936
|
-
if (!
|
|
10990
|
+
if (!existsSync21(dir)) continue;
|
|
10937
10991
|
try {
|
|
10938
|
-
n +=
|
|
10992
|
+
n += readdirSync7(dir).filter((f) => f.endsWith(".tsx") || f.endsWith(".jsx")).length;
|
|
10939
10993
|
} catch {
|
|
10940
10994
|
}
|
|
10941
10995
|
}
|
|
@@ -10944,7 +10998,7 @@ function countComponents(outRoot) {
|
|
|
10944
10998
|
var IMPORT_FROM_REGEX2 = /from\s+['"]([^'"]+)['"]/g;
|
|
10945
10999
|
async function collectImportedPackages2(dir, extensions) {
|
|
10946
11000
|
const packages = /* @__PURE__ */ new Set();
|
|
10947
|
-
if (!
|
|
11001
|
+
if (!existsSync21(dir)) return packages;
|
|
10948
11002
|
async function walk(d) {
|
|
10949
11003
|
const entries = await readdir3(d, { withFileTypes: true });
|
|
10950
11004
|
for (const e of entries) {
|
|
@@ -10972,7 +11026,7 @@ async function collectImportedPackages2(dir, extensions) {
|
|
|
10972
11026
|
}
|
|
10973
11027
|
async function findMissingDepsInExport(outRoot) {
|
|
10974
11028
|
const pkgPath = join15(outRoot, "package.json");
|
|
10975
|
-
if (!
|
|
11029
|
+
if (!existsSync21(pkgPath)) return [];
|
|
10976
11030
|
let pkg;
|
|
10977
11031
|
try {
|
|
10978
11032
|
pkg = JSON.parse(await readFile6(pkgPath, "utf-8"));
|
|
@@ -10993,25 +11047,25 @@ async function stripCoherentArtifacts(outputDir) {
|
|
|
10993
11047
|
const removed = [];
|
|
10994
11048
|
for (const p of ["app/design-system", "app/api/design-system"]) {
|
|
10995
11049
|
const full = join15(outputDir, p);
|
|
10996
|
-
if (
|
|
11050
|
+
if (existsSync21(full)) {
|
|
10997
11051
|
rmSync4(full, { recursive: true, force: true });
|
|
10998
11052
|
removed.push(p);
|
|
10999
11053
|
}
|
|
11000
11054
|
}
|
|
11001
11055
|
const appNavPath = join15(outputDir, "app", "AppNav.tsx");
|
|
11002
|
-
if (
|
|
11056
|
+
if (existsSync21(appNavPath)) {
|
|
11003
11057
|
rmSync4(appNavPath, { force: true });
|
|
11004
11058
|
removed.push("app/AppNav.tsx");
|
|
11005
11059
|
}
|
|
11006
11060
|
const layoutPath = join15(outputDir, "app", "layout.tsx");
|
|
11007
|
-
if (
|
|
11061
|
+
if (existsSync21(layoutPath)) {
|
|
11008
11062
|
let layout = await readFile6(layoutPath, "utf-8");
|
|
11009
11063
|
layout = layout.replace(/import\s*\{?\s*AppNav\s*\}?\s*from\s*['"][^'"]+['"]\s*\n?/g, "");
|
|
11010
11064
|
layout = layout.replace(/\s*<AppNav\s*\/?\s*>\s*/g, "\n");
|
|
11011
11065
|
await writeFile5(layoutPath, layout, "utf-8");
|
|
11012
11066
|
}
|
|
11013
11067
|
const sharedHeaderPath = join15(outputDir, "components", "shared", "header.tsx");
|
|
11014
|
-
if (
|
|
11068
|
+
if (existsSync21(sharedHeaderPath)) {
|
|
11015
11069
|
let header = await readFile6(sharedHeaderPath, "utf-8");
|
|
11016
11070
|
header = header.replace(/<Link\s[^>]*href="\/design-system"[^>]*>[\s\S]*?<\/Link>/g, "");
|
|
11017
11071
|
header = header.replace(/\n\s*<>\s*\n/, "\n");
|
|
@@ -11019,7 +11073,7 @@ async function stripCoherentArtifacts(outputDir) {
|
|
|
11019
11073
|
await writeFile5(sharedHeaderPath, header, "utf-8");
|
|
11020
11074
|
}
|
|
11021
11075
|
const guardPath2 = join15(outputDir, "app", "ShowWhenNotAuthRoute.tsx");
|
|
11022
|
-
if (
|
|
11076
|
+
if (existsSync21(guardPath2)) {
|
|
11023
11077
|
let guard = await readFile6(guardPath2, "utf-8");
|
|
11024
11078
|
guard = guard.replace(/['"],?\s*'\/design-system['"],?\s*/g, "");
|
|
11025
11079
|
const pathsMatch = guard.match(/HIDDEN_PATHS\s*=\s*\[([^\]]*)\]/);
|
|
@@ -11027,7 +11081,7 @@ async function stripCoherentArtifacts(outputDir) {
|
|
|
11027
11081
|
if (remaining.length === 0) {
|
|
11028
11082
|
rmSync4(guardPath2, { force: true });
|
|
11029
11083
|
removed.push("app/ShowWhenNotAuthRoute.tsx");
|
|
11030
|
-
if (
|
|
11084
|
+
if (existsSync21(layoutPath)) {
|
|
11031
11085
|
let layout = await readFile6(layoutPath, "utf-8");
|
|
11032
11086
|
layout = layout.replace(/import\s+\w+\s+from\s*['"]\.\/ShowWhenNotAuthRoute['"]\s*\n?/g, "");
|
|
11033
11087
|
layout = layout.replace(/\s*<ShowWhenNotAuthRoute>\s*\n?/g, "\n");
|
|
@@ -11048,14 +11102,14 @@ async function stripCoherentArtifacts(outputDir) {
|
|
|
11048
11102
|
"recommendations.md"
|
|
11049
11103
|
]) {
|
|
11050
11104
|
const full = join15(outputDir, name);
|
|
11051
|
-
if (
|
|
11105
|
+
if (existsSync21(full)) {
|
|
11052
11106
|
rmSync4(full, { force: true });
|
|
11053
11107
|
removed.push(name);
|
|
11054
11108
|
}
|
|
11055
11109
|
}
|
|
11056
11110
|
for (const dir of [".claude", ".coherent"]) {
|
|
11057
11111
|
const full = join15(outputDir, dir);
|
|
11058
|
-
if (
|
|
11112
|
+
if (existsSync21(full)) {
|
|
11059
11113
|
rmSync4(full, { recursive: true, force: true });
|
|
11060
11114
|
removed.push(dir + "/");
|
|
11061
11115
|
}
|
|
@@ -11063,7 +11117,7 @@ async function stripCoherentArtifacts(outputDir) {
|
|
|
11063
11117
|
return removed;
|
|
11064
11118
|
}
|
|
11065
11119
|
async function exportCommand(options = {}) {
|
|
11066
|
-
const outputDir =
|
|
11120
|
+
const outputDir = resolve12(process.cwd(), options.output ?? "./export");
|
|
11067
11121
|
const doBuild = options.build !== false;
|
|
11068
11122
|
const keepDs = options.keepDs === true;
|
|
11069
11123
|
const spinner = ora4("Preparing export...").start();
|
|
@@ -11079,7 +11133,7 @@ async function exportCommand(options = {}) {
|
|
|
11079
11133
|
process.exit(1);
|
|
11080
11134
|
}
|
|
11081
11135
|
spinner.text = "Copying project...";
|
|
11082
|
-
if (
|
|
11136
|
+
if (existsSync21(outputDir)) rmSync4(outputDir, { recursive: true, force: true });
|
|
11083
11137
|
await copyDir(projectRoot, outputDir);
|
|
11084
11138
|
spinner.succeed("Project copied");
|
|
11085
11139
|
if (!keepDs) {
|
|
@@ -11254,8 +11308,8 @@ async function regenerateDocsCommand() {
|
|
|
11254
11308
|
|
|
11255
11309
|
// src/commands/fix.ts
|
|
11256
11310
|
import chalk19 from "chalk";
|
|
11257
|
-
import { readdirSync as
|
|
11258
|
-
import { resolve as
|
|
11311
|
+
import { readdirSync as readdirSync8, readFileSync as readFileSync16, existsSync as existsSync22, writeFileSync as writeFileSync11, rmSync as rmSync5, mkdirSync as mkdirSync7 } from "fs";
|
|
11312
|
+
import { resolve as resolve13, join as join16 } from "path";
|
|
11259
11313
|
import {
|
|
11260
11314
|
DesignSystemManager as DesignSystemManager11,
|
|
11261
11315
|
ComponentManager as ComponentManager6,
|
|
@@ -11279,7 +11333,7 @@ function extractComponentIdsFromCode2(code) {
|
|
|
11279
11333
|
function listTsxFiles(dir) {
|
|
11280
11334
|
const files = [];
|
|
11281
11335
|
try {
|
|
11282
|
-
const entries =
|
|
11336
|
+
const entries = readdirSync8(dir, { withFileTypes: true });
|
|
11283
11337
|
for (const e of entries) {
|
|
11284
11338
|
const full = join16(dir, e.name);
|
|
11285
11339
|
if (e.isDirectory() && e.name !== "node_modules" && !e.name.startsWith(".")) {
|
|
@@ -11311,7 +11365,7 @@ async function fixCommand(opts = {}) {
|
|
|
11311
11365
|
}
|
|
11312
11366
|
if (!skipCache) {
|
|
11313
11367
|
const nextDir = join16(projectRoot, ".next");
|
|
11314
|
-
if (
|
|
11368
|
+
if (existsSync22(nextDir)) {
|
|
11315
11369
|
if (!dryRun) rmSync5(nextDir, { recursive: true, force: true });
|
|
11316
11370
|
fixes.push("Cleared build cache");
|
|
11317
11371
|
console.log(chalk19.green(" \u2714 Cleared build cache"));
|
|
@@ -11333,12 +11387,12 @@ async function fixCommand(opts = {}) {
|
|
|
11333
11387
|
}
|
|
11334
11388
|
}
|
|
11335
11389
|
}
|
|
11336
|
-
const appDir =
|
|
11390
|
+
const appDir = resolve13(projectRoot, "app");
|
|
11337
11391
|
const allTsxFiles = listTsxFiles(appDir);
|
|
11338
|
-
const componentsTsxFiles = listTsxFiles(
|
|
11392
|
+
const componentsTsxFiles = listTsxFiles(resolve13(projectRoot, "components"));
|
|
11339
11393
|
const allComponentIds = /* @__PURE__ */ new Set();
|
|
11340
11394
|
for (const file of [...allTsxFiles, ...componentsTsxFiles]) {
|
|
11341
|
-
const content =
|
|
11395
|
+
const content = readFileSync16(file, "utf-8");
|
|
11342
11396
|
extractComponentIdsFromCode2(content).forEach((id) => allComponentIds.add(id));
|
|
11343
11397
|
}
|
|
11344
11398
|
let dsm = null;
|
|
@@ -11357,8 +11411,8 @@ async function fixCommand(opts = {}) {
|
|
|
11357
11411
|
missingComponents.push(id);
|
|
11358
11412
|
} else {
|
|
11359
11413
|
const fileName = toKebabCase(id) + ".tsx";
|
|
11360
|
-
const filePath =
|
|
11361
|
-
if (!
|
|
11414
|
+
const filePath = resolve13(projectRoot, "components", "ui", fileName);
|
|
11415
|
+
if (!existsSync22(filePath)) missingFiles.push(id);
|
|
11362
11416
|
}
|
|
11363
11417
|
}
|
|
11364
11418
|
const provider = getComponentProvider();
|
|
@@ -11387,8 +11441,8 @@ async function fixCommand(opts = {}) {
|
|
|
11387
11441
|
const generator = new ComponentGenerator4(updatedConfig);
|
|
11388
11442
|
const code = await generator.generate(component);
|
|
11389
11443
|
const fileName = toKebabCase(component.name) + ".tsx";
|
|
11390
|
-
const filePath =
|
|
11391
|
-
mkdirSync7(
|
|
11444
|
+
const filePath = resolve13(projectRoot, "components", "ui", fileName);
|
|
11445
|
+
mkdirSync7(resolve13(projectRoot, "components", "ui"), { recursive: true });
|
|
11392
11446
|
await writeFile(filePath, code);
|
|
11393
11447
|
}
|
|
11394
11448
|
}
|
|
@@ -11410,7 +11464,7 @@ async function fixCommand(opts = {}) {
|
|
|
11410
11464
|
const userTsxFiles = allTsxFiles.filter((f) => !f.includes("/design-system/"));
|
|
11411
11465
|
let syntaxFixed = 0;
|
|
11412
11466
|
for (const file of userTsxFiles) {
|
|
11413
|
-
const content =
|
|
11467
|
+
const content = readFileSync16(file, "utf-8");
|
|
11414
11468
|
const fixed = fixUnescapedLtInJsx(
|
|
11415
11469
|
fixEscapedClosingQuotes(sanitizeMetadataStrings(ensureUseClientIfNeeded(content)))
|
|
11416
11470
|
);
|
|
@@ -11428,7 +11482,7 @@ async function fixCommand(opts = {}) {
|
|
|
11428
11482
|
let qualityFixCount = 0;
|
|
11429
11483
|
const qualityFixDetails = [];
|
|
11430
11484
|
for (const file of userTsxFiles) {
|
|
11431
|
-
const content =
|
|
11485
|
+
const content = readFileSync16(file, "utf-8");
|
|
11432
11486
|
const { code: autoFixed, fixes: fileFixes } = await autoFixCode(content);
|
|
11433
11487
|
if (autoFixed !== content) {
|
|
11434
11488
|
if (!dryRun) writeFileSync11(file, autoFixed, "utf-8");
|
|
@@ -11447,7 +11501,7 @@ async function fixCommand(opts = {}) {
|
|
|
11447
11501
|
let totalWarnings = 0;
|
|
11448
11502
|
const fileIssues = [];
|
|
11449
11503
|
for (const file of allTsxFiles) {
|
|
11450
|
-
const code = dryRun ?
|
|
11504
|
+
const code = dryRun ? readFileSync16(file, "utf-8") : readFileSync16(file, "utf-8");
|
|
11451
11505
|
const relativePath = file.replace(projectRoot + "/", "");
|
|
11452
11506
|
const baseName = file.split("/").pop() || "";
|
|
11453
11507
|
const isAuthPage = relativePath.includes("(auth)");
|
|
@@ -11569,17 +11623,17 @@ async function fixCommand(opts = {}) {
|
|
|
11569
11623
|
|
|
11570
11624
|
// src/commands/check.ts
|
|
11571
11625
|
import chalk20 from "chalk";
|
|
11572
|
-
import { resolve as
|
|
11573
|
-
import { readdirSync as
|
|
11626
|
+
import { resolve as resolve14 } from "path";
|
|
11627
|
+
import { readdirSync as readdirSync9, readFileSync as readFileSync17, statSync as statSync3, existsSync as existsSync23 } from "fs";
|
|
11574
11628
|
import { loadManifest as loadManifest11 } from "@getcoherent/core";
|
|
11575
11629
|
var EXCLUDED_DIRS = /* @__PURE__ */ new Set(["node_modules", "design-system"]);
|
|
11576
11630
|
function findTsxFiles(dir) {
|
|
11577
11631
|
const results = [];
|
|
11578
11632
|
try {
|
|
11579
|
-
const entries =
|
|
11633
|
+
const entries = readdirSync9(dir);
|
|
11580
11634
|
for (const entry of entries) {
|
|
11581
|
-
const full =
|
|
11582
|
-
const stat =
|
|
11635
|
+
const full = resolve14(dir, entry);
|
|
11636
|
+
const stat = statSync3(full);
|
|
11583
11637
|
if (stat.isDirectory() && !entry.startsWith(".") && !EXCLUDED_DIRS.has(entry)) {
|
|
11584
11638
|
results.push(...findTsxFiles(full));
|
|
11585
11639
|
} else if (entry.endsWith(".tsx")) {
|
|
@@ -11613,7 +11667,7 @@ async function checkCommand(opts = {}) {
|
|
|
11613
11667
|
} catch {
|
|
11614
11668
|
}
|
|
11615
11669
|
if (!skipPages) {
|
|
11616
|
-
const appDir =
|
|
11670
|
+
const appDir = resolve14(projectRoot, "app");
|
|
11617
11671
|
const files = findTsxFiles(appDir);
|
|
11618
11672
|
result.pages.total = files.length;
|
|
11619
11673
|
if (!opts.json) console.log(chalk20.cyan("\n \u{1F4C4} Pages") + chalk20.dim(` (${files.length} scanned)
|
|
@@ -11627,7 +11681,7 @@ async function checkCommand(opts = {}) {
|
|
|
11627
11681
|
"NATIVE_TABLE"
|
|
11628
11682
|
]);
|
|
11629
11683
|
for (const file of files) {
|
|
11630
|
-
const code =
|
|
11684
|
+
const code = readFileSync17(file, "utf-8");
|
|
11631
11685
|
const relativePath = file.replace(projectRoot + "/", "");
|
|
11632
11686
|
const baseName = file.split("/").pop() || "";
|
|
11633
11687
|
const isAuthPage = relativePath.includes("(auth)");
|
|
@@ -11669,7 +11723,7 @@ async function checkCommand(opts = {}) {
|
|
|
11669
11723
|
routeSet.add("/");
|
|
11670
11724
|
routeSet.add("#");
|
|
11671
11725
|
for (const file of files) {
|
|
11672
|
-
const code =
|
|
11726
|
+
const code = readFileSync17(file, "utf-8");
|
|
11673
11727
|
const relativePath = file.replace(projectRoot + "/", "");
|
|
11674
11728
|
const lines = code.split("\n");
|
|
11675
11729
|
const linkHrefRe = /href\s*=\s*["'](\/[a-z0-9/-]*)["']/gi;
|
|
@@ -11701,8 +11755,8 @@ async function checkCommand(opts = {}) {
|
|
|
11701
11755
|
const manifest = await loadManifest11(project.root);
|
|
11702
11756
|
if (manifest.shared.length > 0) {
|
|
11703
11757
|
for (const entry of manifest.shared) {
|
|
11704
|
-
const fullPath =
|
|
11705
|
-
if (!
|
|
11758
|
+
const fullPath = resolve14(project.root, entry.file);
|
|
11759
|
+
if (!existsSync23(fullPath)) {
|
|
11706
11760
|
result.pages.withErrors++;
|
|
11707
11761
|
if (!opts.json) console.log(chalk20.red(`
|
|
11708
11762
|
\u2717 Missing shared component file: ${entry.id} (${entry.file})`));
|
|
@@ -11726,8 +11780,8 @@ async function checkCommand(opts = {}) {
|
|
|
11726
11780
|
let _staleUsedIn = 0;
|
|
11727
11781
|
let _nameMismatch = 0;
|
|
11728
11782
|
for (const entry of manifest.shared) {
|
|
11729
|
-
const filePath =
|
|
11730
|
-
const fileExists =
|
|
11783
|
+
const filePath = resolve14(projectRoot, entry.file);
|
|
11784
|
+
const fileExists = existsSync23(filePath);
|
|
11731
11785
|
if (!fileExists) {
|
|
11732
11786
|
_orphaned++;
|
|
11733
11787
|
if (!opts.json) {
|
|
@@ -11737,7 +11791,7 @@ async function checkCommand(opts = {}) {
|
|
|
11737
11791
|
continue;
|
|
11738
11792
|
}
|
|
11739
11793
|
try {
|
|
11740
|
-
const code =
|
|
11794
|
+
const code = readFileSync17(filePath, "utf-8");
|
|
11741
11795
|
const actualExports = extractExportedComponentNames(code);
|
|
11742
11796
|
if (actualExports.length > 0 && !actualExports.includes(entry.name)) {
|
|
11743
11797
|
_nameMismatch++;
|
|
@@ -11805,7 +11859,7 @@ async function checkCommand(opts = {}) {
|
|
|
11805
11859
|
id: e.id,
|
|
11806
11860
|
name: e.name,
|
|
11807
11861
|
type: e.type,
|
|
11808
|
-
status:
|
|
11862
|
+
status: existsSync23(resolve14(projectRoot, e.file)) ? "ok" : "unused",
|
|
11809
11863
|
message: "",
|
|
11810
11864
|
suggestions: void 0
|
|
11811
11865
|
}))
|
|
@@ -11900,8 +11954,8 @@ import {
|
|
|
11900
11954
|
generateSharedComponent as generateSharedComponent5,
|
|
11901
11955
|
integrateSharedLayoutIntoRootLayout as integrateSharedLayoutIntoRootLayout3
|
|
11902
11956
|
} from "@getcoherent/core";
|
|
11903
|
-
import { existsSync as
|
|
11904
|
-
import { resolve as
|
|
11957
|
+
import { existsSync as existsSync24 } from "fs";
|
|
11958
|
+
import { resolve as resolve15 } from "path";
|
|
11905
11959
|
|
|
11906
11960
|
// src/utils/ds-files.ts
|
|
11907
11961
|
import { mkdir as mkdir6, writeFile as writeFile6 } from "fs/promises";
|
|
@@ -12031,8 +12085,8 @@ function createComponentsCommand() {
|
|
|
12031
12085
|
const updated = await integrateSharedLayoutIntoRootLayout3(project.root);
|
|
12032
12086
|
if (updated) console.log(chalk26.cyan(" Updated app/layout.tsx to use shared layout components.\n"));
|
|
12033
12087
|
}
|
|
12034
|
-
const sharedPagePath =
|
|
12035
|
-
if (!
|
|
12088
|
+
const sharedPagePath = resolve15(project.root, "app/design-system/shared/page.tsx");
|
|
12089
|
+
if (!existsSync24(sharedPagePath)) {
|
|
12036
12090
|
try {
|
|
12037
12091
|
const dsm = new DesignSystemManager12(project.configPath);
|
|
12038
12092
|
await dsm.load();
|
|
@@ -12058,8 +12112,8 @@ function createComponentsCommand() {
|
|
|
12058
12112
|
import chalk27 from "chalk";
|
|
12059
12113
|
import ora6 from "ora";
|
|
12060
12114
|
import { writeFile as writeFile7, mkdir as mkdir7 } from "fs/promises";
|
|
12061
|
-
import { resolve as
|
|
12062
|
-
import { existsSync as
|
|
12115
|
+
import { resolve as resolve16, join as join18, dirname as dirname9 } from "path";
|
|
12116
|
+
import { existsSync as existsSync25 } from "fs";
|
|
12063
12117
|
import {
|
|
12064
12118
|
FigmaClient,
|
|
12065
12119
|
parseFigmaFileResponse,
|
|
@@ -12283,7 +12337,7 @@ async function importFigmaAction(urlOrKey, opts) {
|
|
|
12283
12337
|
if (dryRun) stats.filesWritten.push(FIGMA_COMPONENT_MAP_FILENAME);
|
|
12284
12338
|
else
|
|
12285
12339
|
await writeFile7(
|
|
12286
|
-
|
|
12340
|
+
resolve16(projectRoot, FIGMA_COMPONENT_MAP_FILENAME),
|
|
12287
12341
|
JSON.stringify(componentMapObj, null, 2),
|
|
12288
12342
|
"utf-8"
|
|
12289
12343
|
);
|
|
@@ -12306,9 +12360,9 @@ async function importFigmaAction(urlOrKey, opts) {
|
|
|
12306
12360
|
const fullConfig = buildFigmaImportConfig(mergedConfig, pageDefs, intermediate.fileName);
|
|
12307
12361
|
if (!dryRun) {
|
|
12308
12362
|
spinner.start("Updating design-system.config.ts...");
|
|
12309
|
-
const configPath =
|
|
12363
|
+
const configPath = resolve16(projectRoot, DESIGN_SYSTEM_CONFIG_PATH);
|
|
12310
12364
|
const dsm = new DesignSystemManager13(configPath);
|
|
12311
|
-
if (
|
|
12365
|
+
if (existsSync25(configPath)) {
|
|
12312
12366
|
await dsm.load();
|
|
12313
12367
|
const existing = dsm.getConfig();
|
|
12314
12368
|
dsm.updateConfig({
|
|
@@ -12338,7 +12392,7 @@ export const config = ${JSON.stringify(fullConfig, null, 2)} as const
|
|
|
12338
12392
|
spinner.succeed("design-system.config.ts updated");
|
|
12339
12393
|
spinner.start("Ensuring root layout...");
|
|
12340
12394
|
const layoutPath = join18(projectRoot, "app/layout.tsx");
|
|
12341
|
-
if (!
|
|
12395
|
+
if (!existsSync25(layoutPath)) {
|
|
12342
12396
|
await mkdir7(dirname9(layoutPath), { recursive: true });
|
|
12343
12397
|
await writeFile7(layoutPath, MINIMAL_ROOT_LAYOUT, "utf-8");
|
|
12344
12398
|
stats.filesWritten.push("app/layout.tsx");
|
|
@@ -12428,7 +12482,7 @@ async function dsRegenerateCommand() {
|
|
|
12428
12482
|
// src/commands/update.ts
|
|
12429
12483
|
import chalk29 from "chalk";
|
|
12430
12484
|
import ora8 from "ora";
|
|
12431
|
-
import { readFileSync as
|
|
12485
|
+
import { readFileSync as readFileSync18, existsSync as existsSync26 } from "fs";
|
|
12432
12486
|
import { join as join19 } from "path";
|
|
12433
12487
|
import { DesignSystemManager as DesignSystemManager15, CLI_VERSION as CLI_VERSION4 } from "@getcoherent/core";
|
|
12434
12488
|
|
|
@@ -12599,9 +12653,9 @@ var EXPECTED_CSS_VARS = [
|
|
|
12599
12653
|
];
|
|
12600
12654
|
function checkMissingCssVars(projectRoot) {
|
|
12601
12655
|
const globalsPath = join19(projectRoot, "app", "globals.css");
|
|
12602
|
-
if (!
|
|
12656
|
+
if (!existsSync26(globalsPath)) return [];
|
|
12603
12657
|
try {
|
|
12604
|
-
const content =
|
|
12658
|
+
const content = readFileSync18(globalsPath, "utf-8");
|
|
12605
12659
|
return EXPECTED_CSS_VARS.filter((v) => !content.includes(v));
|
|
12606
12660
|
} catch {
|
|
12607
12661
|
return [];
|
|
@@ -12609,9 +12663,9 @@ function checkMissingCssVars(projectRoot) {
|
|
|
12609
12663
|
}
|
|
12610
12664
|
function patchGlobalsCss(projectRoot, missingVars) {
|
|
12611
12665
|
const globalsPath = join19(projectRoot, "app", "globals.css");
|
|
12612
|
-
if (!
|
|
12666
|
+
if (!existsSync26(globalsPath) || missingVars.length === 0) return;
|
|
12613
12667
|
const { writeFileSync: writeFileSync14 } = __require("fs");
|
|
12614
|
-
let content =
|
|
12668
|
+
let content = readFileSync18(globalsPath, "utf-8");
|
|
12615
12669
|
const defaultValues = {
|
|
12616
12670
|
"--chart-1": "220 70% 50%",
|
|
12617
12671
|
"--chart-2": "160 60% 45%",
|
|
@@ -12689,7 +12743,7 @@ async function undoCommand(options) {
|
|
|
12689
12743
|
// src/commands/sync.ts
|
|
12690
12744
|
import chalk31 from "chalk";
|
|
12691
12745
|
import ora9 from "ora";
|
|
12692
|
-
import { existsSync as
|
|
12746
|
+
import { existsSync as existsSync27, readFileSync as readFileSync19 } from "fs";
|
|
12693
12747
|
import { join as join20, relative as relative5, dirname as dirname10 } from "path";
|
|
12694
12748
|
import { readdir as readdir4, readFile as readFile7 } from "fs/promises";
|
|
12695
12749
|
import { DesignSystemManager as DesignSystemManager16 } from "@getcoherent/core";
|
|
@@ -12698,8 +12752,8 @@ function extractTokensFromProject(projectRoot) {
|
|
|
12698
12752
|
const lightColors = {};
|
|
12699
12753
|
const darkColors = {};
|
|
12700
12754
|
const globalsPath = join20(projectRoot, "app", "globals.css");
|
|
12701
|
-
if (
|
|
12702
|
-
const css =
|
|
12755
|
+
if (existsSync27(globalsPath)) {
|
|
12756
|
+
const css = readFileSync19(globalsPath, "utf-8");
|
|
12703
12757
|
const rootMatch = css.match(/:root\s*\{([^}]+)\}/s);
|
|
12704
12758
|
if (rootMatch) parseVarsInto(rootMatch[1], lightColors);
|
|
12705
12759
|
const darkMatch = css.match(/\.dark\s*\{([^}]+)\}/s);
|
|
@@ -12707,8 +12761,8 @@ function extractTokensFromProject(projectRoot) {
|
|
|
12707
12761
|
}
|
|
12708
12762
|
const layoutPath = join20(projectRoot, "app", "layout.tsx");
|
|
12709
12763
|
let layoutCode = "";
|
|
12710
|
-
if (
|
|
12711
|
-
layoutCode =
|
|
12764
|
+
if (existsSync27(layoutPath)) {
|
|
12765
|
+
layoutCode = readFileSync19(layoutPath, "utf-8");
|
|
12712
12766
|
const rootInline = layoutCode.match(/:root\s*\{([^}]+)\}/s);
|
|
12713
12767
|
if (rootInline && Object.keys(lightColors).length === 0) {
|
|
12714
12768
|
parseVarsInto(rootInline[1], lightColors);
|
|
@@ -12726,7 +12780,7 @@ function extractTokensFromProject(projectRoot) {
|
|
|
12726
12780
|
defaultMode = "dark";
|
|
12727
12781
|
}
|
|
12728
12782
|
let radius;
|
|
12729
|
-
const allCss = [
|
|
12783
|
+
const allCss = [existsSync27(globalsPath) ? readFileSync19(globalsPath, "utf-8") : "", layoutCode].join("\n");
|
|
12730
12784
|
const radiusMatch = allCss.match(/--radius:\s*([^;]+);/);
|
|
12731
12785
|
if (radiusMatch) radius = radiusMatch[1].trim();
|
|
12732
12786
|
return {
|
|
@@ -12750,7 +12804,7 @@ function parseVarsInto(block, target) {
|
|
|
12750
12804
|
async function detectCustomComponents(projectRoot, allPageCode) {
|
|
12751
12805
|
const results = [];
|
|
12752
12806
|
const componentsDir = join20(projectRoot, "components");
|
|
12753
|
-
if (!
|
|
12807
|
+
if (!existsSync27(componentsDir)) return results;
|
|
12754
12808
|
const files = [];
|
|
12755
12809
|
await walkForTsx(componentsDir, files, ["ui"]);
|
|
12756
12810
|
const fileResults = await Promise.all(
|
|
@@ -12929,7 +12983,7 @@ async function syncCommand(options = {}) {
|
|
|
12929
12983
|
const spinner = ora9("Scanning project files...").start();
|
|
12930
12984
|
try {
|
|
12931
12985
|
const appDir = join20(project.root, "app");
|
|
12932
|
-
if (!
|
|
12986
|
+
if (!existsSync27(appDir)) {
|
|
12933
12987
|
spinner.fail("No app/ directory found");
|
|
12934
12988
|
process.exit(1);
|
|
12935
12989
|
}
|
|
@@ -13156,7 +13210,7 @@ async function syncCommand(options = {}) {
|
|
|
13156
13210
|
// src/commands/migrate.ts
|
|
13157
13211
|
import chalk32 from "chalk";
|
|
13158
13212
|
import ora10 from "ora";
|
|
13159
|
-
import { existsSync as
|
|
13213
|
+
import { existsSync as existsSync28, mkdirSync as mkdirSync8, cpSync, rmSync as rmSync6, writeFileSync as writeFileSync12, readFileSync as readFileSync20, readdirSync as readdirSync10 } from "fs";
|
|
13160
13214
|
import { join as join21 } from "path";
|
|
13161
13215
|
function backupDir(projectRoot) {
|
|
13162
13216
|
const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
@@ -13169,11 +13223,11 @@ function createBackup2(projectRoot) {
|
|
|
13169
13223
|
const uiDir = join21(projectRoot, "components", "ui");
|
|
13170
13224
|
const dest = backupDir(projectRoot);
|
|
13171
13225
|
mkdirSync8(dest, { recursive: true });
|
|
13172
|
-
if (
|
|
13226
|
+
if (existsSync28(uiDir)) {
|
|
13173
13227
|
cpSync(uiDir, join21(dest, "components-ui"), { recursive: true });
|
|
13174
13228
|
}
|
|
13175
13229
|
const configPath = join21(projectRoot, "design-system.config.ts");
|
|
13176
|
-
if (
|
|
13230
|
+
if (existsSync28(configPath)) {
|
|
13177
13231
|
cpSync(configPath, join21(dest, "design-system.config.ts"));
|
|
13178
13232
|
}
|
|
13179
13233
|
return dest;
|
|
@@ -13185,24 +13239,24 @@ function setGuard(projectRoot, backupPath) {
|
|
|
13185
13239
|
}
|
|
13186
13240
|
function clearGuard(projectRoot) {
|
|
13187
13241
|
const guard = guardPath(projectRoot);
|
|
13188
|
-
if (
|
|
13242
|
+
if (existsSync28(guard)) rmSync6(guard);
|
|
13189
13243
|
}
|
|
13190
13244
|
function rollback(projectRoot) {
|
|
13191
13245
|
const guard = guardPath(projectRoot);
|
|
13192
|
-
if (!
|
|
13246
|
+
if (!existsSync28(guard)) return false;
|
|
13193
13247
|
try {
|
|
13194
|
-
const data = JSON.parse(
|
|
13248
|
+
const data = JSON.parse(readFileSync20(guard, "utf-8"));
|
|
13195
13249
|
const backup = data.backup;
|
|
13196
|
-
if (!
|
|
13250
|
+
if (!existsSync28(backup)) return false;
|
|
13197
13251
|
const uiBackup = join21(backup, "components-ui");
|
|
13198
13252
|
const uiDir = join21(projectRoot, "components", "ui");
|
|
13199
|
-
if (
|
|
13200
|
-
if (
|
|
13253
|
+
if (existsSync28(uiBackup)) {
|
|
13254
|
+
if (existsSync28(uiDir)) rmSync6(uiDir, { recursive: true });
|
|
13201
13255
|
cpSync(uiBackup, uiDir, { recursive: true });
|
|
13202
13256
|
}
|
|
13203
13257
|
const configBackup = join21(backup, "design-system.config.ts");
|
|
13204
13258
|
const configDest = join21(projectRoot, "design-system.config.ts");
|
|
13205
|
-
if (
|
|
13259
|
+
if (existsSync28(configBackup)) {
|
|
13206
13260
|
cpSync(configBackup, configDest);
|
|
13207
13261
|
}
|
|
13208
13262
|
clearGuard(projectRoot);
|
|
@@ -13230,19 +13284,19 @@ async function migrateAction(options) {
|
|
|
13230
13284
|
return;
|
|
13231
13285
|
}
|
|
13232
13286
|
const guard = guardPath(projectRoot);
|
|
13233
|
-
if (
|
|
13287
|
+
if (existsSync28(guard)) {
|
|
13234
13288
|
console.log(chalk32.yellow("A migration is already in progress."));
|
|
13235
13289
|
console.log(chalk32.dim("Run `coherent migrate --rollback` to undo, or delete .coherent/migration-in-progress"));
|
|
13236
13290
|
return;
|
|
13237
13291
|
}
|
|
13238
13292
|
const uiDir = join21(projectRoot, "components", "ui");
|
|
13239
|
-
if (!
|
|
13293
|
+
if (!existsSync28(uiDir)) {
|
|
13240
13294
|
console.log(chalk32.yellow("No components/ui directory found. Nothing to migrate."));
|
|
13241
13295
|
return;
|
|
13242
13296
|
}
|
|
13243
13297
|
const provider = getComponentProvider();
|
|
13244
13298
|
const managedIds = new Set(provider.listNames());
|
|
13245
|
-
const files =
|
|
13299
|
+
const files = readdirSync10(uiDir).filter((f) => f.endsWith(".tsx"));
|
|
13246
13300
|
const migratable = files.map((f) => f.replace(".tsx", "")).filter((id) => managedIds.has(id));
|
|
13247
13301
|
if (migratable.length === 0) {
|
|
13248
13302
|
console.log(chalk32.green("All components are already up to date."));
|
|
@@ -13263,7 +13317,7 @@ Found ${migratable.length} component(s) to migrate:`));
|
|
|
13263
13317
|
try {
|
|
13264
13318
|
for (const id of migratable) {
|
|
13265
13319
|
const filePath = join21(uiDir, `${id}.tsx`);
|
|
13266
|
-
if (
|
|
13320
|
+
if (existsSync28(filePath)) rmSync6(filePath);
|
|
13267
13321
|
}
|
|
13268
13322
|
const results = await provider.installBatch(migratable, projectRoot, { force: true });
|
|
13269
13323
|
let migrated = 0;
|
|
@@ -13285,7 +13339,7 @@ Found ${migratable.length} component(s) to migrate:`));
|
|
|
13285
13339
|
}
|
|
13286
13340
|
|
|
13287
13341
|
// src/utils/update-notifier.ts
|
|
13288
|
-
import { existsSync as
|
|
13342
|
+
import { existsSync as existsSync29, mkdirSync as mkdirSync9, readFileSync as readFileSync21, writeFileSync as writeFileSync13 } from "fs";
|
|
13289
13343
|
import { join as join22 } from "path";
|
|
13290
13344
|
import { homedir } from "os";
|
|
13291
13345
|
import chalk33 from "chalk";
|
|
@@ -13297,8 +13351,8 @@ var CACHE_FILE = join22(CACHE_DIR, "update-check.json");
|
|
|
13297
13351
|
var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
13298
13352
|
function readCache() {
|
|
13299
13353
|
try {
|
|
13300
|
-
if (!
|
|
13301
|
-
const raw =
|
|
13354
|
+
if (!existsSync29(CACHE_FILE)) return null;
|
|
13355
|
+
const raw = readFileSync21(CACHE_FILE, "utf-8");
|
|
13302
13356
|
return JSON.parse(raw);
|
|
13303
13357
|
} catch (e) {
|
|
13304
13358
|
if (DEBUG5) console.error("Failed to read update cache:", e);
|
|
@@ -13307,7 +13361,7 @@ function readCache() {
|
|
|
13307
13361
|
}
|
|
13308
13362
|
function writeCache(data) {
|
|
13309
13363
|
try {
|
|
13310
|
-
if (!
|
|
13364
|
+
if (!existsSync29(CACHE_DIR)) mkdirSync9(CACHE_DIR, { recursive: true });
|
|
13311
13365
|
writeFileSync13(CACHE_FILE, JSON.stringify(data), "utf-8");
|
|
13312
13366
|
} catch (e) {
|
|
13313
13367
|
if (DEBUG5) console.error("Failed to write update cache:", e);
|