@getcoherent/cli 0.6.42 → 0.6.43
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/chunk-4TLYDTT3.js +22 -0
- package/dist/{chunk-TD2ZYIIC.js → chunk-662O2QEG.js} +5 -8
- package/dist/{chunk-QT5MRW4F.js → chunk-KJRBBLXT.js} +1 -1
- package/dist/{chunk-4A4YYAGN.js → chunk-NOM47EB4.js} +41 -3
- package/dist/chunk-Q67PCGRQ.js +308 -0
- package/dist/{code-generator-D3ZHOO4M.js → code-generator-CV54KQFF.js} +4 -3
- package/dist/fix-globals-css-UQCGJ5NO.js +9 -0
- package/dist/index.js +422 -585
- package/dist/{plan-generator-625ZNUZF.js → plan-generator-YOPF773K.js} +2 -2
- package/dist/{quality-validator-ONJCQ325.js → quality-validator-2KIT6QKA.js} +1 -1
- package/dist/strings-BHAW5PVU.js +11 -0
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
createAIProvider
|
|
3
|
-
} from "./chunk-SPQZBQYY.js";
|
|
4
1
|
import {
|
|
5
2
|
AUTH_SYNONYMS,
|
|
6
3
|
acquireProjectLock,
|
|
@@ -33,12 +30,11 @@ import {
|
|
|
33
30
|
routeToRelPath,
|
|
34
31
|
saveHashes,
|
|
35
32
|
scanAndInstallSharedDeps,
|
|
36
|
-
toKebabCase,
|
|
37
33
|
validateAndFixGeneratedCode,
|
|
38
34
|
warnIfVolatile,
|
|
39
35
|
warnInlineDuplicates,
|
|
40
36
|
writeFile
|
|
41
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-662O2QEG.js";
|
|
42
38
|
import {
|
|
43
39
|
COHERENT_REQUIRED_PACKAGES,
|
|
44
40
|
ensureUseClientIfNeeded,
|
|
@@ -56,7 +52,14 @@ import {
|
|
|
56
52
|
sanitizeMetadataStrings,
|
|
57
53
|
savePlan,
|
|
58
54
|
updateArchitecturePlan
|
|
59
|
-
} from "./chunk-
|
|
55
|
+
} from "./chunk-KJRBBLXT.js";
|
|
56
|
+
import {
|
|
57
|
+
toKebabCase,
|
|
58
|
+
toTitleCase
|
|
59
|
+
} from "./chunk-4TLYDTT3.js";
|
|
60
|
+
import {
|
|
61
|
+
createAIProvider
|
|
62
|
+
} from "./chunk-SPQZBQYY.js";
|
|
60
63
|
import {
|
|
61
64
|
CORE_CONSTRAINTS,
|
|
62
65
|
DESIGN_QUALITY,
|
|
@@ -68,13 +71,19 @@ import {
|
|
|
68
71
|
inferPageTypeFromRoute,
|
|
69
72
|
selectContextualRules
|
|
70
73
|
} from "./chunk-5AHG4NNX.js";
|
|
74
|
+
import {
|
|
75
|
+
fixGlobalsCss,
|
|
76
|
+
generateV4GlobalsCss,
|
|
77
|
+
isTailwindV4,
|
|
78
|
+
needsGlobalsFix
|
|
79
|
+
} from "./chunk-Q67PCGRQ.js";
|
|
71
80
|
import {
|
|
72
81
|
autoFixCode,
|
|
73
82
|
checkDesignConsistency,
|
|
74
83
|
formatIssues,
|
|
75
84
|
validatePageQuality,
|
|
76
85
|
verifyIncrementalEdit
|
|
77
|
-
} from "./chunk-
|
|
86
|
+
} from "./chunk-NOM47EB4.js";
|
|
78
87
|
import {
|
|
79
88
|
__require
|
|
80
89
|
} from "./chunk-3RG5ZIWI.js";
|
|
@@ -88,14 +97,14 @@ import { CLI_VERSION as CLI_VERSION6 } from "@getcoherent/core";
|
|
|
88
97
|
import chalk3 from "chalk";
|
|
89
98
|
import ora from "ora";
|
|
90
99
|
import prompts2 from "prompts";
|
|
91
|
-
import { existsSync as
|
|
92
|
-
import { join as join3 } from "path";
|
|
100
|
+
import { existsSync as existsSync4, readFileSync as readFileSync2, mkdirSync as mkdirSync3, rmSync, writeFileSync as writeFileSync4 } from "fs";
|
|
101
|
+
import { basename, join as join3 } from "path";
|
|
93
102
|
import { execSync } from "child_process";
|
|
94
103
|
import { ProjectScaffolder, ComponentGenerator } from "@getcoherent/core";
|
|
95
104
|
|
|
96
105
|
// src/utils/minimal-config.ts
|
|
97
106
|
import { CLI_VERSION, FRAMEWORK_VERSIONS } from "@getcoherent/core";
|
|
98
|
-
function createMinimalConfig() {
|
|
107
|
+
function createMinimalConfig(appName = "My App") {
|
|
99
108
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
100
109
|
return {
|
|
101
110
|
provider: "shadcn",
|
|
@@ -106,7 +115,7 @@ function createMinimalConfig() {
|
|
|
106
115
|
react: FRAMEWORK_VERSIONS.react,
|
|
107
116
|
tailwind: FRAMEWORK_VERSIONS.tailwindcss
|
|
108
117
|
},
|
|
109
|
-
name:
|
|
118
|
+
name: appName,
|
|
110
119
|
description: "Built with Coherent Design Method",
|
|
111
120
|
tokens: {
|
|
112
121
|
colors: {
|
|
@@ -254,7 +263,7 @@ function createMinimalConfig() {
|
|
|
254
263
|
layout: "centered",
|
|
255
264
|
sections: [],
|
|
256
265
|
title: "Home",
|
|
257
|
-
description:
|
|
266
|
+
description: `Welcome to ${appName}`,
|
|
258
267
|
requiresAuth: false,
|
|
259
268
|
noIndex: false,
|
|
260
269
|
createdAt: now,
|
|
@@ -1723,204 +1732,13 @@ async function regenerateCursorRules() {
|
|
|
1723
1732
|
return writeCursorRules(project.root);
|
|
1724
1733
|
}
|
|
1725
1734
|
|
|
1726
|
-
// src/utils/tailwind-version.ts
|
|
1727
|
-
import { existsSync as existsSync4, readFileSync as readFileSync2 } from "fs";
|
|
1728
|
-
import { resolve as resolve2 } from "path";
|
|
1729
|
-
function isTailwindV4(projectRoot) {
|
|
1730
|
-
const pkgPath = resolve2(projectRoot, "package.json");
|
|
1731
|
-
if (existsSync4(pkgPath)) {
|
|
1732
|
-
try {
|
|
1733
|
-
const pkg = JSON.parse(readFileSync2(pkgPath, "utf-8"));
|
|
1734
|
-
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
1735
|
-
if (allDeps["@tailwindcss/postcss"]) return true;
|
|
1736
|
-
const twVersion = allDeps["tailwindcss"] || "";
|
|
1737
|
-
if (twVersion.startsWith("^4") || twVersion.startsWith("~4") || twVersion.startsWith("4")) return true;
|
|
1738
|
-
} catch {
|
|
1739
|
-
}
|
|
1740
|
-
}
|
|
1741
|
-
const globalsPath = resolve2(projectRoot, "app", "globals.css");
|
|
1742
|
-
if (existsSync4(globalsPath)) {
|
|
1743
|
-
const content = readFileSync2(globalsPath, "utf-8");
|
|
1744
|
-
if (content.includes('@import "tailwindcss"') || content.includes("@import 'tailwindcss'")) return true;
|
|
1745
|
-
}
|
|
1746
|
-
return false;
|
|
1747
|
-
}
|
|
1748
|
-
function generateV4GlobalsCss(config2) {
|
|
1749
|
-
const light = config2.tokens.colors.light;
|
|
1750
|
-
const dark = config2.tokens.colors.dark;
|
|
1751
|
-
const contrastFg = (hex) => {
|
|
1752
|
-
const c = hex.replace("#", "");
|
|
1753
|
-
const r = parseInt(c.slice(0, 2), 16);
|
|
1754
|
-
const g = parseInt(c.slice(2, 4), 16);
|
|
1755
|
-
const b = parseInt(c.slice(4, 6), 16);
|
|
1756
|
-
const lum = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
|
|
1757
|
-
return lum > 0.5 ? "#09090b" : "#fafafa";
|
|
1758
|
-
};
|
|
1759
|
-
const blendColors = (hex1, hex2, ratio) => {
|
|
1760
|
-
const parse = (h) => {
|
|
1761
|
-
const c = h.replace("#", "");
|
|
1762
|
-
return [parseInt(c.slice(0, 2), 16), parseInt(c.slice(2, 4), 16), parseInt(c.slice(4, 6), 16)];
|
|
1763
|
-
};
|
|
1764
|
-
const [r1, g1, b1] = parse(hex1);
|
|
1765
|
-
const [r2, g2, b2] = parse(hex2);
|
|
1766
|
-
const blend = (a, b) => Math.round(a + (b - a) * ratio);
|
|
1767
|
-
const toHex = (n) => n.toString(16).padStart(2, "0");
|
|
1768
|
-
return `#${toHex(blend(r1, r2))}${toHex(blend(g1, g2))}${toHex(blend(b1, b2))}`;
|
|
1769
|
-
};
|
|
1770
|
-
const radius = config2.tokens.radius;
|
|
1771
|
-
return `@import "tailwindcss";
|
|
1772
|
-
|
|
1773
|
-
@theme inline {
|
|
1774
|
-
--color-background: var(--background);
|
|
1775
|
-
--color-foreground: var(--foreground);
|
|
1776
|
-
--color-primary: var(--primary);
|
|
1777
|
-
--color-primary-foreground: var(--primary-foreground);
|
|
1778
|
-
--color-secondary: var(--secondary);
|
|
1779
|
-
--color-secondary-foreground: var(--secondary-foreground);
|
|
1780
|
-
--color-muted: var(--muted);
|
|
1781
|
-
--color-muted-foreground: var(--muted-foreground);
|
|
1782
|
-
--color-accent: var(--accent);
|
|
1783
|
-
--color-accent-foreground: var(--accent-foreground);
|
|
1784
|
-
--color-destructive: var(--destructive);
|
|
1785
|
-
--color-destructive-foreground: var(--destructive-foreground);
|
|
1786
|
-
--color-transparent: transparent;
|
|
1787
|
-
--color-border: var(--border);
|
|
1788
|
-
--color-input: var(--input);
|
|
1789
|
-
--color-ring: var(--ring);
|
|
1790
|
-
--color-card: var(--card);
|
|
1791
|
-
--color-card-foreground: var(--card-foreground);
|
|
1792
|
-
--color-popover: var(--popover);
|
|
1793
|
-
--color-popover-foreground: var(--popover-foreground);
|
|
1794
|
-
--color-success: var(--success);
|
|
1795
|
-
--color-warning: var(--warning);
|
|
1796
|
-
--color-error: var(--error);
|
|
1797
|
-
--color-info: var(--info);
|
|
1798
|
-
--color-black: #000;
|
|
1799
|
-
--color-white: #fff;
|
|
1800
|
-
--color-sidebar-background: var(--sidebar-background);
|
|
1801
|
-
--color-sidebar-foreground: var(--sidebar-foreground);
|
|
1802
|
-
--color-sidebar-primary: var(--sidebar-primary);
|
|
1803
|
-
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
|
1804
|
-
--color-sidebar-accent: var(--sidebar-accent);
|
|
1805
|
-
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
|
1806
|
-
--color-sidebar-border: var(--sidebar-border);
|
|
1807
|
-
--color-sidebar-ring: var(--sidebar-ring);
|
|
1808
|
-
--color-sidebar-muted: var(--sidebar-muted);
|
|
1809
|
-
--color-sidebar-muted-foreground: var(--sidebar-muted-foreground);
|
|
1810
|
-
--color-chart-1: var(--chart-1);
|
|
1811
|
-
--color-chart-2: var(--chart-2);
|
|
1812
|
-
--color-chart-3: var(--chart-3);
|
|
1813
|
-
--color-chart-4: var(--chart-4);
|
|
1814
|
-
--color-chart-5: var(--chart-5);
|
|
1815
|
-
--radius-xs: 0.125rem;
|
|
1816
|
-
--radius-sm: ${radius.sm || "0.25rem"};
|
|
1817
|
-
--radius-md: ${radius.md || "0.5rem"};
|
|
1818
|
-
--radius-lg: ${radius.lg || "0.75rem"};
|
|
1819
|
-
--radius-xl: ${radius.xl || "1rem"};
|
|
1820
|
-
}
|
|
1821
|
-
|
|
1822
|
-
:root {
|
|
1823
|
-
--background: ${light.background};
|
|
1824
|
-
--foreground: ${light.foreground};
|
|
1825
|
-
--primary: ${light.primary};
|
|
1826
|
-
--primary-foreground: ${contrastFg(light.primary)};
|
|
1827
|
-
--secondary: ${light.secondary};
|
|
1828
|
-
--secondary-foreground: ${contrastFg(light.secondary)};
|
|
1829
|
-
--muted: ${light.muted};
|
|
1830
|
-
--muted-foreground: ${blendColors(light.foreground, light.background, 0.45)};
|
|
1831
|
-
--accent: ${light.accent || light.muted};
|
|
1832
|
-
--accent-foreground: ${light.foreground};
|
|
1833
|
-
--destructive: ${light.error};
|
|
1834
|
-
--destructive-foreground: ${contrastFg(light.error)};
|
|
1835
|
-
--border: ${light.border};
|
|
1836
|
-
--input: ${light.border};
|
|
1837
|
-
--ring: ${light.primary};
|
|
1838
|
-
--radius: ${radius.md || "0.5rem"};
|
|
1839
|
-
--card: ${light.background};
|
|
1840
|
-
--card-foreground: ${light.foreground};
|
|
1841
|
-
--popover: ${light.background};
|
|
1842
|
-
--popover-foreground: ${light.foreground};
|
|
1843
|
-
--success: ${light.success};
|
|
1844
|
-
--warning: ${light.warning};
|
|
1845
|
-
--error: ${light.error};
|
|
1846
|
-
--info: ${light.info || light.primary};
|
|
1847
|
-
--sidebar-background: ${light.background};
|
|
1848
|
-
--sidebar-foreground: ${light.foreground};
|
|
1849
|
-
--sidebar-primary: ${light.primary};
|
|
1850
|
-
--sidebar-primary-foreground: ${contrastFg(light.primary)};
|
|
1851
|
-
--sidebar-accent: ${light.accent || light.muted};
|
|
1852
|
-
--sidebar-accent-foreground: ${light.foreground};
|
|
1853
|
-
--sidebar-border: ${light.border};
|
|
1854
|
-
--sidebar-ring: ${light.primary};
|
|
1855
|
-
--sidebar-muted: ${light.muted};
|
|
1856
|
-
--sidebar-muted-foreground: ${blendColors(light.foreground, light.background, 0.45)};
|
|
1857
|
-
--chart-1: ${light.primary};
|
|
1858
|
-
--chart-2: ${light.success};
|
|
1859
|
-
--chart-3: ${light.warning};
|
|
1860
|
-
--chart-4: ${light.error};
|
|
1861
|
-
--chart-5: ${light.info || light.primary};
|
|
1862
|
-
}
|
|
1863
|
-
|
|
1864
|
-
.dark {
|
|
1865
|
-
--background: ${dark.background};
|
|
1866
|
-
--foreground: ${dark.foreground};
|
|
1867
|
-
--primary: ${dark.primary};
|
|
1868
|
-
--primary-foreground: ${contrastFg(dark.primary)};
|
|
1869
|
-
--secondary: ${dark.secondary};
|
|
1870
|
-
--secondary-foreground: ${contrastFg(dark.secondary)};
|
|
1871
|
-
--muted: ${dark.muted};
|
|
1872
|
-
--muted-foreground: ${blendColors(dark.foreground, dark.background, 0.45)};
|
|
1873
|
-
--accent: ${dark.accent || dark.muted};
|
|
1874
|
-
--accent-foreground: ${dark.foreground};
|
|
1875
|
-
--destructive: ${dark.error};
|
|
1876
|
-
--destructive-foreground: ${contrastFg(dark.error)};
|
|
1877
|
-
--border: ${dark.border};
|
|
1878
|
-
--input: ${dark.border};
|
|
1879
|
-
--ring: ${dark.primary};
|
|
1880
|
-
--card: ${dark.background};
|
|
1881
|
-
--card-foreground: ${dark.foreground};
|
|
1882
|
-
--popover: ${dark.background};
|
|
1883
|
-
--popover-foreground: ${dark.foreground};
|
|
1884
|
-
--success: ${dark.success};
|
|
1885
|
-
--warning: ${dark.warning};
|
|
1886
|
-
--error: ${dark.error};
|
|
1887
|
-
--info: ${dark.info || dark.primary};
|
|
1888
|
-
--sidebar-background: ${dark.background};
|
|
1889
|
-
--sidebar-foreground: ${dark.foreground};
|
|
1890
|
-
--sidebar-primary: ${dark.primary};
|
|
1891
|
-
--sidebar-primary-foreground: ${contrastFg(dark.primary)};
|
|
1892
|
-
--sidebar-accent: ${dark.accent || dark.muted};
|
|
1893
|
-
--sidebar-accent-foreground: ${dark.foreground};
|
|
1894
|
-
--sidebar-border: ${dark.border};
|
|
1895
|
-
--sidebar-ring: ${dark.primary};
|
|
1896
|
-
--sidebar-muted: ${dark.muted};
|
|
1897
|
-
--sidebar-muted-foreground: ${blendColors(dark.foreground, dark.background, 0.45)};
|
|
1898
|
-
--chart-1: ${dark.primary};
|
|
1899
|
-
--chart-2: ${dark.success};
|
|
1900
|
-
--chart-3: ${dark.warning};
|
|
1901
|
-
--chart-4: ${dark.error};
|
|
1902
|
-
--chart-5: ${dark.info || dark.primary};
|
|
1903
|
-
}
|
|
1904
|
-
|
|
1905
|
-
* {
|
|
1906
|
-
border-color: var(--border);
|
|
1907
|
-
}
|
|
1908
|
-
|
|
1909
|
-
body {
|
|
1910
|
-
background-color: var(--background);
|
|
1911
|
-
color: var(--foreground);
|
|
1912
|
-
font-family: Arial, Helvetica, sans-serif;
|
|
1913
|
-
}
|
|
1914
|
-
`;
|
|
1915
|
-
}
|
|
1916
|
-
|
|
1917
1735
|
// src/commands/init.ts
|
|
1918
1736
|
import { cwd } from "process";
|
|
1919
1737
|
function hasNextInPackageJson(projectPath) {
|
|
1920
1738
|
const pkgPath = join3(projectPath, "package.json");
|
|
1921
|
-
if (!
|
|
1739
|
+
if (!existsSync4(pkgPath)) return false;
|
|
1922
1740
|
try {
|
|
1923
|
-
const json = JSON.parse(
|
|
1741
|
+
const json = JSON.parse(readFileSync2(pkgPath, "utf-8"));
|
|
1924
1742
|
const deps = { ...json.dependencies, ...json.devDependencies };
|
|
1925
1743
|
return typeof deps?.next === "string";
|
|
1926
1744
|
} catch {
|
|
@@ -1931,7 +1749,7 @@ function cleanConflictingFiles(projectPath) {
|
|
|
1931
1749
|
const conflicts = [".next", ".coherent", ".cursorrules", ".eslintrc.json", "CLAUDE.md", ".claude", ".vscode"];
|
|
1932
1750
|
for (const name of conflicts) {
|
|
1933
1751
|
const fullPath = join3(projectPath, name);
|
|
1934
|
-
if (
|
|
1752
|
+
if (existsSync4(fullPath)) {
|
|
1935
1753
|
rmSync(fullPath, { recursive: true, force: true });
|
|
1936
1754
|
}
|
|
1937
1755
|
}
|
|
@@ -1939,12 +1757,12 @@ function cleanConflictingFiles(projectPath) {
|
|
|
1939
1757
|
function runCreateNextApp(projectPath) {
|
|
1940
1758
|
cleanConflictingFiles(projectPath);
|
|
1941
1759
|
const envPath = join3(projectPath, ".env");
|
|
1942
|
-
const envBackup =
|
|
1760
|
+
const envBackup = existsSync4(envPath) ? readFileSync2(envPath, "utf-8") : null;
|
|
1943
1761
|
if (envBackup !== null) rmSync(envPath, { force: true });
|
|
1944
1762
|
const cmd = "npx --yes create-next-app@15.2.4 . --typescript --tailwind --eslint --app --no-src-dir --no-turbopack --yes";
|
|
1945
1763
|
execSync(cmd, { cwd: projectPath, stdio: "inherit" });
|
|
1946
1764
|
if (envBackup !== null) {
|
|
1947
|
-
const existing =
|
|
1765
|
+
const existing = existsSync4(envPath) ? readFileSync2(envPath, "utf-8") : "";
|
|
1948
1766
|
writeFileSync4(envPath, existing ? existing + "\n" + envBackup : envBackup, "utf-8");
|
|
1949
1767
|
}
|
|
1950
1768
|
}
|
|
@@ -1952,8 +1770,8 @@ async function ensureCoherentPrerequisites(projectPath) {
|
|
|
1952
1770
|
const libPath = join3(projectPath, "lib");
|
|
1953
1771
|
const utilsPath = join3(projectPath, "lib", "utils.ts");
|
|
1954
1772
|
const componentsUiPath = join3(projectPath, "components", "ui");
|
|
1955
|
-
if (!
|
|
1956
|
-
if (!
|
|
1773
|
+
if (!existsSync4(utilsPath)) {
|
|
1774
|
+
if (!existsSync4(libPath)) mkdirSync3(libPath, { recursive: true });
|
|
1957
1775
|
const cnContent = `import { type ClassValue, clsx } from 'clsx'
|
|
1958
1776
|
import { twMerge } from 'tailwind-merge'
|
|
1959
1777
|
|
|
@@ -1963,7 +1781,7 @@ export function cn(...inputs: ClassValue[]) {
|
|
|
1963
1781
|
`;
|
|
1964
1782
|
await writeFile(utilsPath, cnContent);
|
|
1965
1783
|
}
|
|
1966
|
-
if (!
|
|
1784
|
+
if (!existsSync4(componentsUiPath)) mkdirSync3(componentsUiPath, { recursive: true });
|
|
1967
1785
|
}
|
|
1968
1786
|
async function ensureRegistryComponents(config2, projectPath) {
|
|
1969
1787
|
const provider = getComponentProvider();
|
|
@@ -1971,12 +1789,12 @@ async function ensureRegistryComponents(config2, projectPath) {
|
|
|
1971
1789
|
await provider.installBatch(baseComponents, projectPath);
|
|
1972
1790
|
const generator = new ComponentGenerator(config2);
|
|
1973
1791
|
const uiDir = join3(projectPath, "components", "ui");
|
|
1974
|
-
if (!
|
|
1792
|
+
if (!existsSync4(uiDir)) mkdirSync3(uiDir, { recursive: true });
|
|
1975
1793
|
for (const comp of config2.components) {
|
|
1976
1794
|
if (comp.source === "shadcn") continue;
|
|
1977
1795
|
const fileName = toKebabCase(comp.name) + ".tsx";
|
|
1978
1796
|
const filePath = join3(uiDir, fileName);
|
|
1979
|
-
if (
|
|
1797
|
+
if (existsSync4(filePath)) continue;
|
|
1980
1798
|
const code = await generator.generate(comp);
|
|
1981
1799
|
await writeFile(filePath, code);
|
|
1982
1800
|
}
|
|
@@ -2005,7 +1823,7 @@ async function initCommand(name) {
|
|
|
2005
1823
|
process.exit(1);
|
|
2006
1824
|
}
|
|
2007
1825
|
const targetDir = join3(cwd(), name);
|
|
2008
|
-
if (!
|
|
1826
|
+
if (!existsSync4(targetDir)) {
|
|
2009
1827
|
mkdirSync3(targetDir, { recursive: true });
|
|
2010
1828
|
}
|
|
2011
1829
|
process.chdir(targetDir);
|
|
@@ -2013,7 +1831,7 @@ async function initCommand(name) {
|
|
|
2013
1831
|
let projectPath;
|
|
2014
1832
|
try {
|
|
2015
1833
|
projectPath = cwd();
|
|
2016
|
-
if (!
|
|
1834
|
+
if (!existsSync4(projectPath)) {
|
|
2017
1835
|
throw new Error("ENOENT");
|
|
2018
1836
|
}
|
|
2019
1837
|
} catch (err) {
|
|
@@ -2073,8 +1891,24 @@ async function initCommand(name) {
|
|
|
2073
1891
|
});
|
|
2074
1892
|
autoScaffoldValue = answer ?? true;
|
|
2075
1893
|
}
|
|
1894
|
+
let appName;
|
|
1895
|
+
if (name) {
|
|
1896
|
+
appName = toTitleCase(name);
|
|
1897
|
+
} else {
|
|
1898
|
+
try {
|
|
1899
|
+
const pkgPath = join3(projectPath, "package.json");
|
|
1900
|
+
if (existsSync4(pkgPath)) {
|
|
1901
|
+
const pkg = JSON.parse(readFileSync2(pkgPath, "utf-8"));
|
|
1902
|
+
if (typeof pkg.name === "string" && pkg.name) {
|
|
1903
|
+
appName = toTitleCase(pkg.name);
|
|
1904
|
+
}
|
|
1905
|
+
}
|
|
1906
|
+
} catch {
|
|
1907
|
+
}
|
|
1908
|
+
if (!appName) appName = toTitleCase(basename(projectPath));
|
|
1909
|
+
}
|
|
2076
1910
|
const spinner = ora("Creating design system...").start();
|
|
2077
|
-
const config2 = createMinimalConfig();
|
|
1911
|
+
const config2 = createMinimalConfig(appName);
|
|
2078
1912
|
config2.settings.autoScaffold = autoScaffoldValue;
|
|
2079
1913
|
const configContent = generateConfigFile(config2);
|
|
2080
1914
|
await writeFile("./design-system.config.ts", configContent);
|
|
@@ -2175,9 +2009,9 @@ async function configureNextImages(projectPath) {
|
|
|
2175
2009
|
const jsPath = join3(projectPath, "next.config.js");
|
|
2176
2010
|
const mjsPath = join3(projectPath, "next.config.mjs");
|
|
2177
2011
|
let configPath = "";
|
|
2178
|
-
if (
|
|
2179
|
-
else if (
|
|
2180
|
-
else if (
|
|
2012
|
+
if (existsSync4(tsPath)) configPath = tsPath;
|
|
2013
|
+
else if (existsSync4(mjsPath)) configPath = mjsPath;
|
|
2014
|
+
else if (existsSync4(jsPath)) configPath = jsPath;
|
|
2181
2015
|
else return;
|
|
2182
2016
|
const content = `import type { NextConfig } from "next";
|
|
2183
2017
|
|
|
@@ -2216,8 +2050,8 @@ async function createAppRouteGroupLayout(projectPath) {
|
|
|
2216
2050
|
// src/commands/chat.ts
|
|
2217
2051
|
import chalk10 from "chalk";
|
|
2218
2052
|
import ora2 from "ora";
|
|
2219
|
-
import { resolve as
|
|
2220
|
-
import { existsSync as
|
|
2053
|
+
import { resolve as resolve5, relative as relative2, join as join6 } from "path";
|
|
2054
|
+
import { existsSync as existsSync9, readFileSync as readFileSync6, mkdirSync as mkdirSync6, readdirSync as readdirSync3 } from "fs";
|
|
2221
2055
|
import {
|
|
2222
2056
|
DesignSystemManager as DesignSystemManager5,
|
|
2223
2057
|
ComponentManager as ComponentManager4,
|
|
@@ -2717,7 +2551,7 @@ function extractComponentSpec(changes) {
|
|
|
2717
2551
|
// src/utils/dark-mode.ts
|
|
2718
2552
|
import { readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
|
|
2719
2553
|
import { join as join4 } from "path";
|
|
2720
|
-
import { existsSync as
|
|
2554
|
+
import { existsSync as existsSync5 } from "fs";
|
|
2721
2555
|
import { generateSharedComponent, loadManifest as loadManifest3, integrateSharedLayoutIntoRootLayout } from "@getcoherent/core";
|
|
2722
2556
|
var THEME_TOGGLE_CODE = `'use client'
|
|
2723
2557
|
|
|
@@ -2744,7 +2578,7 @@ export function ThemeToggle() {
|
|
|
2744
2578
|
`;
|
|
2745
2579
|
async function setDefaultDarkTheme(projectRoot) {
|
|
2746
2580
|
const layoutPath = join4(projectRoot, "app", "layout.tsx");
|
|
2747
|
-
if (!
|
|
2581
|
+
if (!existsSync5(layoutPath)) return false;
|
|
2748
2582
|
let content = await readFile2(layoutPath, "utf-8");
|
|
2749
2583
|
if (content.includes('<html className="dark"') || content.includes("<html className='dark'")) return true;
|
|
2750
2584
|
content = content.replace(/<html(\s|>)/, '<html className="dark"$1');
|
|
@@ -2772,7 +2606,7 @@ async function ensureThemeToggle(projectRoot) {
|
|
|
2772
2606
|
import { appendFile } from "fs/promises";
|
|
2773
2607
|
|
|
2774
2608
|
// src/utils/backup.ts
|
|
2775
|
-
import { existsSync as
|
|
2609
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync4, readFileSync as readFileSync3, writeFileSync as writeFileSync5, readdirSync, rmSync as rmSync2, statSync } from "fs";
|
|
2776
2610
|
import { join as join5, relative, dirname as dirname2 } from "path";
|
|
2777
2611
|
import chalk5 from "chalk";
|
|
2778
2612
|
var DEBUG = process.env.COHERENT_DEBUG === "1";
|
|
@@ -2795,16 +2629,16 @@ function createBackup(projectRoot) {
|
|
|
2795
2629
|
let fileCount = 0;
|
|
2796
2630
|
for (const file of CRITICAL_FILES) {
|
|
2797
2631
|
const src = join5(projectRoot, file);
|
|
2798
|
-
if (
|
|
2632
|
+
if (existsSync6(src)) {
|
|
2799
2633
|
const dest = join5(backupPath, file);
|
|
2800
2634
|
mkdirSync4(dirname2(dest), { recursive: true });
|
|
2801
|
-
writeFileSync5(dest,
|
|
2635
|
+
writeFileSync5(dest, readFileSync3(src));
|
|
2802
2636
|
fileCount++;
|
|
2803
2637
|
}
|
|
2804
2638
|
}
|
|
2805
2639
|
for (const dir of CRITICAL_DIRS) {
|
|
2806
2640
|
const srcDir = join5(projectRoot, dir);
|
|
2807
|
-
if (!
|
|
2641
|
+
if (!existsSync6(srcDir)) continue;
|
|
2808
2642
|
backupDirectory(srcDir, projectRoot, backupPath);
|
|
2809
2643
|
fileCount += countFiles(srcDir);
|
|
2810
2644
|
}
|
|
@@ -2838,7 +2672,7 @@ function backupDirectory(srcDir, projectRoot, backupPath) {
|
|
|
2838
2672
|
backupDirectory(fullPath, projectRoot, backupPath);
|
|
2839
2673
|
} else if (entry.isFile()) {
|
|
2840
2674
|
mkdirSync4(dirname2(destPath), { recursive: true });
|
|
2841
|
-
writeFileSync5(destPath,
|
|
2675
|
+
writeFileSync5(destPath, readFileSync3(fullPath));
|
|
2842
2676
|
}
|
|
2843
2677
|
}
|
|
2844
2678
|
}
|
|
@@ -2872,14 +2706,14 @@ function pruneOldBackups(backupBase) {
|
|
|
2872
2706
|
}
|
|
2873
2707
|
function listBackups(projectRoot) {
|
|
2874
2708
|
const backupBase = join5(projectRoot, BACKUP_DIR);
|
|
2875
|
-
if (!
|
|
2709
|
+
if (!existsSync6(backupBase)) return [];
|
|
2876
2710
|
try {
|
|
2877
2711
|
return readdirSync(backupBase).filter((e) => !e.startsWith(".")).map((name) => {
|
|
2878
2712
|
const metaPath = join5(backupBase, name, ".backup-meta.json");
|
|
2879
2713
|
let meta = { timestamp: name, files: 0 };
|
|
2880
|
-
if (
|
|
2714
|
+
if (existsSync6(metaPath)) {
|
|
2881
2715
|
try {
|
|
2882
|
-
meta = JSON.parse(
|
|
2716
|
+
meta = JSON.parse(readFileSync3(metaPath, "utf-8"));
|
|
2883
2717
|
} catch (e) {
|
|
2884
2718
|
if (DEBUG) console.error("Bad backup meta:", metaPath, e);
|
|
2885
2719
|
}
|
|
@@ -2893,7 +2727,7 @@ function listBackups(projectRoot) {
|
|
|
2893
2727
|
}
|
|
2894
2728
|
function restoreBackup(projectRoot, backupName) {
|
|
2895
2729
|
const backupPath = join5(projectRoot, BACKUP_DIR, backupName);
|
|
2896
|
-
if (!
|
|
2730
|
+
if (!existsSync6(backupPath)) return false;
|
|
2897
2731
|
try {
|
|
2898
2732
|
restoreDirectory(backupPath, backupPath, projectRoot);
|
|
2899
2733
|
return true;
|
|
@@ -2914,7 +2748,7 @@ function restoreDirectory(currentDir, backupRoot, projectRoot) {
|
|
|
2914
2748
|
restoreDirectory(fullPath, backupRoot, projectRoot);
|
|
2915
2749
|
} else if (entry.isFile()) {
|
|
2916
2750
|
mkdirSync4(dirname2(destPath), { recursive: true });
|
|
2917
|
-
writeFileSync5(destPath,
|
|
2751
|
+
writeFileSync5(destPath, readFileSync3(fullPath));
|
|
2918
2752
|
}
|
|
2919
2753
|
}
|
|
2920
2754
|
}
|
|
@@ -2925,78 +2759,6 @@ function logBackupCreated(backupPath) {
|
|
|
2925
2759
|
}
|
|
2926
2760
|
}
|
|
2927
2761
|
|
|
2928
|
-
// src/utils/fix-globals-css.ts
|
|
2929
|
-
import { existsSync as existsSync8, readFileSync as readFileSync5, writeFileSync as writeFileSync6 } from "fs";
|
|
2930
|
-
import { resolve as resolve3 } from "path";
|
|
2931
|
-
import { buildCssVariables } from "@getcoherent/core";
|
|
2932
|
-
function needsGlobalsFix(projectRoot) {
|
|
2933
|
-
const globalsPath = resolve3(projectRoot, "app", "globals.css");
|
|
2934
|
-
if (!existsSync8(globalsPath)) {
|
|
2935
|
-
return false;
|
|
2936
|
-
}
|
|
2937
|
-
const content = readFileSync5(globalsPath, "utf-8");
|
|
2938
|
-
if (isTailwindV4(projectRoot)) {
|
|
2939
|
-
if (!content.includes("@theme inline")) return true;
|
|
2940
|
-
if (content.includes("@tailwind base")) return true;
|
|
2941
|
-
const REQUIRED_V4_TOKENS = [
|
|
2942
|
-
"--color-transparent",
|
|
2943
|
-
"--color-sidebar-background",
|
|
2944
|
-
"--color-chart-1",
|
|
2945
|
-
"--color-black",
|
|
2946
|
-
"--color-white",
|
|
2947
|
-
"--radius-xs"
|
|
2948
|
-
];
|
|
2949
|
-
for (const token of REQUIRED_V4_TOKENS) {
|
|
2950
|
-
if (!content.includes(token)) return true;
|
|
2951
|
-
}
|
|
2952
|
-
return false;
|
|
2953
|
-
}
|
|
2954
|
-
if (content.includes(":root {") || content.includes(".dark {")) return true;
|
|
2955
|
-
if (content.includes("@apply")) return true;
|
|
2956
|
-
if (!content.includes("@tailwind base") || content.length < 100) return true;
|
|
2957
|
-
return false;
|
|
2958
|
-
}
|
|
2959
|
-
function fixGlobalsCss(projectRoot, config2) {
|
|
2960
|
-
const globalsPath = resolve3(projectRoot, "app", "globals.css");
|
|
2961
|
-
const layoutPath = resolve3(projectRoot, "app", "layout.tsx");
|
|
2962
|
-
if (!existsSync8(globalsPath)) {
|
|
2963
|
-
return;
|
|
2964
|
-
}
|
|
2965
|
-
if (isTailwindV4(projectRoot)) {
|
|
2966
|
-
const v4Css = generateV4GlobalsCss(config2);
|
|
2967
|
-
writeFileSync6(globalsPath, v4Css, "utf-8");
|
|
2968
|
-
return;
|
|
2969
|
-
}
|
|
2970
|
-
const minimalCss = `@tailwind base;
|
|
2971
|
-
@tailwind components;
|
|
2972
|
-
@tailwind utilities;
|
|
2973
|
-
|
|
2974
|
-
@layer base {
|
|
2975
|
-
* {
|
|
2976
|
-
border-color: var(--border);
|
|
2977
|
-
}
|
|
2978
|
-
body {
|
|
2979
|
-
background-color: var(--background);
|
|
2980
|
-
color: var(--foreground);
|
|
2981
|
-
}
|
|
2982
|
-
}
|
|
2983
|
-
`;
|
|
2984
|
-
writeFileSync6(globalsPath, minimalCss, "utf-8");
|
|
2985
|
-
if (!existsSync8(layoutPath)) {
|
|
2986
|
-
return;
|
|
2987
|
-
}
|
|
2988
|
-
let layoutContent = readFileSync5(layoutPath, "utf-8");
|
|
2989
|
-
if (layoutContent.includes("dangerouslySetInnerHTML")) {
|
|
2990
|
-
return;
|
|
2991
|
-
}
|
|
2992
|
-
const cssVars = buildCssVariables(config2);
|
|
2993
|
-
const headBlock = `<head>
|
|
2994
|
-
<style dangerouslySetInnerHTML={{ __html: ${JSON.stringify(cssVars)} }} />
|
|
2995
|
-
</head>`;
|
|
2996
|
-
layoutContent = layoutContent.replace('<html lang="en">', '<html lang="en">\n ' + headBlock);
|
|
2997
|
-
writeFileSync6(layoutPath, layoutContent, "utf-8");
|
|
2998
|
-
}
|
|
2999
|
-
|
|
3000
2762
|
// src/commands/chat/request-parser.ts
|
|
3001
2763
|
import { colorToHex } from "@getcoherent/core";
|
|
3002
2764
|
var AUTH_FLOW_PATTERNS = {
|
|
@@ -3443,8 +3205,8 @@ function applyDefaults(request) {
|
|
|
3443
3205
|
}
|
|
3444
3206
|
|
|
3445
3207
|
// src/commands/chat/split-generator.ts
|
|
3446
|
-
import { existsSync as
|
|
3447
|
-
import { resolve as
|
|
3208
|
+
import { existsSync as existsSync7, readFileSync as readFileSync4, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
|
|
3209
|
+
import { resolve as resolve2 } from "path";
|
|
3448
3210
|
import { z } from "zod";
|
|
3449
3211
|
import {
|
|
3450
3212
|
SharedComponentTypeSchema,
|
|
@@ -3892,10 +3654,10 @@ function readExistingAppPageForReference(projectRoot, plan) {
|
|
|
3892
3654
|
for (const [key, note] of Object.entries(plan.pageNotes)) {
|
|
3893
3655
|
if (note.type !== "app") continue;
|
|
3894
3656
|
for (const group of ["(app)", "(admin)", "(dashboard)"]) {
|
|
3895
|
-
const filePath =
|
|
3657
|
+
const filePath = resolve2(projectRoot, "app", group, key, "page.tsx");
|
|
3896
3658
|
try {
|
|
3897
|
-
if (
|
|
3898
|
-
const code =
|
|
3659
|
+
if (existsSync7(filePath)) {
|
|
3660
|
+
const code = readFileSync4(filePath, "utf-8");
|
|
3899
3661
|
const lines = code.split("\n");
|
|
3900
3662
|
return lines.slice(0, 60).join("\n");
|
|
3901
3663
|
}
|
|
@@ -3905,19 +3667,19 @@ function readExistingAppPageForReference(projectRoot, plan) {
|
|
|
3905
3667
|
}
|
|
3906
3668
|
}
|
|
3907
3669
|
}
|
|
3908
|
-
const appDir =
|
|
3909
|
-
if (!
|
|
3670
|
+
const appDir = resolve2(projectRoot, "app");
|
|
3671
|
+
if (!existsSync7(appDir)) return null;
|
|
3910
3672
|
try {
|
|
3911
3673
|
const entries = readdirSync2(appDir);
|
|
3912
3674
|
for (const entry of entries) {
|
|
3913
3675
|
if (!entry.startsWith("(") || entry === "(auth)") continue;
|
|
3914
|
-
const groupDir =
|
|
3676
|
+
const groupDir = resolve2(appDir, entry);
|
|
3915
3677
|
if (!statSync2(groupDir).isDirectory()) continue;
|
|
3916
3678
|
const subDirs = readdirSync2(groupDir);
|
|
3917
3679
|
for (const sub of subDirs) {
|
|
3918
|
-
const pagePath =
|
|
3919
|
-
if (
|
|
3920
|
-
const code =
|
|
3680
|
+
const pagePath = resolve2(groupDir, sub, "page.tsx");
|
|
3681
|
+
if (existsSync7(pagePath)) {
|
|
3682
|
+
const code = readFileSync4(pagePath, "utf-8");
|
|
3921
3683
|
const lines = code.split("\n");
|
|
3922
3684
|
return lines.slice(0, 60).join("\n");
|
|
3923
3685
|
}
|
|
@@ -4134,7 +3896,7 @@ async function splitGeneratePages(spinner, message, modCtx, provider, parseOpts)
|
|
|
4134
3896
|
if (plan && plan.sharedComponents.length > 0) {
|
|
4135
3897
|
spinner.start(`Phase 4.5/6 \u2014 Generating ${plan.sharedComponents.length} shared components from plan...`);
|
|
4136
3898
|
try {
|
|
4137
|
-
const { generateSharedComponentsFromPlan } = await import("./plan-generator-
|
|
3899
|
+
const { generateSharedComponentsFromPlan } = await import("./plan-generator-YOPF773K.js");
|
|
4138
3900
|
const generated = await generateSharedComponentsFromPlan(
|
|
4139
3901
|
plan,
|
|
4140
3902
|
styleContext,
|
|
@@ -4190,14 +3952,14 @@ ${existingAppPageCode}
|
|
|
4190
3952
|
const existingPagesContext = buildExistingPagesContext(modCtx.config);
|
|
4191
3953
|
const existingPageCode = {};
|
|
4192
3954
|
if (projectRoot) {
|
|
4193
|
-
const appDir =
|
|
4194
|
-
if (
|
|
3955
|
+
const appDir = resolve2(projectRoot, "app");
|
|
3956
|
+
if (existsSync7(appDir)) {
|
|
4195
3957
|
const pageFiles = readdirSync2(appDir, { recursive: true }).filter(
|
|
4196
3958
|
(f) => typeof f === "string" && f.endsWith("page.tsx")
|
|
4197
3959
|
);
|
|
4198
3960
|
for (const pf of pageFiles) {
|
|
4199
3961
|
try {
|
|
4200
|
-
const code =
|
|
3962
|
+
const code = readFileSync4(resolve2(appDir, pf), "utf-8");
|
|
4201
3963
|
const route = "/" + pf.replace(/\/page\.tsx$/, "").replace(/\(.*?\)\//g, "");
|
|
4202
3964
|
existingPageCode[route === "/" ? "/" : route] = code;
|
|
4203
3965
|
} catch {
|
|
@@ -4477,7 +4239,7 @@ function extractAppNameFromPrompt(prompt) {
|
|
|
4477
4239
|
}
|
|
4478
4240
|
|
|
4479
4241
|
// src/commands/chat/modification-handler.ts
|
|
4480
|
-
import { resolve as
|
|
4242
|
+
import { resolve as resolve3 } from "path";
|
|
4481
4243
|
import { mkdir } from "fs/promises";
|
|
4482
4244
|
import { dirname as dirname3 } from "path";
|
|
4483
4245
|
import chalk8 from "chalk";
|
|
@@ -4868,7 +4630,7 @@ async function applyModification(request, dsm, cm, pm, projectRoot, aiProvider,
|
|
|
4868
4630
|
modified: []
|
|
4869
4631
|
};
|
|
4870
4632
|
}
|
|
4871
|
-
const fullPath =
|
|
4633
|
+
const fullPath = resolve3(projectRoot, resolved.file);
|
|
4872
4634
|
let currentCode;
|
|
4873
4635
|
try {
|
|
4874
4636
|
currentCode = await readFile(fullPath);
|
|
@@ -4943,7 +4705,7 @@ async function applyModification(request, dsm, cm, pm, projectRoot, aiProvider,
|
|
|
4943
4705
|
} catch {
|
|
4944
4706
|
return { success: false, message: `Could not read ${pageFilePath}`, modified: [] };
|
|
4945
4707
|
}
|
|
4946
|
-
const sharedPath =
|
|
4708
|
+
const sharedPath = resolve3(projectRoot, resolved.file);
|
|
4947
4709
|
let sharedCode;
|
|
4948
4710
|
try {
|
|
4949
4711
|
sharedCode = await readFile(sharedPath);
|
|
@@ -5019,7 +4781,7 @@ async function applyModification(request, dsm, cm, pm, projectRoot, aiProvider,
|
|
|
5019
4781
|
}
|
|
5020
4782
|
let sourceCode;
|
|
5021
4783
|
try {
|
|
5022
|
-
sourceCode = await readFile(
|
|
4784
|
+
sourceCode = await readFile(resolve3(projectRoot, sourcePath));
|
|
5023
4785
|
} catch {
|
|
5024
4786
|
return { success: false, message: `Could not read ${sourcePath}`, modified: [] };
|
|
5025
4787
|
}
|
|
@@ -5039,7 +4801,7 @@ async function applyModification(request, dsm, cm, pm, projectRoot, aiProvider,
|
|
|
5039
4801
|
description: `Extracted from ${sourcePageName}: ${blockHint}`,
|
|
5040
4802
|
usedIn: []
|
|
5041
4803
|
});
|
|
5042
|
-
const sharedPath =
|
|
4804
|
+
const sharedPath = resolve3(projectRoot, created.file);
|
|
5043
4805
|
let sharedCode;
|
|
5044
4806
|
try {
|
|
5045
4807
|
sharedCode = await readFile(sharedPath);
|
|
@@ -5050,7 +4812,7 @@ async function applyModification(request, dsm, cm, pm, projectRoot, aiProvider,
|
|
|
5050
4812
|
for (const pageName of allPagesToLink) {
|
|
5051
4813
|
const relPath = routeToPath(pageName);
|
|
5052
4814
|
if (!relPath) continue;
|
|
5053
|
-
const fullPath =
|
|
4815
|
+
const fullPath = resolve3(projectRoot, relPath);
|
|
5054
4816
|
let linkPageCode;
|
|
5055
4817
|
try {
|
|
5056
4818
|
linkPageCode = await readFile(fullPath);
|
|
@@ -5737,8 +5499,8 @@ function hasNavChanged(before, after) {
|
|
|
5737
5499
|
|
|
5738
5500
|
// src/commands/chat/interactive.ts
|
|
5739
5501
|
import chalk9 from "chalk";
|
|
5740
|
-
import { resolve as
|
|
5741
|
-
import { existsSync as
|
|
5502
|
+
import { resolve as resolve4 } from "path";
|
|
5503
|
+
import { existsSync as existsSync8, readFileSync as readFileSync5, writeFileSync as writeFileSync6, mkdirSync as mkdirSync5 } from "fs";
|
|
5742
5504
|
import { DesignSystemManager as DesignSystemManager4, ComponentManager as ComponentManager3, loadManifest as loadManifest6 } from "@getcoherent/core";
|
|
5743
5505
|
var DEBUG3 = process.env.COHERENT_DEBUG === "1";
|
|
5744
5506
|
async function interactiveChat(options, chatCommandFn) {
|
|
@@ -5758,13 +5520,13 @@ async function interactiveChat(options, chatCommandFn) {
|
|
|
5758
5520
|
\u274C Invalid provider: ${options.provider}`));
|
|
5759
5521
|
process.exit(1);
|
|
5760
5522
|
}
|
|
5761
|
-
const historyDir =
|
|
5762
|
-
const historyFile =
|
|
5523
|
+
const historyDir = resolve4(homedir2(), ".coherent");
|
|
5524
|
+
const historyFile = resolve4(historyDir, "history");
|
|
5763
5525
|
let history = [];
|
|
5764
5526
|
try {
|
|
5765
5527
|
mkdirSync5(historyDir, { recursive: true });
|
|
5766
|
-
if (
|
|
5767
|
-
history =
|
|
5528
|
+
if (existsSync8(historyFile)) {
|
|
5529
|
+
history = readFileSync5(historyFile, "utf-8").split("\n").filter(Boolean).slice(-200);
|
|
5768
5530
|
}
|
|
5769
5531
|
} catch (e) {
|
|
5770
5532
|
if (DEBUG3) console.error("Failed to load REPL history:", e);
|
|
@@ -5912,7 +5674,7 @@ async function interactiveChat(options, chatCommandFn) {
|
|
|
5912
5674
|
function saveHistory() {
|
|
5913
5675
|
try {
|
|
5914
5676
|
const lines = rl.history || [];
|
|
5915
|
-
|
|
5677
|
+
writeFileSync6(historyFile, lines.join("\n") + "\n");
|
|
5916
5678
|
} catch (e) {
|
|
5917
5679
|
if (DEBUG3) console.error("Failed to save REPL history:", e);
|
|
5918
5680
|
}
|
|
@@ -5943,7 +5705,7 @@ async function chatCommand(message, options) {
|
|
|
5943
5705
|
const projectRoot = project.root;
|
|
5944
5706
|
const configPath = project.configPath;
|
|
5945
5707
|
const migrationGuard = join6(projectRoot, ".coherent", "migration-in-progress");
|
|
5946
|
-
if (
|
|
5708
|
+
if (existsSync9(migrationGuard)) {
|
|
5947
5709
|
spinner.fail("Migration in progress");
|
|
5948
5710
|
console.error(chalk10.red("\n\u274C A migration is in progress. Run `coherent migrate --rollback` to undo first."));
|
|
5949
5711
|
bail("Migration in progress");
|
|
@@ -5993,7 +5755,7 @@ async function chatCommand(message, options) {
|
|
|
5993
5755
|
spinner.start(`Creating shared component: ${componentName}...`);
|
|
5994
5756
|
const { createAIProvider: createAIProvider2 } = await import("./ai-provider-CGSIYFZT.js");
|
|
5995
5757
|
const { generateSharedComponent: generateSharedComponent6 } = await import("@getcoherent/core");
|
|
5996
|
-
const { autoFixCode: autoFixCode2 } = await import("./quality-validator-
|
|
5758
|
+
const { autoFixCode: autoFixCode2 } = await import("./quality-validator-2KIT6QKA.js");
|
|
5997
5759
|
const { extractPropsInterface, extractDependencies } = await import("./component-extractor-VYJLT5NR.js");
|
|
5998
5760
|
const aiProvider = await createAIProvider2(provider ?? "auto");
|
|
5999
5761
|
const prompt = `Generate a React component called "${componentName}". Description: ${message}.
|
|
@@ -6061,7 +5823,7 @@ Return JSON: { "requests": [{ "type": "add-page", "changes": { "name": "${compon
|
|
|
6061
5823
|
}
|
|
6062
5824
|
if (/switch to light mode|default to light|make.*light.*(default|theme)|light theme/i.test(message)) {
|
|
6063
5825
|
spinner.start("Setting default theme to light...");
|
|
6064
|
-
const layoutPath =
|
|
5826
|
+
const layoutPath = resolve5(projectRoot, "app/layout.tsx");
|
|
6065
5827
|
try {
|
|
6066
5828
|
let layout = await readFile(layoutPath);
|
|
6067
5829
|
layout = layout.replace(/className="dark"/, "");
|
|
@@ -6100,8 +5862,8 @@ Return JSON: { "requests": [{ "type": "add-page", "changes": { "name": "${compon
|
|
|
6100
5862
|
spinner.start("Parsing your request...");
|
|
6101
5863
|
let manifest = await loadManifest7(project.root);
|
|
6102
5864
|
const validShared = manifest.shared.filter((s) => {
|
|
6103
|
-
const fp =
|
|
6104
|
-
return
|
|
5865
|
+
const fp = resolve5(project.root, s.file);
|
|
5866
|
+
return existsSync9(fp);
|
|
6105
5867
|
});
|
|
6106
5868
|
if (validShared.length !== manifest.shared.length) {
|
|
6107
5869
|
const cleaned = manifest.shared.length - validShared.length;
|
|
@@ -6321,9 +6083,9 @@ Return JSON: { "requests": [{ "type": "add-page", "changes": { "name": "${compon
|
|
|
6321
6083
|
if (manifest.shared.length > 0) {
|
|
6322
6084
|
for (const entry of manifest.shared) {
|
|
6323
6085
|
try {
|
|
6324
|
-
const sharedPath =
|
|
6325
|
-
if (
|
|
6326
|
-
const sharedCode =
|
|
6086
|
+
const sharedPath = resolve5(projectRoot, entry.file);
|
|
6087
|
+
if (existsSync9(sharedPath)) {
|
|
6088
|
+
const sharedCode = readFileSync6(sharedPath, "utf-8");
|
|
6327
6089
|
const sharedImports = sharedCode.matchAll(/@\/components\/ui\/([a-z0-9-]+)/g);
|
|
6328
6090
|
for (const m of sharedImports) {
|
|
6329
6091
|
if (m[1]) allNeededComponentIds.add(m[1]);
|
|
@@ -6344,7 +6106,7 @@ Return JSON: { "requests": [{ "type": "add-page", "changes": { "name": "${compon
|
|
|
6344
6106
|
for (const componentId of allNeededComponentIds) {
|
|
6345
6107
|
const isRegistered = !!cm.read(componentId);
|
|
6346
6108
|
const filePath = join6(projectRoot, "components", "ui", `${componentId}.tsx`);
|
|
6347
|
-
const fileExists =
|
|
6109
|
+
const fileExists = existsSync9(filePath);
|
|
6348
6110
|
if (DEBUG4) console.log(chalk10.gray(` Checking ${componentId}: registered=${isRegistered} file=${fileExists}`));
|
|
6349
6111
|
if (!isRegistered || !fileExists) {
|
|
6350
6112
|
missingComponents.push(componentId);
|
|
@@ -6493,9 +6255,9 @@ Return JSON: { "requests": [{ "type": "add-page", "changes": { "name": "${compon
|
|
|
6493
6255
|
const route = page.route || `/${page.id || "page"}`;
|
|
6494
6256
|
const pageFilePath = routeToFsPath(projectRoot, route, false);
|
|
6495
6257
|
let pageCode = "";
|
|
6496
|
-
if (
|
|
6258
|
+
if (existsSync9(pageFilePath)) {
|
|
6497
6259
|
try {
|
|
6498
|
-
pageCode =
|
|
6260
|
+
pageCode = readFileSync6(pageFilePath, "utf-8");
|
|
6499
6261
|
} catch {
|
|
6500
6262
|
}
|
|
6501
6263
|
}
|
|
@@ -6515,8 +6277,8 @@ Return JSON: { "requests": [{ "type": "add-page", "changes": { "name": "${compon
|
|
|
6515
6277
|
}
|
|
6516
6278
|
const missingRoutes = [...allLinkedRoutes].filter((route) => {
|
|
6517
6279
|
if (expandedExisting.has(route)) return false;
|
|
6518
|
-
if (
|
|
6519
|
-
if (
|
|
6280
|
+
if (existsSync9(routeToFsPath(projectRoot, route, false))) return false;
|
|
6281
|
+
if (existsSync9(routeToFsPath(projectRoot, route, true))) return false;
|
|
6520
6282
|
return true;
|
|
6521
6283
|
});
|
|
6522
6284
|
const SCAFFOLD_AI_LIMIT = 10;
|
|
@@ -6580,8 +6342,8 @@ Return JSON: { "requests": [{ "type": "add-page", "changes": { "name": "${compon
|
|
|
6580
6342
|
const isAuth = isAuthRoute(linkedRoute);
|
|
6581
6343
|
const filePath = routeToFsPath(projectRoot, linkedRoute, isAuth);
|
|
6582
6344
|
if (isAuth) await ensureAuthRouteGroup(projectRoot);
|
|
6583
|
-
const dir =
|
|
6584
|
-
if (!
|
|
6345
|
+
const dir = resolve5(filePath, "..");
|
|
6346
|
+
if (!existsSync9(dir)) {
|
|
6585
6347
|
mkdirSync6(dir, { recursive: true });
|
|
6586
6348
|
}
|
|
6587
6349
|
const placeholderCode = `export default function ${pageName.replace(/\s/g, "")}Page() {
|
|
@@ -6614,7 +6376,7 @@ Return JSON: { "requests": [{ "type": "add-page", "changes": { "name": "${compon
|
|
|
6614
6376
|
for (const mod of result.modified) {
|
|
6615
6377
|
if (mod.startsWith("app/") && mod.endsWith("/page.tsx")) {
|
|
6616
6378
|
try {
|
|
6617
|
-
const code =
|
|
6379
|
+
const code = readFileSync6(resolve5(projectRoot, mod), "utf-8");
|
|
6618
6380
|
const issues = validatePageQuality(code, allRoutes).filter(
|
|
6619
6381
|
(i) => i.type === "BROKEN_INTERNAL_LINK"
|
|
6620
6382
|
);
|
|
@@ -6644,7 +6406,7 @@ Return JSON: { "requests": [{ "type": "add-page", "changes": { "name": "${compon
|
|
|
6644
6406
|
dsm.updateConfig(latestConfig);
|
|
6645
6407
|
if (DEBUG4) console.log(chalk10.dim(` [theme] Set defaultMode to "${targetMode}"`));
|
|
6646
6408
|
}
|
|
6647
|
-
const layoutPath =
|
|
6409
|
+
const layoutPath = resolve5(projectRoot, "app", "layout.tsx");
|
|
6648
6410
|
try {
|
|
6649
6411
|
let layoutCode = await readFile(layoutPath);
|
|
6650
6412
|
if (targetMode === "dark" && !layoutCode.includes('className="dark"')) {
|
|
@@ -6695,16 +6457,16 @@ Return JSON: { "requests": [{ "type": "add-page", "changes": { "name": "${compon
|
|
|
6695
6457
|
}
|
|
6696
6458
|
try {
|
|
6697
6459
|
const updatedHashes = { ...storedHashes };
|
|
6698
|
-
const sharedDir =
|
|
6699
|
-
const layoutFile =
|
|
6460
|
+
const sharedDir = resolve5(projectRoot, "components", "shared");
|
|
6461
|
+
const layoutFile = resolve5(projectRoot, "app", "layout.tsx");
|
|
6700
6462
|
const filesToHash = [layoutFile];
|
|
6701
|
-
if (
|
|
6463
|
+
if (existsSync9(sharedDir)) {
|
|
6702
6464
|
for (const f of readdirSync3(sharedDir)) {
|
|
6703
|
-
if (f.endsWith(".tsx")) filesToHash.push(
|
|
6465
|
+
if (f.endsWith(".tsx")) filesToHash.push(resolve5(sharedDir, f));
|
|
6704
6466
|
}
|
|
6705
6467
|
}
|
|
6706
6468
|
for (const filePath of filesToHash) {
|
|
6707
|
-
if (
|
|
6469
|
+
if (existsSync9(filePath)) {
|
|
6708
6470
|
const rel = relative2(projectRoot, filePath);
|
|
6709
6471
|
updatedHashes[rel] = await computeFileHash(filePath);
|
|
6710
6472
|
}
|
|
@@ -6718,9 +6480,9 @@ Return JSON: { "requests": [{ "type": "add-page", "changes": { "name": "${compon
|
|
|
6718
6480
|
let currentManifest = await loadManifest7(projectRoot);
|
|
6719
6481
|
let manifestChanged = false;
|
|
6720
6482
|
for (const entry of currentManifest.shared) {
|
|
6721
|
-
const fullPath =
|
|
6722
|
-
if (!
|
|
6723
|
-
const code =
|
|
6483
|
+
const fullPath = resolve5(projectRoot, entry.file);
|
|
6484
|
+
if (!existsSync9(fullPath)) continue;
|
|
6485
|
+
const code = readFileSync6(fullPath, "utf-8");
|
|
6724
6486
|
const props = extractPropsInterface(code);
|
|
6725
6487
|
const deps = extractDependencies(code);
|
|
6726
6488
|
if (props && props !== entry.propsInterface || deps.length !== (entry.dependencies?.length ?? 0)) {
|
|
@@ -6733,9 +6495,9 @@ Return JSON: { "requests": [{ "type": "add-page", "changes": { "name": "${compon
|
|
|
6733
6495
|
}
|
|
6734
6496
|
const pageFiles = Array.from(allModified).filter((f) => f.startsWith("app/") && f.endsWith("page.tsx"));
|
|
6735
6497
|
for (const pageFile of pageFiles) {
|
|
6736
|
-
const fullPath =
|
|
6737
|
-
if (!
|
|
6738
|
-
const pageCode =
|
|
6498
|
+
const fullPath = resolve5(projectRoot, pageFile);
|
|
6499
|
+
if (!existsSync9(fullPath)) continue;
|
|
6500
|
+
const pageCode = readFileSync6(fullPath, "utf-8");
|
|
6739
6501
|
for (const entry of currentManifest.shared) {
|
|
6740
6502
|
const isUsed = pageCode.includes(`from '@/components/shared/`) && (pageCode.includes(`{ ${entry.name} }`) || pageCode.includes(`{ ${entry.name},`));
|
|
6741
6503
|
if (isUsed && !entry.usedIn.includes(pageFile)) {
|
|
@@ -6782,7 +6544,7 @@ Return JSON: { "requests": [{ "type": "add-page", "changes": { "name": "${compon
|
|
|
6782
6544
|
console.log("");
|
|
6783
6545
|
}
|
|
6784
6546
|
if (uxRecommendations) {
|
|
6785
|
-
const recPath =
|
|
6547
|
+
const recPath = resolve5(projectRoot, "recommendations.md");
|
|
6786
6548
|
const section = `
|
|
6787
6549
|
|
|
6788
6550
|
---
|
|
@@ -6792,7 +6554,7 @@ Return JSON: { "requests": [{ "type": "add-page", "changes": { "name": "${compon
|
|
|
6792
6554
|
${uxRecommendations}
|
|
6793
6555
|
`;
|
|
6794
6556
|
try {
|
|
6795
|
-
if (!
|
|
6557
|
+
if (!existsSync9(recPath)) {
|
|
6796
6558
|
await writeFile(
|
|
6797
6559
|
recPath,
|
|
6798
6560
|
"# UX/UI Recommendations\n\nRecommendations are added here when you use `coherent chat` and the AI suggests improvements.\n"
|
|
@@ -6866,8 +6628,8 @@ ${uxRecommendations}
|
|
|
6866
6628
|
import chalk11 from "chalk";
|
|
6867
6629
|
import ora3 from "ora";
|
|
6868
6630
|
import { spawn } from "child_process";
|
|
6869
|
-
import { existsSync as
|
|
6870
|
-
import { resolve as
|
|
6631
|
+
import { existsSync as existsSync12, rmSync as rmSync3, readFileSync as readFileSync9, writeFileSync as writeFileSync8, readdirSync as readdirSync5 } from "fs";
|
|
6632
|
+
import { resolve as resolve6, join as join9 } from "path";
|
|
6871
6633
|
import { readdir } from "fs/promises";
|
|
6872
6634
|
|
|
6873
6635
|
// src/utils/css-validator.ts
|
|
@@ -6922,12 +6684,12 @@ function validateV4GlobalsCss(css) {
|
|
|
6922
6684
|
import { DesignSystemManager as DesignSystemManager6, ComponentGenerator as ComponentGenerator2 } from "@getcoherent/core";
|
|
6923
6685
|
|
|
6924
6686
|
// src/utils/file-watcher.ts
|
|
6925
|
-
import { readFileSync as
|
|
6687
|
+
import { readFileSync as readFileSync8, writeFileSync as writeFileSync7, existsSync as existsSync11 } from "fs";
|
|
6926
6688
|
import { relative as relative4, join as join8 } from "path";
|
|
6927
6689
|
import { loadManifest as loadManifest8, saveManifest as saveManifest4 } from "@getcoherent/core";
|
|
6928
6690
|
|
|
6929
6691
|
// src/utils/component-integrity.ts
|
|
6930
|
-
import { existsSync as
|
|
6692
|
+
import { existsSync as existsSync10, readFileSync as readFileSync7, readdirSync as readdirSync4 } from "fs";
|
|
6931
6693
|
import { join as join7, relative as relative3 } from "path";
|
|
6932
6694
|
function extractExportedComponentNames(code) {
|
|
6933
6695
|
const names = [];
|
|
@@ -6961,13 +6723,13 @@ function arraysEqual(a, b) {
|
|
|
6961
6723
|
function findPagesImporting(projectRoot, componentName, componentFile) {
|
|
6962
6724
|
const results = [];
|
|
6963
6725
|
const appDir = join7(projectRoot, "app");
|
|
6964
|
-
if (!
|
|
6726
|
+
if (!existsSync10(appDir)) return results;
|
|
6965
6727
|
const pageFiles = collectFiles(appDir, (name) => name === "page.tsx" || name === "page.jsx");
|
|
6966
6728
|
const componentImportPath = componentFile.replace(/\.tsx$/, "").replace(/\.jsx$/, "");
|
|
6967
6729
|
for (const absPath of pageFiles) {
|
|
6968
6730
|
if (absPath.includes("design-system")) continue;
|
|
6969
6731
|
try {
|
|
6970
|
-
const code =
|
|
6732
|
+
const code = readFileSync7(absPath, "utf-8");
|
|
6971
6733
|
const hasNamedImport = new RegExp(`import\\s+\\{[^}]*\\b${componentName}\\b[^}]*\\}\\s+from\\s+['"]`).test(code);
|
|
6972
6734
|
const hasDefaultImport = new RegExp(`import\\s+${componentName}\\s+from\\s+['"]`).test(code);
|
|
6973
6735
|
const hasPathImport = code.includes(`@/${componentImportPath}`);
|
|
@@ -6982,7 +6744,7 @@ function findPagesImporting(projectRoot, componentName, componentFile) {
|
|
|
6982
6744
|
function isUsedInLayout(projectRoot, componentName) {
|
|
6983
6745
|
const appDir = join7(projectRoot, "app");
|
|
6984
6746
|
const layoutPaths = [join7(appDir, "layout.tsx")];
|
|
6985
|
-
if (
|
|
6747
|
+
if (existsSync10(appDir)) {
|
|
6986
6748
|
try {
|
|
6987
6749
|
for (const entry of readdirSync4(appDir, { withFileTypes: true })) {
|
|
6988
6750
|
if (entry.isDirectory() && entry.name.startsWith("(") && entry.name.endsWith(")")) {
|
|
@@ -6995,7 +6757,7 @@ function isUsedInLayout(projectRoot, componentName) {
|
|
|
6995
6757
|
const matched = [];
|
|
6996
6758
|
for (const lp of [...new Set(layoutPaths)]) {
|
|
6997
6759
|
try {
|
|
6998
|
-
if (
|
|
6760
|
+
if (readFileSync7(lp, "utf-8").includes(componentName)) {
|
|
6999
6761
|
matched.push(relative3(projectRoot, lp));
|
|
7000
6762
|
}
|
|
7001
6763
|
} catch {
|
|
@@ -7006,7 +6768,7 @@ function isUsedInLayout(projectRoot, componentName) {
|
|
|
7006
6768
|
function findUnregisteredComponents(projectRoot, manifest) {
|
|
7007
6769
|
const results = [];
|
|
7008
6770
|
const componentsDir = join7(projectRoot, "components");
|
|
7009
|
-
if (!
|
|
6771
|
+
if (!existsSync10(componentsDir)) return results;
|
|
7010
6772
|
const registeredFiles = new Set(manifest.shared.map((s) => s.file));
|
|
7011
6773
|
const registeredNames = new Set(manifest.shared.map((s) => s.name));
|
|
7012
6774
|
const files = collectFiles(
|
|
@@ -7018,7 +6780,7 @@ function findUnregisteredComponents(projectRoot, manifest) {
|
|
|
7018
6780
|
const relFile = relative3(projectRoot, absPath);
|
|
7019
6781
|
if (registeredFiles.has(relFile)) continue;
|
|
7020
6782
|
try {
|
|
7021
|
-
const code =
|
|
6783
|
+
const code = readFileSync7(absPath, "utf-8");
|
|
7022
6784
|
const exports = extractExportedComponentNames(code);
|
|
7023
6785
|
for (const name of exports) {
|
|
7024
6786
|
if (registeredNames.has(name)) continue;
|
|
@@ -7034,13 +6796,13 @@ function findUnregisteredComponents(projectRoot, manifest) {
|
|
|
7034
6796
|
function findInlineDuplicates(projectRoot, manifest) {
|
|
7035
6797
|
const results = [];
|
|
7036
6798
|
const appDir = join7(projectRoot, "app");
|
|
7037
|
-
if (!
|
|
6799
|
+
if (!existsSync10(appDir)) return results;
|
|
7038
6800
|
const pageFiles = collectFiles(appDir, (name) => name === "page.tsx" || name === "page.jsx");
|
|
7039
6801
|
for (const absPath of pageFiles) {
|
|
7040
6802
|
if (absPath.includes("design-system")) continue;
|
|
7041
6803
|
let code;
|
|
7042
6804
|
try {
|
|
7043
|
-
code =
|
|
6805
|
+
code = readFileSync7(absPath, "utf-8");
|
|
7044
6806
|
} catch {
|
|
7045
6807
|
continue;
|
|
7046
6808
|
}
|
|
@@ -7064,7 +6826,7 @@ function findInlineDuplicates(projectRoot, manifest) {
|
|
|
7064
6826
|
}
|
|
7065
6827
|
function findComponentFileByExportName(projectRoot, componentName) {
|
|
7066
6828
|
const componentsDir = join7(projectRoot, "components");
|
|
7067
|
-
if (!
|
|
6829
|
+
if (!existsSync10(componentsDir)) return null;
|
|
7068
6830
|
const files = collectFiles(
|
|
7069
6831
|
componentsDir,
|
|
7070
6832
|
(name) => (name.endsWith(".tsx") || name.endsWith(".jsx")) && !name.startsWith("."),
|
|
@@ -7072,7 +6834,7 @@ function findComponentFileByExportName(projectRoot, componentName) {
|
|
|
7072
6834
|
);
|
|
7073
6835
|
for (const absPath of files) {
|
|
7074
6836
|
try {
|
|
7075
|
-
const code =
|
|
6837
|
+
const code = readFileSync7(absPath, "utf-8");
|
|
7076
6838
|
const exports = extractExportedComponentNames(code);
|
|
7077
6839
|
if (exports.includes(componentName)) {
|
|
7078
6840
|
return relative3(projectRoot, absPath);
|
|
@@ -7086,7 +6848,7 @@ function removeOrphanedEntries(projectRoot, manifest) {
|
|
|
7086
6848
|
const removed = [];
|
|
7087
6849
|
const valid = manifest.shared.filter((entry) => {
|
|
7088
6850
|
const filePath = join7(projectRoot, entry.file);
|
|
7089
|
-
if (
|
|
6851
|
+
if (existsSync10(filePath)) return true;
|
|
7090
6852
|
removed.push({ id: entry.id, name: entry.name });
|
|
7091
6853
|
return false;
|
|
7092
6854
|
});
|
|
@@ -7105,7 +6867,7 @@ function reconcileComponents(projectRoot, manifest) {
|
|
|
7105
6867
|
const m = { ...manifest, shared: [...manifest.shared], nextId: manifest.nextId };
|
|
7106
6868
|
m.shared = m.shared.filter((entry) => {
|
|
7107
6869
|
const filePath = join7(projectRoot, entry.file);
|
|
7108
|
-
if (!
|
|
6870
|
+
if (!existsSync10(filePath)) {
|
|
7109
6871
|
const newPath = findComponentFileByExportName(projectRoot, entry.name);
|
|
7110
6872
|
if (newPath) {
|
|
7111
6873
|
result.updated.push({ id: entry.id, field: "file", from: entry.file, to: newPath });
|
|
@@ -7117,7 +6879,7 @@ function reconcileComponents(projectRoot, manifest) {
|
|
|
7117
6879
|
}
|
|
7118
6880
|
let code;
|
|
7119
6881
|
try {
|
|
7120
|
-
code =
|
|
6882
|
+
code = readFileSync7(join7(projectRoot, entry.file), "utf-8");
|
|
7121
6883
|
} catch {
|
|
7122
6884
|
return true;
|
|
7123
6885
|
}
|
|
@@ -7241,8 +7003,8 @@ function findInlineDuplicatesOfShared(content, manifest) {
|
|
|
7241
7003
|
function getWatcherConfig(projectRoot) {
|
|
7242
7004
|
try {
|
|
7243
7005
|
const pkgPath = join8(projectRoot, "package.json");
|
|
7244
|
-
if (!
|
|
7245
|
-
const pkg = JSON.parse(
|
|
7006
|
+
if (!existsSync11(pkgPath)) return defaultWatcherConfig();
|
|
7007
|
+
const pkg = JSON.parse(readFileSync8(pkgPath, "utf-8"));
|
|
7246
7008
|
const c = pkg?.coherent?.watcher ?? {};
|
|
7247
7009
|
return {
|
|
7248
7010
|
enabled: c.enabled !== false,
|
|
@@ -7270,7 +7032,7 @@ async function handleFileChange(projectRoot, filePath) {
|
|
|
7270
7032
|
if (relativePath.includes("node_modules") || relativePath.includes(".next")) return;
|
|
7271
7033
|
let content;
|
|
7272
7034
|
try {
|
|
7273
|
-
content =
|
|
7035
|
+
content = readFileSync8(filePath, "utf-8");
|
|
7274
7036
|
} catch {
|
|
7275
7037
|
return;
|
|
7276
7038
|
}
|
|
@@ -7289,7 +7051,7 @@ async function handleFileChange(projectRoot, filePath) {
|
|
|
7289
7051
|
if (config2.autoFix) {
|
|
7290
7052
|
const fixed = sanitizeMetadataStrings(ensureUseClientIfNeeded(content));
|
|
7291
7053
|
if (fixed !== content) {
|
|
7292
|
-
|
|
7054
|
+
writeFileSync7(filePath, fixed, "utf-8");
|
|
7293
7055
|
console.log(chalk30.cyan(` \u{1F527} Auto-fixed syntax in ${relativePath}`));
|
|
7294
7056
|
}
|
|
7295
7057
|
}
|
|
@@ -7343,7 +7105,7 @@ async function detectNewComponent(projectRoot, filePath) {
|
|
|
7343
7105
|
const manifest = await loadManifest8(projectRoot);
|
|
7344
7106
|
const alreadyRegistered = manifest.shared.some((s) => s.file === relativePath);
|
|
7345
7107
|
if (alreadyRegistered) return;
|
|
7346
|
-
const code =
|
|
7108
|
+
const code = readFileSync8(filePath, "utf-8");
|
|
7347
7109
|
const exports = extractExportedComponentNames(code);
|
|
7348
7110
|
if (exports.length > 0) {
|
|
7349
7111
|
const alreadyByName = exports.every((n) => manifest.shared.some((s) => s.name === n));
|
|
@@ -7383,7 +7145,7 @@ function startFileWatcher(projectRoot) {
|
|
|
7383
7145
|
watcher.on("unlink", (fp) => handleFileDelete(projectRoot, fp));
|
|
7384
7146
|
});
|
|
7385
7147
|
const manifestPath = join8(projectRoot, "coherent.components.json");
|
|
7386
|
-
if (
|
|
7148
|
+
if (existsSync11(manifestPath)) {
|
|
7387
7149
|
import("chokidar").then((chokidar) => {
|
|
7388
7150
|
manifestWatcher = chokidar.default.watch(manifestPath, { ignoreInitial: true });
|
|
7389
7151
|
manifestWatcher.on("change", () => handleManifestChange(projectRoot));
|
|
@@ -7397,7 +7159,7 @@ function startFileWatcher(projectRoot) {
|
|
|
7397
7159
|
|
|
7398
7160
|
// src/commands/preview.ts
|
|
7399
7161
|
function getPackageManager(projectRoot) {
|
|
7400
|
-
const hasPnpm =
|
|
7162
|
+
const hasPnpm = existsSync12(resolve6(projectRoot, "pnpm-lock.yaml"));
|
|
7401
7163
|
return hasPnpm ? "pnpm" : "npm";
|
|
7402
7164
|
}
|
|
7403
7165
|
function runInstall(projectRoot) {
|
|
@@ -7419,23 +7181,23 @@ function runInstall(projectRoot) {
|
|
|
7419
7181
|
});
|
|
7420
7182
|
}
|
|
7421
7183
|
function checkProjectInitialized(projectRoot) {
|
|
7422
|
-
const configPath =
|
|
7423
|
-
const packageJsonPath =
|
|
7424
|
-
if (!
|
|
7184
|
+
const configPath = resolve6(projectRoot, "design-system.config.ts");
|
|
7185
|
+
const packageJsonPath = resolve6(projectRoot, "package.json");
|
|
7186
|
+
if (!existsSync12(configPath)) {
|
|
7425
7187
|
return false;
|
|
7426
7188
|
}
|
|
7427
|
-
if (!
|
|
7189
|
+
if (!existsSync12(packageJsonPath)) {
|
|
7428
7190
|
return false;
|
|
7429
7191
|
}
|
|
7430
7192
|
return true;
|
|
7431
7193
|
}
|
|
7432
7194
|
function checkDependenciesInstalled(projectRoot) {
|
|
7433
|
-
const nodeModulesPath =
|
|
7434
|
-
return
|
|
7195
|
+
const nodeModulesPath = resolve6(projectRoot, "node_modules");
|
|
7196
|
+
return existsSync12(nodeModulesPath);
|
|
7435
7197
|
}
|
|
7436
7198
|
function clearStaleCache(projectRoot) {
|
|
7437
7199
|
const nextDir = join9(projectRoot, ".next");
|
|
7438
|
-
if (
|
|
7200
|
+
if (existsSync12(nextDir)) {
|
|
7439
7201
|
rmSync3(nextDir, { recursive: true, force: true });
|
|
7440
7202
|
console.log(chalk11.dim(" \u2714 Cleared stale build cache"));
|
|
7441
7203
|
}
|
|
@@ -7451,7 +7213,7 @@ async function preflightDependencyCheck(projectRoot) {
|
|
|
7451
7213
|
}
|
|
7452
7214
|
async function listPageFiles(appDir) {
|
|
7453
7215
|
const out = [];
|
|
7454
|
-
if (!
|
|
7216
|
+
if (!existsSync12(appDir)) return out;
|
|
7455
7217
|
async function walk(dir) {
|
|
7456
7218
|
const entries = await readdir(dir, { withFileTypes: true });
|
|
7457
7219
|
for (const e of entries) {
|
|
@@ -7467,10 +7229,10 @@ async function validateSyntax(projectRoot) {
|
|
|
7467
7229
|
const appDir = join9(projectRoot, "app");
|
|
7468
7230
|
const pages = await listPageFiles(appDir);
|
|
7469
7231
|
for (const file of pages) {
|
|
7470
|
-
const content =
|
|
7232
|
+
const content = readFileSync9(file, "utf-8");
|
|
7471
7233
|
const fixed = fixUnescapedLtInJsx(sanitizeMetadataStrings(ensureUseClientIfNeeded(content)));
|
|
7472
7234
|
if (fixed !== content) {
|
|
7473
|
-
|
|
7235
|
+
writeFileSync8(file, fixed, "utf-8");
|
|
7474
7236
|
console.log(chalk11.dim(` \u2714 Auto-fixed syntax: ${file.replace(projectRoot, ".").replace(/^\.[/\\]/, "")}`));
|
|
7475
7237
|
}
|
|
7476
7238
|
}
|
|
@@ -7478,16 +7240,16 @@ async function validateSyntax(projectRoot) {
|
|
|
7478
7240
|
async function fixMissingComponentExports(projectRoot) {
|
|
7479
7241
|
const appDir = join9(projectRoot, "app");
|
|
7480
7242
|
const uiDir = join9(projectRoot, "components", "ui");
|
|
7481
|
-
if (!
|
|
7243
|
+
if (!existsSync12(appDir) || !existsSync12(uiDir)) return;
|
|
7482
7244
|
const pages = await listPageFiles(appDir);
|
|
7483
7245
|
const sharedDir = join9(projectRoot, "components", "shared");
|
|
7484
|
-
if (
|
|
7246
|
+
if (existsSync12(sharedDir)) {
|
|
7485
7247
|
const sharedFiles = readdirSync5(sharedDir).filter((f) => f.endsWith(".tsx") || f.endsWith(".ts")).map((f) => join9(sharedDir, f));
|
|
7486
7248
|
pages.push(...sharedFiles);
|
|
7487
7249
|
}
|
|
7488
7250
|
const neededExports = /* @__PURE__ */ new Map();
|
|
7489
7251
|
for (const file of pages) {
|
|
7490
|
-
const content =
|
|
7252
|
+
const content = readFileSync9(file, "utf-8");
|
|
7491
7253
|
const importRe = /import\s*\{([^}]+)\}\s*from\s*['"]@\/components\/ui\/([^'"]+)['"]/g;
|
|
7492
7254
|
let m;
|
|
7493
7255
|
while ((m = importRe.exec(content)) !== null) {
|
|
@@ -7508,7 +7270,7 @@ async function fixMissingComponentExports(projectRoot) {
|
|
|
7508
7270
|
const provider = getComponentProvider();
|
|
7509
7271
|
for (const [componentId, needed] of neededExports) {
|
|
7510
7272
|
const componentFile = join9(uiDir, `${componentId}.tsx`);
|
|
7511
|
-
if (!
|
|
7273
|
+
if (!existsSync12(componentFile)) {
|
|
7512
7274
|
if (provider.has(componentId)) {
|
|
7513
7275
|
try {
|
|
7514
7276
|
const result = await provider.installComponent(componentId, projectRoot);
|
|
@@ -7524,14 +7286,14 @@ async function fixMissingComponentExports(projectRoot) {
|
|
|
7524
7286
|
const { mkdirSync: mkdirSync10 } = await import("fs");
|
|
7525
7287
|
mkdirSync10(uiDir, { recursive: true });
|
|
7526
7288
|
const newContent = await generator.generate(def);
|
|
7527
|
-
|
|
7289
|
+
writeFileSync8(componentFile, newContent, "utf-8");
|
|
7528
7290
|
console.log(chalk11.dim(` \u2714 Created missing ${componentId}.tsx`));
|
|
7529
7291
|
} catch {
|
|
7530
7292
|
}
|
|
7531
7293
|
}
|
|
7532
7294
|
continue;
|
|
7533
7295
|
}
|
|
7534
|
-
const content =
|
|
7296
|
+
const content = readFileSync9(componentFile, "utf-8");
|
|
7535
7297
|
const exportRe = /export\s+(?:const|function|class)\s+(\w+)|export\s*\{([^}]+)\}/g;
|
|
7536
7298
|
const existingExports = /* @__PURE__ */ new Set();
|
|
7537
7299
|
let em;
|
|
@@ -7557,7 +7319,7 @@ async function fixMissingComponentExports(projectRoot) {
|
|
|
7557
7319
|
if (!def) continue;
|
|
7558
7320
|
try {
|
|
7559
7321
|
const newContent = await generator.generate(def);
|
|
7560
|
-
|
|
7322
|
+
writeFileSync8(componentFile, newContent, "utf-8");
|
|
7561
7323
|
console.log(chalk11.dim(` \u2714 Regenerated ${componentId}.tsx (added missing exports: ${missing.join(", ")})`));
|
|
7562
7324
|
} catch {
|
|
7563
7325
|
}
|
|
@@ -7565,7 +7327,7 @@ async function fixMissingComponentExports(projectRoot) {
|
|
|
7565
7327
|
}
|
|
7566
7328
|
const neededSharedExports = /* @__PURE__ */ new Map();
|
|
7567
7329
|
for (const file of pages) {
|
|
7568
|
-
const content =
|
|
7330
|
+
const content = readFileSync9(file, "utf-8");
|
|
7569
7331
|
const sharedImportRe = /import\s*\{([^}]+)\}\s*from\s*['"]@\/components\/shared\/([^'"]+)['"]/g;
|
|
7570
7332
|
let sm;
|
|
7571
7333
|
while ((sm = sharedImportRe.exec(content)) !== null) {
|
|
@@ -7577,8 +7339,8 @@ async function fixMissingComponentExports(projectRoot) {
|
|
|
7577
7339
|
}
|
|
7578
7340
|
for (const [componentId, needed] of neededSharedExports) {
|
|
7579
7341
|
const componentFile = join9(sharedDir, `${componentId}.tsx`);
|
|
7580
|
-
if (!
|
|
7581
|
-
let content =
|
|
7342
|
+
if (!existsSync12(componentFile)) continue;
|
|
7343
|
+
let content = readFileSync9(componentFile, "utf-8");
|
|
7582
7344
|
const exportRe = /export\s+(?:const|function|class)\s+(\w+)|export\s*\{([^}]+)\}/g;
|
|
7583
7345
|
const existingExports = /* @__PURE__ */ new Set();
|
|
7584
7346
|
let em;
|
|
@@ -7594,14 +7356,14 @@ async function fixMissingComponentExports(projectRoot) {
|
|
|
7594
7356
|
const defaultExportMatch = content.match(/export\s+default\s+function\s+(\w+)/);
|
|
7595
7357
|
if (defaultExportMatch && missing.includes(defaultExportMatch[1])) {
|
|
7596
7358
|
content = content.replace(/export\s+default\s+function\s+(\w+)/, "export function $1");
|
|
7597
|
-
|
|
7359
|
+
writeFileSync8(componentFile, content, "utf-8");
|
|
7598
7360
|
console.log(chalk11.dim(` \u2714 Fixed export in ${componentId}.tsx (default \u2192 named)`));
|
|
7599
7361
|
}
|
|
7600
7362
|
}
|
|
7601
7363
|
}
|
|
7602
7364
|
async function backfillPageAnalysis(projectRoot) {
|
|
7603
7365
|
const configPath = join9(projectRoot, "design-system.config.ts");
|
|
7604
|
-
if (!
|
|
7366
|
+
if (!existsSync12(configPath)) return;
|
|
7605
7367
|
try {
|
|
7606
7368
|
const mgr = new DesignSystemManager6(configPath);
|
|
7607
7369
|
const config2 = mgr.getConfig();
|
|
@@ -7618,8 +7380,8 @@ async function backfillPageAnalysis(projectRoot) {
|
|
|
7618
7380
|
} else {
|
|
7619
7381
|
filePath = join9(projectRoot, "app", route.slice(1), "page.tsx");
|
|
7620
7382
|
}
|
|
7621
|
-
if (!
|
|
7622
|
-
const code =
|
|
7383
|
+
if (!existsSync12(filePath)) continue;
|
|
7384
|
+
const code = readFileSync9(filePath, "utf-8");
|
|
7623
7385
|
if (code.length < 50) continue;
|
|
7624
7386
|
page.pageAnalysis = analyzePageCode(code);
|
|
7625
7387
|
changed = true;
|
|
@@ -7769,12 +7531,12 @@ async function openBrowser(url) {
|
|
|
7769
7531
|
}
|
|
7770
7532
|
}
|
|
7771
7533
|
function startDevServer(projectRoot) {
|
|
7772
|
-
const packageJsonPath =
|
|
7773
|
-
if (!
|
|
7534
|
+
const packageJsonPath = resolve6(projectRoot, "package.json");
|
|
7535
|
+
if (!existsSync12(packageJsonPath)) {
|
|
7774
7536
|
throw new Error('package.json not found. Run "coherent init" first.');
|
|
7775
7537
|
}
|
|
7776
|
-
const hasPnpm =
|
|
7777
|
-
const hasNpm =
|
|
7538
|
+
const hasPnpm = existsSync12(resolve6(projectRoot, "pnpm-lock.yaml"));
|
|
7539
|
+
const hasNpm = existsSync12(resolve6(projectRoot, "package-lock.json"));
|
|
7778
7540
|
const command = hasPnpm ? "pnpm" : hasNpm ? "npm" : "npx";
|
|
7779
7541
|
const args = hasPnpm ? ["dev", "--turbo"] : hasNpm ? ["run", "dev", "--", "--turbo"] : ["next", "dev", "--turbo"];
|
|
7780
7542
|
const child = spawn(command, args, {
|
|
@@ -7821,7 +7583,7 @@ async function previewCommand() {
|
|
|
7821
7583
|
if (needsGlobalsFix(projectRoot)) {
|
|
7822
7584
|
spinner.text = "Fixing globals.css...";
|
|
7823
7585
|
try {
|
|
7824
|
-
const dsm = new DesignSystemManager6(
|
|
7586
|
+
const dsm = new DesignSystemManager6(resolve6(projectRoot, "design-system.config.ts"));
|
|
7825
7587
|
await dsm.load();
|
|
7826
7588
|
const config2 = dsm.getConfig();
|
|
7827
7589
|
fixGlobalsCss(projectRoot, config2);
|
|
@@ -7831,9 +7593,9 @@ async function previewCommand() {
|
|
|
7831
7593
|
}
|
|
7832
7594
|
}
|
|
7833
7595
|
if (isTailwindV4(projectRoot)) {
|
|
7834
|
-
const globalsPath =
|
|
7835
|
-
if (
|
|
7836
|
-
const globalsContent =
|
|
7596
|
+
const globalsPath = resolve6(projectRoot, "app", "globals.css");
|
|
7597
|
+
if (existsSync12(globalsPath)) {
|
|
7598
|
+
const globalsContent = readFileSync9(globalsPath, "utf-8");
|
|
7837
7599
|
const cssIssues = validateV4GlobalsCss(globalsContent);
|
|
7838
7600
|
if (cssIssues.length > 0) {
|
|
7839
7601
|
console.log(chalk11.yellow("\n\u26A0\uFE0F globals.css validation warnings:"));
|
|
@@ -7874,8 +7636,8 @@ async function previewCommand() {
|
|
|
7874
7636
|
import chalk12 from "chalk";
|
|
7875
7637
|
import ora4 from "ora";
|
|
7876
7638
|
import { spawn as spawn2 } from "child_process";
|
|
7877
|
-
import { existsSync as
|
|
7878
|
-
import { resolve as
|
|
7639
|
+
import { existsSync as existsSync13, rmSync as rmSync4, readdirSync as readdirSync6 } from "fs";
|
|
7640
|
+
import { resolve as resolve7, join as join10, dirname as dirname4 } from "path";
|
|
7879
7641
|
import { readdir as readdir2, readFile as readFile3, writeFile as writeFile3, mkdir as mkdir2, copyFile } from "fs/promises";
|
|
7880
7642
|
var COPY_EXCLUDE = /* @__PURE__ */ new Set([
|
|
7881
7643
|
"node_modules",
|
|
@@ -7909,17 +7671,17 @@ async function copyDir(src, dest) {
|
|
|
7909
7671
|
}
|
|
7910
7672
|
}
|
|
7911
7673
|
function checkProjectInitialized2(projectRoot) {
|
|
7912
|
-
return
|
|
7674
|
+
return existsSync13(resolve7(projectRoot, "design-system.config.ts")) && existsSync13(resolve7(projectRoot, "package.json"));
|
|
7913
7675
|
}
|
|
7914
7676
|
function getPackageManager2(projectRoot) {
|
|
7915
|
-
if (
|
|
7916
|
-
if (
|
|
7677
|
+
if (existsSync13(resolve7(projectRoot, "pnpm-lock.yaml"))) return "pnpm";
|
|
7678
|
+
if (existsSync13(resolve7(projectRoot, "package-lock.json"))) return "npm";
|
|
7917
7679
|
return "npx";
|
|
7918
7680
|
}
|
|
7919
7681
|
async function patchNextConfigForExport(outRoot) {
|
|
7920
7682
|
for (const name of ["next.config.ts", "next.config.mjs", "next.config.js"]) {
|
|
7921
7683
|
const p = join10(outRoot, name);
|
|
7922
|
-
if (!
|
|
7684
|
+
if (!existsSync13(p)) continue;
|
|
7923
7685
|
let content = await readFile3(p, "utf-8");
|
|
7924
7686
|
if (content.includes("ignoreDuringBuilds")) return;
|
|
7925
7687
|
content = content.replace(
|
|
@@ -7934,9 +7696,9 @@ async function buildProduction(projectRoot) {
|
|
|
7934
7696
|
const pm = getPackageManager2(projectRoot);
|
|
7935
7697
|
const command = pm === "pnpm" ? "pnpm" : pm === "npm" ? "npm" : "npx";
|
|
7936
7698
|
const args = pm === "npx" ? ["next", "build"] : ["run", "build"];
|
|
7937
|
-
return new Promise((
|
|
7699
|
+
return new Promise((resolve12, reject) => {
|
|
7938
7700
|
const child = spawn2(command, args, { cwd: projectRoot, stdio: "inherit", shell: true });
|
|
7939
|
-
child.on("exit", (code) => code === 0 ?
|
|
7701
|
+
child.on("exit", (code) => code === 0 ? resolve12() : reject(new Error(`Build failed with exit code ${code}`)));
|
|
7940
7702
|
child.on("error", (error) => reject(new Error(`Failed to start build: ${error.message}`)));
|
|
7941
7703
|
});
|
|
7942
7704
|
}
|
|
@@ -7961,7 +7723,7 @@ EXPOSE 3000
|
|
|
7961
7723
|
`;
|
|
7962
7724
|
async function ensureReadmeDeploySection(outRoot) {
|
|
7963
7725
|
const readmePath = join10(outRoot, "README.md");
|
|
7964
|
-
if (!
|
|
7726
|
+
if (!existsSync13(readmePath)) return;
|
|
7965
7727
|
try {
|
|
7966
7728
|
let content = await readFile3(readmePath, "utf-8");
|
|
7967
7729
|
if (/##\s+Deploy\b/m.test(content)) return;
|
|
@@ -7986,14 +7748,14 @@ async function countPages(outRoot) {
|
|
|
7986
7748
|
}
|
|
7987
7749
|
}
|
|
7988
7750
|
const appDir = join10(outRoot, "app");
|
|
7989
|
-
if (
|
|
7751
|
+
if (existsSync13(appDir)) await walk(appDir);
|
|
7990
7752
|
return n;
|
|
7991
7753
|
}
|
|
7992
7754
|
function countComponents(outRoot) {
|
|
7993
7755
|
let n = 0;
|
|
7994
7756
|
for (const sub of ["ui", "shared"]) {
|
|
7995
7757
|
const dir = join10(outRoot, "components", sub);
|
|
7996
|
-
if (!
|
|
7758
|
+
if (!existsSync13(dir)) continue;
|
|
7997
7759
|
try {
|
|
7998
7760
|
n += readdirSync6(dir).filter((f) => f.endsWith(".tsx") || f.endsWith(".jsx")).length;
|
|
7999
7761
|
} catch {
|
|
@@ -8004,7 +7766,7 @@ function countComponents(outRoot) {
|
|
|
8004
7766
|
var IMPORT_FROM_REGEX = /from\s+['"]([^'"]+)['"]/g;
|
|
8005
7767
|
async function collectImportedPackages(dir, extensions) {
|
|
8006
7768
|
const packages = /* @__PURE__ */ new Set();
|
|
8007
|
-
if (!
|
|
7769
|
+
if (!existsSync13(dir)) return packages;
|
|
8008
7770
|
async function walk(d) {
|
|
8009
7771
|
const entries = await readdir2(d, { withFileTypes: true });
|
|
8010
7772
|
for (const e of entries) {
|
|
@@ -8032,7 +7794,7 @@ async function collectImportedPackages(dir, extensions) {
|
|
|
8032
7794
|
}
|
|
8033
7795
|
async function findMissingDepsInExport(outRoot) {
|
|
8034
7796
|
const pkgPath = join10(outRoot, "package.json");
|
|
8035
|
-
if (!
|
|
7797
|
+
if (!existsSync13(pkgPath)) return [];
|
|
8036
7798
|
let pkg;
|
|
8037
7799
|
try {
|
|
8038
7800
|
pkg = JSON.parse(await readFile3(pkgPath, "utf-8"));
|
|
@@ -8053,32 +7815,32 @@ async function stripCoherentArtifacts(outputDir) {
|
|
|
8053
7815
|
const removed = [];
|
|
8054
7816
|
for (const p of ["app/design-system", "app/api/design-system"]) {
|
|
8055
7817
|
const full = join10(outputDir, p);
|
|
8056
|
-
if (
|
|
7818
|
+
if (existsSync13(full)) {
|
|
8057
7819
|
rmSync4(full, { recursive: true, force: true });
|
|
8058
7820
|
removed.push(p);
|
|
8059
7821
|
}
|
|
8060
7822
|
}
|
|
8061
7823
|
const appNavPath = join10(outputDir, "app", "AppNav.tsx");
|
|
8062
|
-
if (
|
|
7824
|
+
if (existsSync13(appNavPath)) {
|
|
8063
7825
|
rmSync4(appNavPath, { force: true });
|
|
8064
7826
|
removed.push("app/AppNav.tsx");
|
|
8065
7827
|
}
|
|
8066
7828
|
const layoutPath = join10(outputDir, "app", "layout.tsx");
|
|
8067
|
-
if (
|
|
7829
|
+
if (existsSync13(layoutPath)) {
|
|
8068
7830
|
let layout = await readFile3(layoutPath, "utf-8");
|
|
8069
7831
|
layout = layout.replace(/import\s*\{?\s*AppNav\s*\}?\s*from\s*['"][^'"]+['"]\s*\n?/g, "");
|
|
8070
7832
|
layout = layout.replace(/\s*<AppNav\s*\/?\s*>\s*/g, "\n");
|
|
8071
7833
|
await writeFile3(layoutPath, layout, "utf-8");
|
|
8072
7834
|
}
|
|
8073
7835
|
const sharedHeaderPath = join10(outputDir, "components", "shared", "header.tsx");
|
|
8074
|
-
if (
|
|
7836
|
+
if (existsSync13(sharedHeaderPath)) {
|
|
8075
7837
|
let header = await readFile3(sharedHeaderPath, "utf-8");
|
|
8076
7838
|
header = header.replace(/<Link\s[^>]*href="\/design-system"[^>]*>[\s\S]*?<\/Link>/g, "");
|
|
8077
7839
|
header = header.replace(/\n\s*<>\s*\n/, "\n");
|
|
8078
7840
|
header = header.replace(/\n\s*<\/>\s*\n/, "\n");
|
|
8079
7841
|
await writeFile3(sharedHeaderPath, header, "utf-8");
|
|
8080
7842
|
}
|
|
8081
|
-
if (
|
|
7843
|
+
if (existsSync13(layoutPath)) {
|
|
8082
7844
|
let rootLayout = await readFile3(layoutPath, "utf-8");
|
|
8083
7845
|
const before = rootLayout;
|
|
8084
7846
|
rootLayout = rootLayout.replace(/<Link\s[^>]*href="\/design-system"[^>]*>[\s\S]*?<\/Link>/g, "");
|
|
@@ -8087,7 +7849,7 @@ async function stripCoherentArtifacts(outputDir) {
|
|
|
8087
7849
|
}
|
|
8088
7850
|
}
|
|
8089
7851
|
const guardPath2 = join10(outputDir, "app", "ShowWhenNotAuthRoute.tsx");
|
|
8090
|
-
if (
|
|
7852
|
+
if (existsSync13(guardPath2)) {
|
|
8091
7853
|
let guard = await readFile3(guardPath2, "utf-8");
|
|
8092
7854
|
guard = guard.replace(/['"],?\s*'\/design-system['"],?\s*/g, "");
|
|
8093
7855
|
const pathsMatch = guard.match(/HIDDEN_PATHS\s*=\s*\[([^\]]*)\]/);
|
|
@@ -8095,7 +7857,7 @@ async function stripCoherentArtifacts(outputDir) {
|
|
|
8095
7857
|
if (remaining.length === 0) {
|
|
8096
7858
|
rmSync4(guardPath2, { force: true });
|
|
8097
7859
|
removed.push("app/ShowWhenNotAuthRoute.tsx");
|
|
8098
|
-
if (
|
|
7860
|
+
if (existsSync13(layoutPath)) {
|
|
8099
7861
|
let layout = await readFile3(layoutPath, "utf-8");
|
|
8100
7862
|
layout = layout.replace(/import\s+\w+\s+from\s*['"]\.\/ShowWhenNotAuthRoute['"]\s*\n?/g, "");
|
|
8101
7863
|
layout = layout.replace(/\s*<ShowWhenNotAuthRoute>\s*\n?/g, "\n");
|
|
@@ -8116,14 +7878,14 @@ async function stripCoherentArtifacts(outputDir) {
|
|
|
8116
7878
|
"recommendations.md"
|
|
8117
7879
|
]) {
|
|
8118
7880
|
const full = join10(outputDir, name);
|
|
8119
|
-
if (
|
|
7881
|
+
if (existsSync13(full)) {
|
|
8120
7882
|
rmSync4(full, { force: true });
|
|
8121
7883
|
removed.push(name);
|
|
8122
7884
|
}
|
|
8123
7885
|
}
|
|
8124
7886
|
for (const dir of [".claude", ".coherent"]) {
|
|
8125
7887
|
const full = join10(outputDir, dir);
|
|
8126
|
-
if (
|
|
7888
|
+
if (existsSync13(full)) {
|
|
8127
7889
|
rmSync4(full, { recursive: true, force: true });
|
|
8128
7890
|
removed.push(dir + "/");
|
|
8129
7891
|
}
|
|
@@ -8131,7 +7893,7 @@ async function stripCoherentArtifacts(outputDir) {
|
|
|
8131
7893
|
return removed;
|
|
8132
7894
|
}
|
|
8133
7895
|
async function exportCommand(options = {}) {
|
|
8134
|
-
const outputDir =
|
|
7896
|
+
const outputDir = resolve7(process.cwd(), options.output ?? "./export");
|
|
8135
7897
|
const doBuild = options.build !== false;
|
|
8136
7898
|
const keepDs = options.keepDs === true;
|
|
8137
7899
|
const spinner = ora4("Preparing export...").start();
|
|
@@ -8147,7 +7909,7 @@ async function exportCommand(options = {}) {
|
|
|
8147
7909
|
process.exit(1);
|
|
8148
7910
|
}
|
|
8149
7911
|
spinner.text = "Copying project...";
|
|
8150
|
-
if (
|
|
7912
|
+
if (existsSync13(outputDir)) rmSync4(outputDir, { recursive: true, force: true });
|
|
8151
7913
|
await copyDir(projectRoot, outputDir);
|
|
8152
7914
|
spinner.succeed("Project copied");
|
|
8153
7915
|
if (!keepDs) {
|
|
@@ -8209,7 +7971,7 @@ async function exportCommand(options = {}) {
|
|
|
8209
7971
|
|
|
8210
7972
|
// src/commands/status.ts
|
|
8211
7973
|
import chalk13 from "chalk";
|
|
8212
|
-
import { basename } from "path";
|
|
7974
|
+
import { basename as basename2 } from "path";
|
|
8213
7975
|
import { DesignSystemManager as DesignSystemManager7 } from "@getcoherent/core";
|
|
8214
7976
|
function countTokens(tokens) {
|
|
8215
7977
|
let count = 0;
|
|
@@ -8239,7 +8001,7 @@ async function statusCommand() {
|
|
|
8239
8001
|
}
|
|
8240
8002
|
console.log(chalk13.cyan("\n\u2728 Current Project\n"));
|
|
8241
8003
|
console.log(chalk13.gray("\u{1F4C1} Location: ") + chalk13.white(project.root));
|
|
8242
|
-
console.log(chalk13.gray("\u{1F4C4} Config: ") + chalk13.white(
|
|
8004
|
+
console.log(chalk13.gray("\u{1F4C4} Config: ") + chalk13.white(basename2(project.configPath)));
|
|
8243
8005
|
console.log("");
|
|
8244
8006
|
try {
|
|
8245
8007
|
const manager = new DesignSystemManager7(project.configPath);
|
|
@@ -8322,8 +8084,8 @@ async function regenerateDocsCommand() {
|
|
|
8322
8084
|
|
|
8323
8085
|
// src/commands/fix.ts
|
|
8324
8086
|
import chalk15 from "chalk";
|
|
8325
|
-
import { readdirSync as readdirSync7, readFileSync as
|
|
8326
|
-
import { resolve as
|
|
8087
|
+
import { readdirSync as readdirSync7, readFileSync as readFileSync11, existsSync as existsSync15, rmSync as rmSync5, mkdirSync as mkdirSync7 } from "fs";
|
|
8088
|
+
import { resolve as resolve8, join as join12, relative as relative5, basename as basename3 } from "path";
|
|
8327
8089
|
import {
|
|
8328
8090
|
DesignSystemManager as DesignSystemManager9,
|
|
8329
8091
|
ComponentManager as ComponentManager5,
|
|
@@ -8335,14 +8097,14 @@ import {
|
|
|
8335
8097
|
|
|
8336
8098
|
// src/commands/fix-validation.ts
|
|
8337
8099
|
import { createRequire } from "module";
|
|
8338
|
-
import { existsSync as
|
|
8100
|
+
import { existsSync as existsSync14, readFileSync as readFileSync10, writeFileSync as writeFileSync9 } from "fs";
|
|
8339
8101
|
import { join as join11 } from "path";
|
|
8340
8102
|
var cachedTs = null;
|
|
8341
8103
|
var cachedProjectRoot = null;
|
|
8342
8104
|
function isValidTsx(code, projectRoot, ext = ".tsx") {
|
|
8343
8105
|
if (ext !== ".tsx" && ext !== ".ts") return true;
|
|
8344
8106
|
const pkgJson = join11(projectRoot, "package.json");
|
|
8345
|
-
if (!
|
|
8107
|
+
if (!existsSync14(pkgJson)) return true;
|
|
8346
8108
|
try {
|
|
8347
8109
|
if (!cachedTs || cachedProjectRoot !== projectRoot) {
|
|
8348
8110
|
const req = createRequire(pkgJson);
|
|
@@ -8365,15 +8127,15 @@ function isValidTsx(code, projectRoot, ext = ".tsx") {
|
|
|
8365
8127
|
function safeWrite(filePath, newContent, projectRoot, backups) {
|
|
8366
8128
|
if (!backups.has(filePath)) {
|
|
8367
8129
|
try {
|
|
8368
|
-
backups.set(filePath,
|
|
8130
|
+
backups.set(filePath, readFileSync10(filePath, "utf-8"));
|
|
8369
8131
|
} catch {
|
|
8370
8132
|
}
|
|
8371
8133
|
}
|
|
8372
8134
|
const ext = filePath.slice(filePath.lastIndexOf("."));
|
|
8373
|
-
|
|
8135
|
+
writeFileSync9(filePath, newContent, "utf-8");
|
|
8374
8136
|
if (!isValidTsx(newContent, projectRoot, ext)) {
|
|
8375
8137
|
const original = backups.get(filePath);
|
|
8376
|
-
if (original)
|
|
8138
|
+
if (original) writeFileSync9(filePath, original, "utf-8");
|
|
8377
8139
|
return { ok: false };
|
|
8378
8140
|
}
|
|
8379
8141
|
return { ok: true };
|
|
@@ -8429,7 +8191,7 @@ async function fixCommand(opts = {}) {
|
|
|
8429
8191
|
}
|
|
8430
8192
|
if (!skipCache) {
|
|
8431
8193
|
const nextDir = join12(projectRoot, ".next");
|
|
8432
|
-
if (
|
|
8194
|
+
if (existsSync15(nextDir)) {
|
|
8433
8195
|
if (!dryRun) rmSync5(nextDir, { recursive: true, force: true });
|
|
8434
8196
|
fixes.push("Cleared build cache");
|
|
8435
8197
|
console.log(chalk15.green(" \u2714 Cleared build cache"));
|
|
@@ -8451,12 +8213,12 @@ async function fixCommand(opts = {}) {
|
|
|
8451
8213
|
}
|
|
8452
8214
|
}
|
|
8453
8215
|
}
|
|
8454
|
-
const appDir =
|
|
8216
|
+
const appDir = resolve8(projectRoot, "app");
|
|
8455
8217
|
const allTsxFiles = listTsxFiles(appDir);
|
|
8456
|
-
const componentsTsxFiles = listTsxFiles(
|
|
8218
|
+
const componentsTsxFiles = listTsxFiles(resolve8(projectRoot, "components"));
|
|
8457
8219
|
const allComponentIds = /* @__PURE__ */ new Set();
|
|
8458
8220
|
for (const file of [...allTsxFiles, ...componentsTsxFiles]) {
|
|
8459
|
-
const content =
|
|
8221
|
+
const content = readFileSync11(file, "utf-8");
|
|
8460
8222
|
extractComponentIdsFromCode2(content).forEach((id) => allComponentIds.add(id));
|
|
8461
8223
|
}
|
|
8462
8224
|
let dsm = null;
|
|
@@ -8475,8 +8237,8 @@ async function fixCommand(opts = {}) {
|
|
|
8475
8237
|
missingComponents.push(id);
|
|
8476
8238
|
} else {
|
|
8477
8239
|
const fileName = toKebabCase(id) + ".tsx";
|
|
8478
|
-
const filePath =
|
|
8479
|
-
if (!
|
|
8240
|
+
const filePath = resolve8(projectRoot, "components", "ui", fileName);
|
|
8241
|
+
if (!existsSync15(filePath)) missingFiles.push(id);
|
|
8480
8242
|
}
|
|
8481
8243
|
}
|
|
8482
8244
|
const provider = getComponentProvider();
|
|
@@ -8505,8 +8267,8 @@ async function fixCommand(opts = {}) {
|
|
|
8505
8267
|
const generator = new ComponentGenerator3(updatedConfig);
|
|
8506
8268
|
const code = await generator.generate(component);
|
|
8507
8269
|
const fileName = toKebabCase(component.name) + ".tsx";
|
|
8508
|
-
const filePath =
|
|
8509
|
-
mkdirSync7(
|
|
8270
|
+
const filePath = resolve8(projectRoot, "components", "ui", fileName);
|
|
8271
|
+
mkdirSync7(resolve8(projectRoot, "components", "ui"), { recursive: true });
|
|
8510
8272
|
await writeFile(filePath, code);
|
|
8511
8273
|
}
|
|
8512
8274
|
}
|
|
@@ -8525,10 +8287,100 @@ async function fixCommand(opts = {}) {
|
|
|
8525
8287
|
}
|
|
8526
8288
|
}
|
|
8527
8289
|
}
|
|
8290
|
+
if (!dsm && existsSync15(project.configPath)) {
|
|
8291
|
+
dsm = new DesignSystemManager9(project.configPath);
|
|
8292
|
+
await dsm.load();
|
|
8293
|
+
}
|
|
8294
|
+
if (dsm && dsm.getConfig().name === "My App") {
|
|
8295
|
+
const { toTitleCase: toTitleCase2 } = await import("./strings-BHAW5PVU.js");
|
|
8296
|
+
let derivedName = null;
|
|
8297
|
+
try {
|
|
8298
|
+
const pkgPath = resolve8(projectRoot, "package.json");
|
|
8299
|
+
if (existsSync15(pkgPath)) {
|
|
8300
|
+
const pkg = JSON.parse(readFileSync11(pkgPath, "utf-8"));
|
|
8301
|
+
if (typeof pkg.name === "string" && pkg.name) {
|
|
8302
|
+
derivedName = toTitleCase2(pkg.name);
|
|
8303
|
+
}
|
|
8304
|
+
}
|
|
8305
|
+
} catch {
|
|
8306
|
+
}
|
|
8307
|
+
if (!derivedName) derivedName = toTitleCase2(basename3(projectRoot));
|
|
8308
|
+
if (derivedName !== "My App") {
|
|
8309
|
+
if (dryRun) {
|
|
8310
|
+
fixes.push(`Would replace placeholder "My App" with "${derivedName}" in config`);
|
|
8311
|
+
console.log(chalk15.green(` \u2714 Would replace "My App" with "${derivedName}" in config`));
|
|
8312
|
+
} else {
|
|
8313
|
+
const cfg = dsm.getConfig();
|
|
8314
|
+
dsm.updateConfig({ ...cfg, name: derivedName });
|
|
8315
|
+
await dsm.save();
|
|
8316
|
+
fixes.push(`Replaced placeholder "My App" with "${derivedName}" in config`);
|
|
8317
|
+
console.log(chalk15.green(` \u2714 Replaced "My App" with "${derivedName}" in config`));
|
|
8318
|
+
}
|
|
8319
|
+
}
|
|
8320
|
+
}
|
|
8321
|
+
if (dsm && !dryRun) {
|
|
8322
|
+
try {
|
|
8323
|
+
const { fixGlobalsCss: fixGlobalsCss2 } = await import("./fix-globals-css-UQCGJ5NO.js");
|
|
8324
|
+
fixGlobalsCss2(projectRoot, dsm.getConfig());
|
|
8325
|
+
fixes.push("Synced CSS variables");
|
|
8326
|
+
console.log(chalk15.green(" \u2714 Synced CSS variables"));
|
|
8327
|
+
} catch (e) {
|
|
8328
|
+
console.log(chalk15.yellow(` \u26A0 CSS sync: ${e instanceof Error ? e.message : "unknown error"}`));
|
|
8329
|
+
}
|
|
8330
|
+
} else if (dryRun && dsm) {
|
|
8331
|
+
fixes.push("Would sync CSS variables");
|
|
8332
|
+
}
|
|
8333
|
+
if (dsm) {
|
|
8334
|
+
const configName = dsm.getConfig().name;
|
|
8335
|
+
if (configName && configName !== "My App") {
|
|
8336
|
+
const appLayoutPath = resolve8(projectRoot, "app", "(app)", "layout.tsx");
|
|
8337
|
+
if (existsSync15(appLayoutPath)) {
|
|
8338
|
+
let appLayoutCode = readFileSync11(appLayoutPath, "utf-8");
|
|
8339
|
+
if (appLayoutCode.includes("My App")) {
|
|
8340
|
+
appLayoutCode = appLayoutCode.replace(/My App/g, configName);
|
|
8341
|
+
if (!dryRun) {
|
|
8342
|
+
const appResult = safeWrite(appLayoutPath, appLayoutCode, projectRoot, backups);
|
|
8343
|
+
if (appResult.ok) {
|
|
8344
|
+
modifiedFiles.push(appLayoutPath);
|
|
8345
|
+
fixes.push(`Replaced "My App" with "${configName}" in (app)/layout.tsx`);
|
|
8346
|
+
console.log(chalk15.green(` \u2714 Replaced "My App" with "${configName}" in (app)/layout.tsx`));
|
|
8347
|
+
} else {
|
|
8348
|
+
console.log(chalk15.yellow(" \u26A0 (app)/layout.tsx update rolled back (parse error)"));
|
|
8349
|
+
}
|
|
8350
|
+
} else {
|
|
8351
|
+
fixes.push(`Would replace "My App" with "${configName}" in (app)/layout.tsx`);
|
|
8352
|
+
}
|
|
8353
|
+
}
|
|
8354
|
+
}
|
|
8355
|
+
const sharedDir = resolve8(projectRoot, "components", "shared");
|
|
8356
|
+
if (existsSync15(sharedDir)) {
|
|
8357
|
+
try {
|
|
8358
|
+
for (const f of readdirSync7(sharedDir).filter((n) => n.endsWith(".tsx"))) {
|
|
8359
|
+
const sharedPath = join12(sharedDir, f);
|
|
8360
|
+
const sharedCode = readFileSync11(sharedPath, "utf-8");
|
|
8361
|
+
if (sharedCode.includes("My App")) {
|
|
8362
|
+
const updated = sharedCode.replace(/My App/g, configName);
|
|
8363
|
+
if (!dryRun) {
|
|
8364
|
+
const sharedResult = safeWrite(sharedPath, updated, projectRoot, backups);
|
|
8365
|
+
if (sharedResult.ok) {
|
|
8366
|
+
modifiedFiles.push(sharedPath);
|
|
8367
|
+
fixes.push(`Replaced "My App" with "${configName}" in components/shared/${f}`);
|
|
8368
|
+
console.log(chalk15.green(` \u2714 Replaced "My App" with "${configName}" in components/shared/${f}`));
|
|
8369
|
+
}
|
|
8370
|
+
} else {
|
|
8371
|
+
fixes.push(`Would replace "My App" with "${configName}" in components/shared/${f}`);
|
|
8372
|
+
}
|
|
8373
|
+
}
|
|
8374
|
+
}
|
|
8375
|
+
} catch {
|
|
8376
|
+
}
|
|
8377
|
+
}
|
|
8378
|
+
}
|
|
8379
|
+
}
|
|
8528
8380
|
const userTsxFiles = allTsxFiles.filter((f) => !f.includes("/design-system/"));
|
|
8529
8381
|
let syntaxFixed = 0;
|
|
8530
8382
|
for (const file of userTsxFiles) {
|
|
8531
|
-
const content =
|
|
8383
|
+
const content = readFileSync11(file, "utf-8");
|
|
8532
8384
|
const fixed = fixUnescapedLtInJsx(
|
|
8533
8385
|
fixEscapedClosingQuotes(sanitizeMetadataStrings(ensureUseClientIfNeeded(content)))
|
|
8534
8386
|
);
|
|
@@ -8552,8 +8404,8 @@ async function fixCommand(opts = {}) {
|
|
|
8552
8404
|
console.log(chalk15.green(` \u2714 ${verb} syntax: ${syntaxFixed} file(s) (use client, metadata, quotes)`));
|
|
8553
8405
|
}
|
|
8554
8406
|
try {
|
|
8555
|
-
const { loadPlan: loadPlan2 } = await import("./plan-generator-
|
|
8556
|
-
const { ensurePlanGroupLayouts: ensurePlanGroupLayouts2 } = await import("./code-generator-
|
|
8407
|
+
const { loadPlan: loadPlan2 } = await import("./plan-generator-YOPF773K.js");
|
|
8408
|
+
const { ensurePlanGroupLayouts: ensurePlanGroupLayouts2 } = await import("./code-generator-CV54KQFF.js");
|
|
8557
8409
|
const plan = loadPlan2(projectRoot);
|
|
8558
8410
|
if (plan) {
|
|
8559
8411
|
if (!dsm) {
|
|
@@ -8565,8 +8417,8 @@ async function fixCommand(opts = {}) {
|
|
|
8565
8417
|
fixes.push(`Verified group layouts (${layoutTypes})`);
|
|
8566
8418
|
console.log(chalk15.green(` \u2714 Verified group layouts: ${layoutTypes}`));
|
|
8567
8419
|
const hasSidebar = plan.groups.some((g) => g.layout === "sidebar" || g.layout === "both");
|
|
8568
|
-
const sidebarPath =
|
|
8569
|
-
if (hasSidebar && !
|
|
8420
|
+
const sidebarPath = resolve8(projectRoot, "components", "shared", "sidebar.tsx");
|
|
8421
|
+
if (hasSidebar && !existsSync15(sidebarPath) && !dryRun) {
|
|
8570
8422
|
if (!dsm) {
|
|
8571
8423
|
dsm = new DesignSystemManager9(project.configPath);
|
|
8572
8424
|
await dsm.load();
|
|
@@ -8574,7 +8426,7 @@ async function fixCommand(opts = {}) {
|
|
|
8574
8426
|
const { PageGenerator } = await import("@getcoherent/core");
|
|
8575
8427
|
const generator = new PageGenerator(dsm.getConfig());
|
|
8576
8428
|
const sidebarCode = generator.generateSharedSidebarCode();
|
|
8577
|
-
mkdirSync7(
|
|
8429
|
+
mkdirSync7(resolve8(projectRoot, "components", "shared"), { recursive: true });
|
|
8578
8430
|
const sidebarResult = safeWrite(sidebarPath, sidebarCode, projectRoot, backups);
|
|
8579
8431
|
if (sidebarResult.ok) {
|
|
8580
8432
|
fixes.push("Generated AppSidebar component (components/shared/sidebar.tsx)");
|
|
@@ -8584,9 +8436,9 @@ async function fixCommand(opts = {}) {
|
|
|
8584
8436
|
}
|
|
8585
8437
|
}
|
|
8586
8438
|
if (hasSidebar && !dryRun) {
|
|
8587
|
-
const rootLayoutPath =
|
|
8588
|
-
if (
|
|
8589
|
-
let rootCode =
|
|
8439
|
+
const rootLayoutPath = resolve8(projectRoot, "app", "layout.tsx");
|
|
8440
|
+
if (existsSync15(rootLayoutPath)) {
|
|
8441
|
+
let rootCode = readFileSync11(rootLayoutPath, "utf-8");
|
|
8590
8442
|
if (rootCode.includes("<Header")) {
|
|
8591
8443
|
rootCode = rootCode.replace(/import\s*\{[^}]*Header[^}]*\}[^;\n]*[;\n]?\s*/g, "").replace(/import\s*\{[^}]*Footer[^}]*\}[^;\n]*[;\n]?\s*/g, "").replace(/import\s+ShowWhenNotAuthRoute[^;\n]*[;\n]?\s*/g, "").replace(/<ShowWhenNotAuthRoute>[\s\S]*?<\/ShowWhenNotAuthRoute>/g, (match) => {
|
|
8592
8444
|
const inner = match.replace(/<\/?ShowWhenNotAuthRoute>/g, "").trim();
|
|
@@ -8603,12 +8455,12 @@ async function fixCommand(opts = {}) {
|
|
|
8603
8455
|
}
|
|
8604
8456
|
}
|
|
8605
8457
|
}
|
|
8606
|
-
const publicLayoutPath =
|
|
8607
|
-
const publicExists =
|
|
8608
|
-
const needsPublicLayout = !publicExists || !
|
|
8458
|
+
const publicLayoutPath = resolve8(projectRoot, "app", "(public)", "layout.tsx");
|
|
8459
|
+
const publicExists = existsSync15(publicLayoutPath);
|
|
8460
|
+
const needsPublicLayout = !publicExists || !readFileSync11(publicLayoutPath, "utf-8").includes("<Header");
|
|
8609
8461
|
if (needsPublicLayout) {
|
|
8610
|
-
const { buildPublicLayoutCodeForSidebar } = await import("./code-generator-
|
|
8611
|
-
mkdirSync7(
|
|
8462
|
+
const { buildPublicLayoutCodeForSidebar } = await import("./code-generator-CV54KQFF.js");
|
|
8463
|
+
mkdirSync7(resolve8(projectRoot, "app", "(public)"), { recursive: true });
|
|
8612
8464
|
const publicResult = safeWrite(publicLayoutPath, buildPublicLayoutCodeForSidebar(), projectRoot, backups);
|
|
8613
8465
|
if (publicResult.ok) {
|
|
8614
8466
|
fixes.push("Added Header/Footer to (public) layout");
|
|
@@ -8617,45 +8469,9 @@ async function fixCommand(opts = {}) {
|
|
|
8617
8469
|
console.log(chalk15.yellow(" \u26A0 Public layout generation failed validation"));
|
|
8618
8470
|
}
|
|
8619
8471
|
}
|
|
8620
|
-
const
|
|
8621
|
-
if (
|
|
8622
|
-
|
|
8623
|
-
const configName = dsm.getConfig().name;
|
|
8624
|
-
if (configName && configName !== "My App" && appLayoutCode.includes("My App")) {
|
|
8625
|
-
appLayoutCode = appLayoutCode.replace(/My App/g, configName);
|
|
8626
|
-
const appResult = safeWrite(appLayoutPath, appLayoutCode, projectRoot, backups);
|
|
8627
|
-
if (appResult.ok) {
|
|
8628
|
-
fixes.push(`Replaced "My App" with "${configName}" in (app)/layout.tsx`);
|
|
8629
|
-
console.log(chalk15.green(` \u2714 Replaced "My App" with "${configName}" in (app)/layout.tsx`));
|
|
8630
|
-
} else {
|
|
8631
|
-
console.log(chalk15.yellow(" \u26A0 (app)/layout.tsx update rolled back (parse error)"));
|
|
8632
|
-
}
|
|
8633
|
-
}
|
|
8634
|
-
}
|
|
8635
|
-
const sharedDir = resolve10(projectRoot, "components", "shared");
|
|
8636
|
-
if (existsSync17(sharedDir) && dsm) {
|
|
8637
|
-
const cfgName = dsm.getConfig().name;
|
|
8638
|
-
if (cfgName && cfgName !== "My App") {
|
|
8639
|
-
try {
|
|
8640
|
-
for (const f of readdirSync7(sharedDir).filter((n) => n.endsWith(".tsx"))) {
|
|
8641
|
-
const sharedPath = join12(sharedDir, f);
|
|
8642
|
-
const sharedCode = readFileSync13(sharedPath, "utf-8");
|
|
8643
|
-
if (sharedCode.includes("My App")) {
|
|
8644
|
-
const updated = sharedCode.replace(/My App/g, cfgName);
|
|
8645
|
-
const sharedResult = safeWrite(sharedPath, updated, projectRoot, backups);
|
|
8646
|
-
if (sharedResult.ok) {
|
|
8647
|
-
fixes.push(`Replaced "My App" with "${cfgName}" in components/shared/${f}`);
|
|
8648
|
-
console.log(chalk15.green(` \u2714 Replaced "My App" with "${cfgName}" in components/shared/${f}`));
|
|
8649
|
-
}
|
|
8650
|
-
}
|
|
8651
|
-
}
|
|
8652
|
-
} catch {
|
|
8653
|
-
}
|
|
8654
|
-
}
|
|
8655
|
-
}
|
|
8656
|
-
const sidebarComponentPath2 = resolve10(projectRoot, "components", "shared", "sidebar.tsx");
|
|
8657
|
-
if (existsSync17(sidebarComponentPath2)) {
|
|
8658
|
-
const existingSidebarCode = readFileSync13(sidebarComponentPath2, "utf-8");
|
|
8472
|
+
const sidebarComponentPath2 = resolve8(projectRoot, "components", "shared", "sidebar.tsx");
|
|
8473
|
+
if (existsSync15(sidebarComponentPath2)) {
|
|
8474
|
+
const existingSidebarCode = readFileSync11(sidebarComponentPath2, "utf-8");
|
|
8659
8475
|
const sidebarConfigName = dsm?.getConfig().name ?? "";
|
|
8660
8476
|
const hasWrongName = existingSidebarCode.includes("My App") && sidebarConfigName !== "My App";
|
|
8661
8477
|
const hasTrigger = existingSidebarCode.includes("SidebarTrigger");
|
|
@@ -8681,19 +8497,19 @@ async function fixCommand(opts = {}) {
|
|
|
8681
8497
|
}
|
|
8682
8498
|
}
|
|
8683
8499
|
}
|
|
8684
|
-
const rootPagePath =
|
|
8685
|
-
const publicPagePath =
|
|
8686
|
-
if (
|
|
8500
|
+
const rootPagePath = resolve8(projectRoot, "app", "page.tsx");
|
|
8501
|
+
const publicPagePath = resolve8(projectRoot, "app", "(public)", "page.tsx");
|
|
8502
|
+
if (existsSync15(rootPagePath) && !existsSync15(publicPagePath)) {
|
|
8687
8503
|
const { renameSync } = await import("fs");
|
|
8688
|
-
mkdirSync7(
|
|
8504
|
+
mkdirSync7(resolve8(projectRoot, "app", "(public)"), { recursive: true });
|
|
8689
8505
|
renameSync(rootPagePath, publicPagePath);
|
|
8690
8506
|
fixes.push("Moved app/page.tsx \u2192 app/(public)/page.tsx (sidebar mode)");
|
|
8691
8507
|
console.log(chalk15.green(" \u2714 Moved app/page.tsx \u2192 app/(public)/page.tsx (gets Header/Footer)"));
|
|
8692
8508
|
}
|
|
8693
|
-
const themeTogglePath =
|
|
8694
|
-
if (!
|
|
8695
|
-
const { generateThemeToggleCode } = await import("./code-generator-
|
|
8696
|
-
mkdirSync7(
|
|
8509
|
+
const themeTogglePath = resolve8(projectRoot, "components", "shared", "theme-toggle.tsx");
|
|
8510
|
+
if (!existsSync15(themeTogglePath)) {
|
|
8511
|
+
const { generateThemeToggleCode } = await import("./code-generator-CV54KQFF.js");
|
|
8512
|
+
mkdirSync7(resolve8(projectRoot, "components", "shared"), { recursive: true });
|
|
8697
8513
|
const themeResult = safeWrite(themeTogglePath, generateThemeToggleCode(), projectRoot, backups);
|
|
8698
8514
|
if (themeResult.ok) {
|
|
8699
8515
|
fixes.push("Generated ThemeToggle component (components/shared/theme-toggle.tsx)");
|
|
@@ -8707,11 +8523,32 @@ async function fixCommand(opts = {}) {
|
|
|
8707
8523
|
} catch (err) {
|
|
8708
8524
|
console.log(chalk15.yellow(` \u26A0 Layout repair skipped: ${err instanceof Error ? err.message : "unknown error"}`));
|
|
8709
8525
|
}
|
|
8526
|
+
const appLayoutRepairPath = resolve8(projectRoot, "app", "(app)", "layout.tsx");
|
|
8527
|
+
if (existsSync15(appLayoutRepairPath) && dsm) {
|
|
8528
|
+
const appLayoutCode = readFileSync11(appLayoutRepairPath, "utf-8");
|
|
8529
|
+
const isMinimal = appLayoutCode.length < 500 && !appLayoutCode.includes("Header") && !appLayoutCode.includes("Footer") && !appLayoutCode.includes("Sidebar") && !appLayoutCode.includes("SidebarProvider") && !appLayoutCode.includes("SidebarTrigger") && !appLayoutCode.includes("Sheet");
|
|
8530
|
+
const navType = dsm.getConfig().navigation?.type || "header";
|
|
8531
|
+
if (isMinimal && navType !== "none") {
|
|
8532
|
+
const { buildAppLayoutCode, buildGroupLayoutCode } = await import("./code-generator-CV54KQFF.js");
|
|
8533
|
+
const isSidebar = navType === "sidebar" || navType === "both";
|
|
8534
|
+
const newLayout = isSidebar ? buildAppLayoutCode(navType, dsm.getConfig().name) : buildGroupLayoutCode("header", dsm.getConfig().pages?.map((p) => p.name) || [], dsm.getConfig().name);
|
|
8535
|
+
if (!dryRun) {
|
|
8536
|
+
const layoutResult = safeWrite(appLayoutRepairPath, newLayout, projectRoot, backups);
|
|
8537
|
+
if (layoutResult.ok) {
|
|
8538
|
+
modifiedFiles.push(appLayoutRepairPath);
|
|
8539
|
+
fixes.push(`Regenerated minimal (app) layout with ${navType} navigation`);
|
|
8540
|
+
console.log(chalk15.green(` \u2714 Regenerated (app) layout with ${navType} navigation`));
|
|
8541
|
+
}
|
|
8542
|
+
} else {
|
|
8543
|
+
fixes.push(`Would regenerate minimal (app) layout with ${navType} navigation`);
|
|
8544
|
+
}
|
|
8545
|
+
}
|
|
8546
|
+
}
|
|
8710
8547
|
if (!skipQuality) {
|
|
8711
8548
|
let qualityFixCount = 0;
|
|
8712
8549
|
const qualityFixDetails = [];
|
|
8713
8550
|
for (const file of userTsxFiles) {
|
|
8714
|
-
const content =
|
|
8551
|
+
const content = readFileSync11(file, "utf-8");
|
|
8715
8552
|
const { code: autoFixed, fixes: fileFixes } = await autoFixCode(content);
|
|
8716
8553
|
if (autoFixed !== content) {
|
|
8717
8554
|
if (!dryRun) {
|
|
@@ -8739,7 +8576,7 @@ async function fixCommand(opts = {}) {
|
|
|
8739
8576
|
for (const file of modifiedFiles) {
|
|
8740
8577
|
if (!backups.has(file)) continue;
|
|
8741
8578
|
const before = backups.get(file);
|
|
8742
|
-
const after =
|
|
8579
|
+
const after = readFileSync11(file, "utf-8");
|
|
8743
8580
|
const issues = verifyIncrementalEdit(before, after);
|
|
8744
8581
|
if (issues.length > 0) {
|
|
8745
8582
|
for (const issue of issues) {
|
|
@@ -8751,7 +8588,7 @@ async function fixCommand(opts = {}) {
|
|
|
8751
8588
|
let totalWarnings = 0;
|
|
8752
8589
|
const fileIssues = [];
|
|
8753
8590
|
for (const file of allTsxFiles) {
|
|
8754
|
-
const code = dryRun ?
|
|
8591
|
+
const code = dryRun ? readFileSync11(file, "utf-8") : readFileSync11(file, "utf-8");
|
|
8755
8592
|
const relativePath = file.replace(projectRoot + "/", "");
|
|
8756
8593
|
const baseName = file.split("/").pop() || "";
|
|
8757
8594
|
const isAuthPage = relativePath.includes("(auth)");
|
|
@@ -8881,8 +8718,8 @@ async function fixCommand(opts = {}) {
|
|
|
8881
8718
|
|
|
8882
8719
|
// src/commands/check.ts
|
|
8883
8720
|
import chalk16 from "chalk";
|
|
8884
|
-
import { resolve as
|
|
8885
|
-
import { readdirSync as readdirSync8, readFileSync as
|
|
8721
|
+
import { resolve as resolve9 } from "path";
|
|
8722
|
+
import { readdirSync as readdirSync8, readFileSync as readFileSync12, statSync as statSync3, existsSync as existsSync16 } from "fs";
|
|
8886
8723
|
import { loadManifest as loadManifest10 } from "@getcoherent/core";
|
|
8887
8724
|
var EXCLUDED_DIRS = /* @__PURE__ */ new Set(["node_modules", "design-system"]);
|
|
8888
8725
|
function findTsxFiles(dir) {
|
|
@@ -8890,7 +8727,7 @@ function findTsxFiles(dir) {
|
|
|
8890
8727
|
try {
|
|
8891
8728
|
const entries = readdirSync8(dir);
|
|
8892
8729
|
for (const entry of entries) {
|
|
8893
|
-
const full =
|
|
8730
|
+
const full = resolve9(dir, entry);
|
|
8894
8731
|
const stat = statSync3(full);
|
|
8895
8732
|
if (stat.isDirectory() && !entry.startsWith(".") && !EXCLUDED_DIRS.has(entry)) {
|
|
8896
8733
|
results.push(...findTsxFiles(full));
|
|
@@ -8925,7 +8762,7 @@ async function checkCommand(opts = {}) {
|
|
|
8925
8762
|
} catch {
|
|
8926
8763
|
}
|
|
8927
8764
|
if (!skipPages) {
|
|
8928
|
-
const appDir =
|
|
8765
|
+
const appDir = resolve9(projectRoot, "app");
|
|
8929
8766
|
const files = findTsxFiles(appDir);
|
|
8930
8767
|
result.pages.total = files.length;
|
|
8931
8768
|
if (!opts.json) console.log(chalk16.cyan("\n \u{1F4C4} Pages") + chalk16.dim(` (${files.length} scanned)
|
|
@@ -8939,7 +8776,7 @@ async function checkCommand(opts = {}) {
|
|
|
8939
8776
|
"NATIVE_TABLE"
|
|
8940
8777
|
]);
|
|
8941
8778
|
for (const file of files) {
|
|
8942
|
-
const code =
|
|
8779
|
+
const code = readFileSync12(file, "utf-8");
|
|
8943
8780
|
const relativePath = file.replace(projectRoot + "/", "");
|
|
8944
8781
|
const baseName = file.split("/").pop() || "";
|
|
8945
8782
|
const isAuthPage = relativePath.includes("(auth)");
|
|
@@ -8981,7 +8818,7 @@ async function checkCommand(opts = {}) {
|
|
|
8981
8818
|
routeSet.add("/");
|
|
8982
8819
|
routeSet.add("#");
|
|
8983
8820
|
for (const file of files) {
|
|
8984
|
-
const code =
|
|
8821
|
+
const code = readFileSync12(file, "utf-8");
|
|
8985
8822
|
const relativePath = file.replace(projectRoot + "/", "");
|
|
8986
8823
|
const lines = code.split("\n");
|
|
8987
8824
|
const linkHrefRe = /href\s*=\s*["'](\/[a-z0-9/-]*)["']/gi;
|
|
@@ -9013,8 +8850,8 @@ async function checkCommand(opts = {}) {
|
|
|
9013
8850
|
const manifest = await loadManifest10(project.root);
|
|
9014
8851
|
if (manifest.shared.length > 0) {
|
|
9015
8852
|
for (const entry of manifest.shared) {
|
|
9016
|
-
const fullPath =
|
|
9017
|
-
if (!
|
|
8853
|
+
const fullPath = resolve9(project.root, entry.file);
|
|
8854
|
+
if (!existsSync16(fullPath)) {
|
|
9018
8855
|
result.pages.withErrors++;
|
|
9019
8856
|
if (!opts.json) console.log(chalk16.red(`
|
|
9020
8857
|
\u2717 Missing shared component file: ${entry.id} (${entry.file})`));
|
|
@@ -9038,8 +8875,8 @@ async function checkCommand(opts = {}) {
|
|
|
9038
8875
|
let _staleUsedIn = 0;
|
|
9039
8876
|
let _nameMismatch = 0;
|
|
9040
8877
|
for (const entry of manifest.shared) {
|
|
9041
|
-
const filePath =
|
|
9042
|
-
const fileExists =
|
|
8878
|
+
const filePath = resolve9(projectRoot, entry.file);
|
|
8879
|
+
const fileExists = existsSync16(filePath);
|
|
9043
8880
|
if (!fileExists) {
|
|
9044
8881
|
_orphaned++;
|
|
9045
8882
|
if (!opts.json) {
|
|
@@ -9049,7 +8886,7 @@ async function checkCommand(opts = {}) {
|
|
|
9049
8886
|
continue;
|
|
9050
8887
|
}
|
|
9051
8888
|
try {
|
|
9052
|
-
const code =
|
|
8889
|
+
const code = readFileSync12(filePath, "utf-8");
|
|
9053
8890
|
const actualExports = extractExportedComponentNames(code);
|
|
9054
8891
|
if (actualExports.length > 0 && !actualExports.includes(entry.name)) {
|
|
9055
8892
|
_nameMismatch++;
|
|
@@ -9117,7 +8954,7 @@ async function checkCommand(opts = {}) {
|
|
|
9117
8954
|
id: e.id,
|
|
9118
8955
|
name: e.name,
|
|
9119
8956
|
type: e.type,
|
|
9120
|
-
status:
|
|
8957
|
+
status: existsSync16(resolve9(projectRoot, e.file)) ? "ok" : "unused",
|
|
9121
8958
|
message: "",
|
|
9122
8959
|
suggestions: void 0
|
|
9123
8960
|
}))
|
|
@@ -9130,12 +8967,12 @@ async function checkCommand(opts = {}) {
|
|
|
9130
8967
|
const { validateReuse } = await import("./reuse-validator-XR2ZEYC4.js");
|
|
9131
8968
|
const { inferPageTypeFromRoute: inferPageTypeFromRoute2 } = await import("./design-constraints-EIP2XM7T.js");
|
|
9132
8969
|
const manifest = await loadManifest10(projectRoot);
|
|
9133
|
-
const appDir =
|
|
9134
|
-
const pageFiles =
|
|
8970
|
+
const appDir = resolve9(projectRoot, "app");
|
|
8971
|
+
const pageFiles = existsSync16(appDir) ? findTsxFiles(appDir) : [];
|
|
9135
8972
|
if (manifest.shared.length > 0 && pageFiles.length > 0) {
|
|
9136
8973
|
const reuseWarnings = [];
|
|
9137
8974
|
for (const file of pageFiles) {
|
|
9138
|
-
const code =
|
|
8975
|
+
const code = readFileSync12(file, "utf-8");
|
|
9139
8976
|
const relativePath = file.replace(projectRoot + "/", "");
|
|
9140
8977
|
const route = "/" + relativePath.replace(/^app\//, "").replace(/\/page\.tsx$/, "").replace(/^\(.*?\)\//, "");
|
|
9141
8978
|
const pageType = inferPageTypeFromRoute2(route);
|
|
@@ -9246,8 +9083,8 @@ import {
|
|
|
9246
9083
|
generateSharedComponent as generateSharedComponent4,
|
|
9247
9084
|
integrateSharedLayoutIntoRootLayout as integrateSharedLayoutIntoRootLayout2
|
|
9248
9085
|
} from "@getcoherent/core";
|
|
9249
|
-
import { existsSync as
|
|
9250
|
-
import { resolve as
|
|
9086
|
+
import { existsSync as existsSync17 } from "fs";
|
|
9087
|
+
import { resolve as resolve10 } from "path";
|
|
9251
9088
|
|
|
9252
9089
|
// src/utils/ds-files.ts
|
|
9253
9090
|
import { mkdir as mkdir3, writeFile as writeFile4 } from "fs/promises";
|
|
@@ -9400,8 +9237,8 @@ function createComponentsCommand() {
|
|
|
9400
9237
|
const updated = await integrateSharedLayoutIntoRootLayout2(project.root);
|
|
9401
9238
|
if (updated) console.log(chalk22.cyan(" Updated app/layout.tsx to use shared layout components.\n"));
|
|
9402
9239
|
}
|
|
9403
|
-
const sharedPagePath =
|
|
9404
|
-
if (!
|
|
9240
|
+
const sharedPagePath = resolve10(project.root, "app/design-system/shared/page.tsx");
|
|
9241
|
+
if (!existsSync17(sharedPagePath)) {
|
|
9405
9242
|
try {
|
|
9406
9243
|
const dsm = new DesignSystemManager10(project.configPath);
|
|
9407
9244
|
await dsm.load();
|
|
@@ -9427,14 +9264,14 @@ function createComponentsCommand() {
|
|
|
9427
9264
|
import chalk23 from "chalk";
|
|
9428
9265
|
import ora6 from "ora";
|
|
9429
9266
|
import { writeFile as writeFile5, mkdir as mkdir4 } from "fs/promises";
|
|
9430
|
-
import { resolve as
|
|
9431
|
-
import { existsSync as
|
|
9267
|
+
import { resolve as resolve11, join as join14, dirname as dirname6 } from "path";
|
|
9268
|
+
import { existsSync as existsSync18 } from "fs";
|
|
9432
9269
|
import {
|
|
9433
9270
|
FigmaClient,
|
|
9434
9271
|
parseFigmaFileResponse,
|
|
9435
9272
|
extractTokensFromFigma,
|
|
9436
9273
|
mergeExtractedColorsWithDefaults,
|
|
9437
|
-
buildCssVariables
|
|
9274
|
+
buildCssVariables,
|
|
9438
9275
|
EXAMPLE_MULTIPAGE_CONFIG,
|
|
9439
9276
|
normalizeFigmaComponents,
|
|
9440
9277
|
setSharedMapping,
|
|
@@ -9608,7 +9445,7 @@ async function importFigmaAction(urlOrKey, opts) {
|
|
|
9608
9445
|
};
|
|
9609
9446
|
stats.colorStyles = intermediate.colorStyles.length;
|
|
9610
9447
|
stats.textStyles = intermediate.textStyles.length;
|
|
9611
|
-
const cssVars =
|
|
9448
|
+
const cssVars = buildCssVariables(mergedConfig);
|
|
9612
9449
|
const fullGlobals = `@tailwind base;
|
|
9613
9450
|
@tailwind components;
|
|
9614
9451
|
@tailwind utilities;
|
|
@@ -9652,7 +9489,7 @@ async function importFigmaAction(urlOrKey, opts) {
|
|
|
9652
9489
|
if (dryRun) stats.filesWritten.push(FIGMA_COMPONENT_MAP_FILENAME);
|
|
9653
9490
|
else
|
|
9654
9491
|
await writeFile5(
|
|
9655
|
-
|
|
9492
|
+
resolve11(projectRoot, FIGMA_COMPONENT_MAP_FILENAME),
|
|
9656
9493
|
JSON.stringify(componentMapObj, null, 2),
|
|
9657
9494
|
"utf-8"
|
|
9658
9495
|
);
|
|
@@ -9675,9 +9512,9 @@ async function importFigmaAction(urlOrKey, opts) {
|
|
|
9675
9512
|
const fullConfig = buildFigmaImportConfig(mergedConfig, pageDefs, intermediate.fileName);
|
|
9676
9513
|
if (!dryRun) {
|
|
9677
9514
|
spinner.start("Updating design-system.config.ts...");
|
|
9678
|
-
const configPath =
|
|
9515
|
+
const configPath = resolve11(projectRoot, DESIGN_SYSTEM_CONFIG_PATH);
|
|
9679
9516
|
const dsm = new DesignSystemManager11(configPath);
|
|
9680
|
-
if (
|
|
9517
|
+
if (existsSync18(configPath)) {
|
|
9681
9518
|
await dsm.load();
|
|
9682
9519
|
const existing = dsm.getConfig();
|
|
9683
9520
|
dsm.updateConfig({
|
|
@@ -9707,7 +9544,7 @@ export const config = ${JSON.stringify(fullConfig, null, 2)} as const
|
|
|
9707
9544
|
spinner.succeed("design-system.config.ts updated");
|
|
9708
9545
|
spinner.start("Ensuring root layout...");
|
|
9709
9546
|
const layoutPath = join14(projectRoot, "app/layout.tsx");
|
|
9710
|
-
if (!
|
|
9547
|
+
if (!existsSync18(layoutPath)) {
|
|
9711
9548
|
await mkdir4(dirname6(layoutPath), { recursive: true });
|
|
9712
9549
|
await writeFile5(layoutPath, MINIMAL_ROOT_LAYOUT, "utf-8");
|
|
9713
9550
|
stats.filesWritten.push("app/layout.tsx");
|
|
@@ -9797,7 +9634,7 @@ async function dsRegenerateCommand() {
|
|
|
9797
9634
|
// src/commands/update.ts
|
|
9798
9635
|
import chalk25 from "chalk";
|
|
9799
9636
|
import ora8 from "ora";
|
|
9800
|
-
import { readFileSync as
|
|
9637
|
+
import { readFileSync as readFileSync13, existsSync as existsSync19 } from "fs";
|
|
9801
9638
|
import { join as join15 } from "path";
|
|
9802
9639
|
import { DesignSystemManager as DesignSystemManager13, CLI_VERSION as CLI_VERSION4 } from "@getcoherent/core";
|
|
9803
9640
|
|
|
@@ -9968,9 +9805,9 @@ var EXPECTED_CSS_VARS = [
|
|
|
9968
9805
|
];
|
|
9969
9806
|
function checkMissingCssVars(projectRoot) {
|
|
9970
9807
|
const globalsPath = join15(projectRoot, "app", "globals.css");
|
|
9971
|
-
if (!
|
|
9808
|
+
if (!existsSync19(globalsPath)) return [];
|
|
9972
9809
|
try {
|
|
9973
|
-
const content =
|
|
9810
|
+
const content = readFileSync13(globalsPath, "utf-8");
|
|
9974
9811
|
return EXPECTED_CSS_VARS.filter((v) => !content.includes(v));
|
|
9975
9812
|
} catch {
|
|
9976
9813
|
return [];
|
|
@@ -9978,9 +9815,9 @@ function checkMissingCssVars(projectRoot) {
|
|
|
9978
9815
|
}
|
|
9979
9816
|
function patchGlobalsCss(projectRoot, missingVars) {
|
|
9980
9817
|
const globalsPath = join15(projectRoot, "app", "globals.css");
|
|
9981
|
-
if (!
|
|
9982
|
-
const { writeFileSync:
|
|
9983
|
-
let content =
|
|
9818
|
+
if (!existsSync19(globalsPath) || missingVars.length === 0) return;
|
|
9819
|
+
const { writeFileSync: writeFileSync13 } = __require("fs");
|
|
9820
|
+
let content = readFileSync13(globalsPath, "utf-8");
|
|
9984
9821
|
const defaultValues = {
|
|
9985
9822
|
"--chart-1": "220 70% 50%",
|
|
9986
9823
|
"--chart-2": "160 60% 45%",
|
|
@@ -10008,7 +9845,7 @@ function patchGlobalsCss(projectRoot, missingVars) {
|
|
|
10008
9845
|
const lightSectionEnd = content.indexOf("}");
|
|
10009
9846
|
if (lightSectionEnd > 0) {
|
|
10010
9847
|
content = content.slice(0, lightSectionEnd) + "\n" + injection + "\n" + content.slice(lightSectionEnd);
|
|
10011
|
-
|
|
9848
|
+
writeFileSync13(globalsPath, content, "utf-8");
|
|
10012
9849
|
}
|
|
10013
9850
|
}
|
|
10014
9851
|
|
|
@@ -10058,7 +9895,7 @@ async function undoCommand(options) {
|
|
|
10058
9895
|
// src/commands/sync.ts
|
|
10059
9896
|
import chalk27 from "chalk";
|
|
10060
9897
|
import ora9 from "ora";
|
|
10061
|
-
import { existsSync as
|
|
9898
|
+
import { existsSync as existsSync20, readFileSync as readFileSync14 } from "fs";
|
|
10062
9899
|
import { join as join16, relative as relative6, dirname as dirname7 } from "path";
|
|
10063
9900
|
import { readdir as readdir3, readFile as readFile4 } from "fs/promises";
|
|
10064
9901
|
import { DesignSystemManager as DesignSystemManager14 } from "@getcoherent/core";
|
|
@@ -10067,8 +9904,8 @@ function extractTokensFromProject(projectRoot) {
|
|
|
10067
9904
|
const lightColors = {};
|
|
10068
9905
|
const darkColors = {};
|
|
10069
9906
|
const globalsPath = join16(projectRoot, "app", "globals.css");
|
|
10070
|
-
if (
|
|
10071
|
-
const css =
|
|
9907
|
+
if (existsSync20(globalsPath)) {
|
|
9908
|
+
const css = readFileSync14(globalsPath, "utf-8");
|
|
10072
9909
|
const rootMatch = css.match(/:root\s*\{([^}]+)\}/s);
|
|
10073
9910
|
if (rootMatch) parseVarsInto(rootMatch[1], lightColors);
|
|
10074
9911
|
const darkMatch = css.match(/\.dark\s*\{([^}]+)\}/s);
|
|
@@ -10076,8 +9913,8 @@ function extractTokensFromProject(projectRoot) {
|
|
|
10076
9913
|
}
|
|
10077
9914
|
const layoutPath = join16(projectRoot, "app", "layout.tsx");
|
|
10078
9915
|
let layoutCode = "";
|
|
10079
|
-
if (
|
|
10080
|
-
layoutCode =
|
|
9916
|
+
if (existsSync20(layoutPath)) {
|
|
9917
|
+
layoutCode = readFileSync14(layoutPath, "utf-8");
|
|
10081
9918
|
const rootInline = layoutCode.match(/:root\s*\{([^}]+)\}/s);
|
|
10082
9919
|
if (rootInline && Object.keys(lightColors).length === 0) {
|
|
10083
9920
|
parseVarsInto(rootInline[1], lightColors);
|
|
@@ -10095,7 +9932,7 @@ function extractTokensFromProject(projectRoot) {
|
|
|
10095
9932
|
defaultMode = "dark";
|
|
10096
9933
|
}
|
|
10097
9934
|
let radius;
|
|
10098
|
-
const allCss = [
|
|
9935
|
+
const allCss = [existsSync20(globalsPath) ? readFileSync14(globalsPath, "utf-8") : "", layoutCode].join("\n");
|
|
10099
9936
|
const radiusMatch = allCss.match(/--radius:\s*([^;]+);/);
|
|
10100
9937
|
if (radiusMatch) radius = radiusMatch[1].trim();
|
|
10101
9938
|
return {
|
|
@@ -10119,7 +9956,7 @@ function parseVarsInto(block, target) {
|
|
|
10119
9956
|
async function detectCustomComponents(projectRoot, allPageCode) {
|
|
10120
9957
|
const results = [];
|
|
10121
9958
|
const componentsDir = join16(projectRoot, "components");
|
|
10122
|
-
if (!
|
|
9959
|
+
if (!existsSync20(componentsDir)) return results;
|
|
10123
9960
|
const files = [];
|
|
10124
9961
|
await walkForTsx(componentsDir, files, ["ui"]);
|
|
10125
9962
|
const fileResults = await Promise.all(
|
|
@@ -10310,7 +10147,7 @@ async function syncCommand(options = {}) {
|
|
|
10310
10147
|
const spinner = ora9("Scanning project files...").start();
|
|
10311
10148
|
try {
|
|
10312
10149
|
const appDir = join16(project.root, "app");
|
|
10313
|
-
if (!
|
|
10150
|
+
if (!existsSync20(appDir)) {
|
|
10314
10151
|
spinner.fail("No app/ directory found");
|
|
10315
10152
|
process.exit(1);
|
|
10316
10153
|
}
|
|
@@ -10540,7 +10377,7 @@ async function syncCommand(options = {}) {
|
|
|
10540
10377
|
// src/commands/migrate.ts
|
|
10541
10378
|
import chalk28 from "chalk";
|
|
10542
10379
|
import ora10 from "ora";
|
|
10543
|
-
import { existsSync as
|
|
10380
|
+
import { existsSync as existsSync21, mkdirSync as mkdirSync8, cpSync, rmSync as rmSync6, writeFileSync as writeFileSync11, readFileSync as readFileSync15, readdirSync as readdirSync9 } from "fs";
|
|
10544
10381
|
import { join as join17 } from "path";
|
|
10545
10382
|
function backupDir(projectRoot) {
|
|
10546
10383
|
const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
@@ -10553,11 +10390,11 @@ function createBackup2(projectRoot) {
|
|
|
10553
10390
|
const uiDir = join17(projectRoot, "components", "ui");
|
|
10554
10391
|
const dest = backupDir(projectRoot);
|
|
10555
10392
|
mkdirSync8(dest, { recursive: true });
|
|
10556
|
-
if (
|
|
10393
|
+
if (existsSync21(uiDir)) {
|
|
10557
10394
|
cpSync(uiDir, join17(dest, "components-ui"), { recursive: true });
|
|
10558
10395
|
}
|
|
10559
10396
|
const configPath = join17(projectRoot, "design-system.config.ts");
|
|
10560
|
-
if (
|
|
10397
|
+
if (existsSync21(configPath)) {
|
|
10561
10398
|
cpSync(configPath, join17(dest, "design-system.config.ts"));
|
|
10562
10399
|
}
|
|
10563
10400
|
return dest;
|
|
@@ -10565,28 +10402,28 @@ function createBackup2(projectRoot) {
|
|
|
10565
10402
|
function setGuard(projectRoot, backupPath) {
|
|
10566
10403
|
const guard = guardPath(projectRoot);
|
|
10567
10404
|
mkdirSync8(join17(projectRoot, ".coherent"), { recursive: true });
|
|
10568
|
-
|
|
10405
|
+
writeFileSync11(guard, JSON.stringify({ backup: backupPath, startedAt: (/* @__PURE__ */ new Date()).toISOString() }));
|
|
10569
10406
|
}
|
|
10570
10407
|
function clearGuard(projectRoot) {
|
|
10571
10408
|
const guard = guardPath(projectRoot);
|
|
10572
|
-
if (
|
|
10409
|
+
if (existsSync21(guard)) rmSync6(guard);
|
|
10573
10410
|
}
|
|
10574
10411
|
function rollback(projectRoot) {
|
|
10575
10412
|
const guard = guardPath(projectRoot);
|
|
10576
|
-
if (!
|
|
10413
|
+
if (!existsSync21(guard)) return false;
|
|
10577
10414
|
try {
|
|
10578
|
-
const data = JSON.parse(
|
|
10415
|
+
const data = JSON.parse(readFileSync15(guard, "utf-8"));
|
|
10579
10416
|
const backup = data.backup;
|
|
10580
|
-
if (!
|
|
10417
|
+
if (!existsSync21(backup)) return false;
|
|
10581
10418
|
const uiBackup = join17(backup, "components-ui");
|
|
10582
10419
|
const uiDir = join17(projectRoot, "components", "ui");
|
|
10583
|
-
if (
|
|
10584
|
-
if (
|
|
10420
|
+
if (existsSync21(uiBackup)) {
|
|
10421
|
+
if (existsSync21(uiDir)) rmSync6(uiDir, { recursive: true });
|
|
10585
10422
|
cpSync(uiBackup, uiDir, { recursive: true });
|
|
10586
10423
|
}
|
|
10587
10424
|
const configBackup = join17(backup, "design-system.config.ts");
|
|
10588
10425
|
const configDest = join17(projectRoot, "design-system.config.ts");
|
|
10589
|
-
if (
|
|
10426
|
+
if (existsSync21(configBackup)) {
|
|
10590
10427
|
cpSync(configBackup, configDest);
|
|
10591
10428
|
}
|
|
10592
10429
|
clearGuard(projectRoot);
|
|
@@ -10614,13 +10451,13 @@ async function migrateAction(options) {
|
|
|
10614
10451
|
return;
|
|
10615
10452
|
}
|
|
10616
10453
|
const guard = guardPath(projectRoot);
|
|
10617
|
-
if (
|
|
10454
|
+
if (existsSync21(guard)) {
|
|
10618
10455
|
console.log(chalk28.yellow("A migration is already in progress."));
|
|
10619
10456
|
console.log(chalk28.dim("Run `coherent migrate --rollback` to undo, or delete .coherent/migration-in-progress"));
|
|
10620
10457
|
return;
|
|
10621
10458
|
}
|
|
10622
10459
|
const uiDir = join17(projectRoot, "components", "ui");
|
|
10623
|
-
if (!
|
|
10460
|
+
if (!existsSync21(uiDir)) {
|
|
10624
10461
|
console.log(chalk28.yellow("No components/ui directory found. Nothing to migrate."));
|
|
10625
10462
|
return;
|
|
10626
10463
|
}
|
|
@@ -10647,7 +10484,7 @@ Found ${migratable.length} component(s) to migrate:`));
|
|
|
10647
10484
|
try {
|
|
10648
10485
|
for (const id of migratable) {
|
|
10649
10486
|
const filePath = join17(uiDir, `${id}.tsx`);
|
|
10650
|
-
if (
|
|
10487
|
+
if (existsSync21(filePath)) rmSync6(filePath);
|
|
10651
10488
|
}
|
|
10652
10489
|
const results = await provider.installBatch(migratable, projectRoot, { force: true });
|
|
10653
10490
|
let migrated = 0;
|
|
@@ -10669,7 +10506,7 @@ Found ${migratable.length} component(s) to migrate:`));
|
|
|
10669
10506
|
}
|
|
10670
10507
|
|
|
10671
10508
|
// src/utils/update-notifier.ts
|
|
10672
|
-
import { existsSync as
|
|
10509
|
+
import { existsSync as existsSync22, mkdirSync as mkdirSync9, readFileSync as readFileSync16, writeFileSync as writeFileSync12 } from "fs";
|
|
10673
10510
|
import { join as join18 } from "path";
|
|
10674
10511
|
import { homedir } from "os";
|
|
10675
10512
|
import chalk29 from "chalk";
|
|
@@ -10681,8 +10518,8 @@ var CACHE_FILE = join18(CACHE_DIR, "update-check.json");
|
|
|
10681
10518
|
var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
10682
10519
|
function readCache() {
|
|
10683
10520
|
try {
|
|
10684
|
-
if (!
|
|
10685
|
-
const raw =
|
|
10521
|
+
if (!existsSync22(CACHE_FILE)) return null;
|
|
10522
|
+
const raw = readFileSync16(CACHE_FILE, "utf-8");
|
|
10686
10523
|
return JSON.parse(raw);
|
|
10687
10524
|
} catch (e) {
|
|
10688
10525
|
if (DEBUG5) console.error("Failed to read update cache:", e);
|
|
@@ -10691,8 +10528,8 @@ function readCache() {
|
|
|
10691
10528
|
}
|
|
10692
10529
|
function writeCache(data) {
|
|
10693
10530
|
try {
|
|
10694
|
-
if (!
|
|
10695
|
-
|
|
10531
|
+
if (!existsSync22(CACHE_DIR)) mkdirSync9(CACHE_DIR, { recursive: true });
|
|
10532
|
+
writeFileSync12(CACHE_FILE, JSON.stringify(data), "utf-8");
|
|
10696
10533
|
} catch (e) {
|
|
10697
10534
|
if (DEBUG5) console.error("Failed to write update cache:", e);
|
|
10698
10535
|
}
|