@getcoherent/cli 0.6.46 → 0.6.47

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.
@@ -0,0 +1,50 @@
1
+ // src/commands/fix-validation.ts
2
+ import { createRequire } from "module";
3
+ import { existsSync, readFileSync, writeFileSync } from "fs";
4
+ import { join } from "path";
5
+ var cachedTs = null;
6
+ var cachedProjectRoot = null;
7
+ function isValidTsx(code, projectRoot, ext = ".tsx") {
8
+ if (ext !== ".tsx" && ext !== ".ts") return true;
9
+ const pkgJson = join(projectRoot, "package.json");
10
+ if (!existsSync(pkgJson)) return true;
11
+ try {
12
+ if (!cachedTs || cachedProjectRoot !== projectRoot) {
13
+ const req = createRequire(pkgJson);
14
+ cachedTs = req("typescript");
15
+ cachedProjectRoot = projectRoot;
16
+ }
17
+ const sf = cachedTs.createSourceFile(
18
+ "check.tsx",
19
+ code,
20
+ cachedTs.ScriptTarget.Latest,
21
+ false,
22
+ cachedTs.ScriptKind.TSX
23
+ );
24
+ const diagnostics = sf.parseDiagnostics;
25
+ return !diagnostics || diagnostics.length === 0;
26
+ } catch {
27
+ return true;
28
+ }
29
+ }
30
+ function safeWrite(filePath, newContent, projectRoot, backups) {
31
+ if (!backups.has(filePath)) {
32
+ try {
33
+ backups.set(filePath, readFileSync(filePath, "utf-8"));
34
+ } catch {
35
+ }
36
+ }
37
+ const ext = filePath.slice(filePath.lastIndexOf("."));
38
+ writeFileSync(filePath, newContent, "utf-8");
39
+ if (!isValidTsx(newContent, projectRoot, ext)) {
40
+ const original = backups.get(filePath);
41
+ if (original) writeFileSync(filePath, original, "utf-8");
42
+ return { ok: false };
43
+ }
44
+ return { ok: true };
45
+ }
46
+
47
+ export {
48
+ isValidTsx,
49
+ safeWrite
50
+ };
@@ -0,0 +1,260 @@
1
+ import {
2
+ safeWrite
3
+ } from "./chunk-U6M76BKY.js";
4
+
5
+ // src/utils/tsc-autofix.ts
6
+ import { existsSync, readFileSync } from "fs";
7
+ import { execSync } from "child_process";
8
+ import { resolve } from "path";
9
+
10
+ // src/utils/tsc-error-parser.ts
11
+ var ERROR_RE = /^(.+?)\((\d+),(\d+)\): error (TS\d+): (.+)$/;
12
+ var RELATED_LOCATION_RE = /^(.+?)\((\d+),(\d+)\):\s/;
13
+ function parseTscOutput(output) {
14
+ const lines = output.split("\n");
15
+ const errors = [];
16
+ const seen = /* @__PURE__ */ new Set();
17
+ let current = null;
18
+ for (const raw of lines) {
19
+ const trimmed = raw.trimStart();
20
+ const match = trimmed.match(ERROR_RE);
21
+ if (match) {
22
+ const [, file, lineStr, colStr, code, msg] = match;
23
+ const isRelated = raw.startsWith(" ");
24
+ if (isRelated && current) {
25
+ const cleanFile = file.trim();
26
+ if (!current.relatedFiles.includes(cleanFile)) {
27
+ current.relatedFiles.push(cleanFile);
28
+ }
29
+ } else {
30
+ flushCurrent();
31
+ current = {
32
+ file: file.trim(),
33
+ line: parseInt(lineStr, 10),
34
+ col: parseInt(colStr, 10),
35
+ code,
36
+ message: msg,
37
+ relatedFiles: []
38
+ };
39
+ }
40
+ } else if (current && raw.startsWith(" ") && raw.trim().length > 0) {
41
+ const locMatch = trimmed.match(RELATED_LOCATION_RE);
42
+ if (locMatch) {
43
+ const cleanFile = locMatch[1].trim();
44
+ if (!current.relatedFiles.includes(cleanFile)) {
45
+ current.relatedFiles.push(cleanFile);
46
+ }
47
+ } else {
48
+ current.message += "\n" + raw.trim();
49
+ }
50
+ }
51
+ }
52
+ flushCurrent();
53
+ return errors;
54
+ function flushCurrent() {
55
+ if (!current) return;
56
+ const key = `${current.file}:${current.line}:${current.code}`;
57
+ if (!seen.has(key)) {
58
+ seen.add(key);
59
+ errors.push(current);
60
+ }
61
+ current = null;
62
+ }
63
+ }
64
+
65
+ // src/utils/tsc-autofix.ts
66
+ function runTscCheck(projectRoot, timeout = 3e4) {
67
+ const tsconfigPath = resolve(projectRoot, "tsconfig.json");
68
+ if (!existsSync(tsconfigPath)) return [];
69
+ try {
70
+ execSync("npx tsc --noEmit 2>&1", {
71
+ cwd: projectRoot,
72
+ timeout,
73
+ encoding: "utf-8"
74
+ });
75
+ return [];
76
+ } catch (err) {
77
+ if (err && typeof err === "object" && "killed" in err && err.killed) {
78
+ console.log(" \u26A0 TypeScript check timed out \u2014 skipping");
79
+ return [];
80
+ }
81
+ const e = err;
82
+ const output = (e.stdout || "") + (e.stderr || "");
83
+ return parseTscOutput(output);
84
+ }
85
+ }
86
+ function levenshtein(a, b) {
87
+ const m = a.length, n = b.length;
88
+ const dp = Array.from(
89
+ { length: m + 1 },
90
+ (_, i) => Array.from({ length: n + 1 }, (_2, j) => i === 0 ? j : j === 0 ? i : 0)
91
+ );
92
+ for (let i = 1; i <= m; i++)
93
+ for (let j = 1; j <= n; j++)
94
+ dp[i][j] = a[i - 1] === b[j - 1] ? dp[i - 1][j - 1] : 1 + Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]);
95
+ return dp[m][n];
96
+ }
97
+ function maxLevenshtein(fieldName) {
98
+ return Math.max(1, Math.floor(fieldName.length * 0.4));
99
+ }
100
+ function escapeRegExp(s) {
101
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
102
+ }
103
+ var MISSING_PROP_RE = /Property '(\w+)' is missing in type '\{([^}]*)\}'/;
104
+ var UNION_RE = /Type 'string' is not assignable to type '((?:"[^"]+"\s*\|\s*)*"[^"]+")'/;
105
+ var MISSING_REQUIRED_RE = /Property '(\w+)' is missing in type .* but required/;
106
+ function extractFieldsFromCode(code, line) {
107
+ const lines = code.split("\n");
108
+ const searchRange = lines.slice(Math.max(0, line - 3), line + 3).join(" ");
109
+ const fieldMatches = searchRange.match(/(\w+)\s*:/g);
110
+ if (!fieldMatches) return [];
111
+ return fieldMatches.map((m) => m.replace(/\s*:$/, ""));
112
+ }
113
+ function fixFieldRename(code, error, errorLine) {
114
+ const match = error.message.match(MISSING_PROP_RE);
115
+ const expectedField = match?.[1] ?? error.message.match(/Property '(\w+)' is missing/)?.[1];
116
+ if (!expectedField) return null;
117
+ let typeFields;
118
+ if (match?.[2]) {
119
+ typeFields = match[2].split(";").map((f) => f.trim().split(":")[0]?.trim()).filter(Boolean);
120
+ } else {
121
+ typeFields = extractFieldsFromCode(code, errorLine ?? error.line);
122
+ }
123
+ let bestMatch = null;
124
+ let bestDist = Infinity;
125
+ for (const field of typeFields) {
126
+ if (field === expectedField) continue;
127
+ if (field.includes(expectedField) || expectedField.includes(field)) {
128
+ bestMatch = field;
129
+ bestDist = 0;
130
+ break;
131
+ }
132
+ const dist = levenshtein(field.toLowerCase(), expectedField.toLowerCase());
133
+ if (dist <= maxLevenshtein(expectedField) && dist < bestDist) {
134
+ bestDist = dist;
135
+ bestMatch = field;
136
+ }
137
+ }
138
+ if (!bestMatch) return null;
139
+ const targetLine = errorLine ?? error.line;
140
+ const lines = code.split("\n");
141
+ const targetIdx = targetLine - 1;
142
+ const windowStart = Math.max(0, targetIdx - 5);
143
+ const windowEnd = Math.min(lines.length, targetIdx + 6);
144
+ const fieldRe = new RegExp(`(\\b)${escapeRegExp(bestMatch)}(\\s*:)`, "g");
145
+ for (let i = windowStart; i < windowEnd; i++) {
146
+ if (fieldRe.test(lines[i])) {
147
+ lines[i] = lines[i].replace(fieldRe, `$1${expectedField}$2`);
148
+ }
149
+ fieldRe.lastIndex = 0;
150
+ }
151
+ const newCode = lines.join("\n");
152
+ if (newCode === code) return null;
153
+ return { code: newCode, field: `${bestMatch} \u2192 ${expectedField}` };
154
+ }
155
+ function fixUnionType(code, error) {
156
+ const match = error.message.match(UNION_RE);
157
+ if (!match) return null;
158
+ const variants = match[1].match(/"([^"]+)"/g)?.map((v) => v.replace(/"/g, ""));
159
+ if (!variants || variants.length === 0) return null;
160
+ const lines = code.split("\n");
161
+ const errorLine = lines[error.line - 1];
162
+ if (!errorLine) return null;
163
+ for (const variant of variants) {
164
+ const caseInsensitiveRe = new RegExp(`['"]${escapeRegExp(variant)}['"]`, "i");
165
+ const exactRe = new RegExp(`['"]${escapeRegExp(variant)}['"]`);
166
+ if (caseInsensitiveRe.test(errorLine) && !exactRe.test(errorLine)) {
167
+ lines[error.line - 1] = errorLine.replace(caseInsensitiveRe, `'${variant}'`);
168
+ return { code: lines.join("\n"), fix: `union case: '${variant}'` };
169
+ }
170
+ }
171
+ return null;
172
+ }
173
+ function fixMissingEventHandler(code, error) {
174
+ const match = error.message.match(MISSING_REQUIRED_RE);
175
+ if (!match) return null;
176
+ const propName = match[1];
177
+ if (!propName.startsWith("on") || propName.length < 3) return null;
178
+ if (propName[2] !== propName[2].toUpperCase()) return null;
179
+ const lines = code.split("\n");
180
+ const errorLine = lines[error.line - 1];
181
+ if (!errorLine) return null;
182
+ const closingMatch = errorLine.match(/(\s*\/?>)/);
183
+ if (!closingMatch) return null;
184
+ const insertPos = errorLine.lastIndexOf(closingMatch[1]);
185
+ lines[error.line - 1] = errorLine.slice(0, insertPos) + ` ${propName}={() => {}}` + errorLine.slice(insertPos);
186
+ return { code: lines.join("\n"), prop: propName };
187
+ }
188
+ function deduplicateErrors(errors) {
189
+ const seen = /* @__PURE__ */ new Set();
190
+ return errors.filter((e) => {
191
+ const key = `${e.file}:${e.line}:${e.code}`;
192
+ if (seen.has(key)) return false;
193
+ seen.add(key);
194
+ return true;
195
+ });
196
+ }
197
+ async function applyDeterministicFixes(errors, projectRoot, backups) {
198
+ const deduped = deduplicateErrors(errors);
199
+ const fixed = [];
200
+ const remaining = [];
201
+ const fileErrors = /* @__PURE__ */ new Map();
202
+ for (const err of deduped) {
203
+ const list = fileErrors.get(err.file) || [];
204
+ list.push(err);
205
+ fileErrors.set(err.file, list);
206
+ }
207
+ for (const [file, errs] of fileErrors) {
208
+ const absPath = resolve(projectRoot, file);
209
+ let code;
210
+ try {
211
+ code = readFileSync(absPath, "utf-8");
212
+ } catch {
213
+ remaining.push(...errs);
214
+ continue;
215
+ }
216
+ let changed = false;
217
+ const fileRemaining = [];
218
+ for (const e of errs) {
219
+ const renameResult = fixFieldRename(code, e, e.line);
220
+ if (renameResult) {
221
+ code = renameResult.code;
222
+ changed = true;
223
+ continue;
224
+ }
225
+ const unionResult = fixUnionType(code, e);
226
+ if (unionResult) {
227
+ code = unionResult.code;
228
+ changed = true;
229
+ continue;
230
+ }
231
+ const handlerResult = fixMissingEventHandler(code, e);
232
+ if (handlerResult) {
233
+ code = handlerResult.code;
234
+ changed = true;
235
+ continue;
236
+ }
237
+ fileRemaining.push(e);
238
+ }
239
+ if (changed) {
240
+ const { ok } = safeWrite(absPath, code, projectRoot, backups);
241
+ if (ok) {
242
+ fixed.push(file);
243
+ remaining.push(...fileRemaining);
244
+ } else {
245
+ remaining.push(...errs);
246
+ }
247
+ } else {
248
+ remaining.push(...fileRemaining);
249
+ }
250
+ }
251
+ return { fixed, remaining };
252
+ }
253
+
254
+ export {
255
+ runTscCheck,
256
+ fixFieldRename,
257
+ fixUnionType,
258
+ fixMissingEventHandler,
259
+ applyDeterministicFixes
260
+ };
package/dist/index.js CHANGED
@@ -53,6 +53,10 @@ import {
53
53
  savePlan,
54
54
  updateArchitecturePlan
55
55
  } from "./chunk-VLBVBF6V.js";
56
+ import {
57
+ isValidTsx,
58
+ safeWrite
59
+ } from "./chunk-U6M76BKY.js";
56
60
  import {
57
61
  toKebabCase,
58
62
  toTitleCase
@@ -5018,6 +5022,70 @@ async function applyModification(request, dsm, cm, pm, projectRoot, aiProvider,
5018
5022
  allFixes.forEach((f) => console.log(chalk8.dim(` ${f}`)));
5019
5023
  }
5020
5024
  await writeFile(filePath, codeToWrite);
5025
+ try {
5026
+ const { runTscCheck, applyDeterministicFixes } = await import("./tsc-autofix-S5PKMFSC.js");
5027
+ const tscBackups = /* @__PURE__ */ new Map();
5028
+ const relPath = filePath.replace(projectRoot + "/", "").replace(projectRoot + "\\", "");
5029
+ const tscErrors = runTscCheck(projectRoot).filter((e) => e.file === relPath);
5030
+ if (tscErrors.length > 0) {
5031
+ const bestSnapshot = codeToWrite;
5032
+ const detResult = await applyDeterministicFixes(tscErrors, projectRoot, tscBackups);
5033
+ let bestErrorCount = Math.min(tscErrors.length, tscErrors.length - detResult.fixed.length);
5034
+ if (detResult.fixed.length > 0) {
5035
+ codeToWrite = await readFile(filePath);
5036
+ console.log(
5037
+ chalk8.green(` \u2714 Fixed ${tscErrors.length - detResult.remaining.length} TypeScript error(s)`)
5038
+ );
5039
+ }
5040
+ if (detResult.remaining.length > 0 && aiProvider) {
5041
+ try {
5042
+ const ai = await createAIProvider(aiProvider);
5043
+ if (ai.editPageCode) {
5044
+ const errorList = detResult.remaining.map((e) => `Line ${e.line}: [${e.code}] ${e.message.split("\n")[0]}`).join("\n");
5045
+ const tscFixed = await ai.editPageCode(
5046
+ codeToWrite,
5047
+ `Fix these TypeScript errors:
5048
+ ${errorList}
5049
+
5050
+ Keep all existing functionality intact.`,
5051
+ page.name || page.id || "Page"
5052
+ );
5053
+ if (tscFixed && tscFixed.length > 100) {
5054
+ const { code: reFixed } = await autoFixCode(tscFixed, autoFixCtx);
5055
+ await writeFile(filePath, reFixed);
5056
+ const afterErrors = runTscCheck(projectRoot).filter((e) => e.file === relPath);
5057
+ if (afterErrors.length > bestErrorCount) {
5058
+ await writeFile(filePath, bestSnapshot);
5059
+ codeToWrite = bestSnapshot;
5060
+ console.log(
5061
+ chalk8.yellow(` \u26A0 AI fix regressed TypeScript errors. Reverted to best version.`)
5062
+ );
5063
+ } else {
5064
+ codeToWrite = reFixed;
5065
+ console.log(
5066
+ chalk8.green(
5067
+ ` \u2714 Fixed ${detResult.remaining.length - afterErrors.length} TypeScript error(s) via AI`
5068
+ )
5069
+ );
5070
+ }
5071
+ }
5072
+ }
5073
+ } catch (tscAiErr) {
5074
+ console.log(
5075
+ chalk8.dim(
5076
+ ` \u26A0 AI tsc fix skipped: ${tscAiErr instanceof Error ? tscAiErr.message : "unknown"}`
5077
+ )
5078
+ );
5079
+ }
5080
+ }
5081
+ }
5082
+ } catch (tscErr) {
5083
+ console.log(
5084
+ chalk8.dim(
5085
+ ` \u26A0 TypeScript check skipped: ${tscErr instanceof Error ? tscErr.message : "unknown"}`
5086
+ )
5087
+ );
5088
+ }
5021
5089
  const pageIdx = dsm.getConfig().pages.findIndex((p) => p.id === page.id);
5022
5090
  if (pageIdx !== -1) {
5023
5091
  const cfg = dsm.getConfig();
@@ -8084,8 +8152,8 @@ async function regenerateDocsCommand() {
8084
8152
 
8085
8153
  // src/commands/fix.ts
8086
8154
  import chalk15 from "chalk";
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";
8155
+ import { readdirSync as readdirSync7, readFileSync as readFileSync10, existsSync as existsSync14, rmSync as rmSync5, mkdirSync as mkdirSync7 } from "fs";
8156
+ import { resolve as resolve8, join as join11, relative as relative5, basename as basename3 } from "path";
8089
8157
  import {
8090
8158
  DesignSystemManager as DesignSystemManager9,
8091
8159
  ComponentManager as ComponentManager5,
@@ -8094,54 +8162,6 @@ import {
8094
8162
  loadManifest as loadManifest9,
8095
8163
  saveManifest as saveManifest5
8096
8164
  } from "@getcoherent/core";
8097
-
8098
- // src/commands/fix-validation.ts
8099
- import { createRequire } from "module";
8100
- import { existsSync as existsSync14, readFileSync as readFileSync10, writeFileSync as writeFileSync9 } from "fs";
8101
- import { join as join11 } from "path";
8102
- var cachedTs = null;
8103
- var cachedProjectRoot = null;
8104
- function isValidTsx(code, projectRoot, ext = ".tsx") {
8105
- if (ext !== ".tsx" && ext !== ".ts") return true;
8106
- const pkgJson = join11(projectRoot, "package.json");
8107
- if (!existsSync14(pkgJson)) return true;
8108
- try {
8109
- if (!cachedTs || cachedProjectRoot !== projectRoot) {
8110
- const req = createRequire(pkgJson);
8111
- cachedTs = req("typescript");
8112
- cachedProjectRoot = projectRoot;
8113
- }
8114
- const sf = cachedTs.createSourceFile(
8115
- "check.tsx",
8116
- code,
8117
- cachedTs.ScriptTarget.Latest,
8118
- false,
8119
- cachedTs.ScriptKind.TSX
8120
- );
8121
- const diagnostics = sf.parseDiagnostics;
8122
- return !diagnostics || diagnostics.length === 0;
8123
- } catch {
8124
- return true;
8125
- }
8126
- }
8127
- function safeWrite(filePath, newContent, projectRoot, backups) {
8128
- if (!backups.has(filePath)) {
8129
- try {
8130
- backups.set(filePath, readFileSync10(filePath, "utf-8"));
8131
- } catch {
8132
- }
8133
- }
8134
- const ext = filePath.slice(filePath.lastIndexOf("."));
8135
- writeFileSync9(filePath, newContent, "utf-8");
8136
- if (!isValidTsx(newContent, projectRoot, ext)) {
8137
- const original = backups.get(filePath);
8138
- if (original) writeFileSync9(filePath, original, "utf-8");
8139
- return { ok: false };
8140
- }
8141
- return { ok: true };
8142
- }
8143
-
8144
- // src/commands/fix.ts
8145
8165
  function extractComponentIdsFromCode2(code) {
8146
8166
  const ids = /* @__PURE__ */ new Set();
8147
8167
  const allMatches = code.matchAll(/@\/components\/((?:ui\/)?[a-z0-9-]+)/g);
@@ -8159,7 +8179,7 @@ function listTsxFiles(dir) {
8159
8179
  try {
8160
8180
  const entries = readdirSync7(dir, { withFileTypes: true });
8161
8181
  for (const e of entries) {
8162
- const full = join12(dir, e.name);
8182
+ const full = join11(dir, e.name);
8163
8183
  if (e.isDirectory() && e.name !== "node_modules" && !e.name.startsWith(".")) {
8164
8184
  files.push(...listTsxFiles(full));
8165
8185
  } else if (e.isFile() && e.name.endsWith(".tsx")) {
@@ -8190,8 +8210,8 @@ async function fixCommand(opts = {}) {
8190
8210
  console.log(chalk15.cyan("\ncoherent fix\n"));
8191
8211
  }
8192
8212
  if (!skipCache) {
8193
- const nextDir = join12(projectRoot, ".next");
8194
- if (existsSync15(nextDir)) {
8213
+ const nextDir = join11(projectRoot, ".next");
8214
+ if (existsSync14(nextDir)) {
8195
8215
  if (!dryRun) rmSync5(nextDir, { recursive: true, force: true });
8196
8216
  fixes.push("Cleared build cache");
8197
8217
  console.log(chalk15.green(" \u2714 Cleared build cache"));
@@ -8218,7 +8238,7 @@ async function fixCommand(opts = {}) {
8218
8238
  const componentsTsxFiles = listTsxFiles(resolve8(projectRoot, "components"));
8219
8239
  const allComponentIds = /* @__PURE__ */ new Set();
8220
8240
  for (const file of [...allTsxFiles, ...componentsTsxFiles]) {
8221
- const content = readFileSync11(file, "utf-8");
8241
+ const content = readFileSync10(file, "utf-8");
8222
8242
  extractComponentIdsFromCode2(content).forEach((id) => allComponentIds.add(id));
8223
8243
  }
8224
8244
  let dsm = null;
@@ -8238,7 +8258,7 @@ async function fixCommand(opts = {}) {
8238
8258
  } else {
8239
8259
  const fileName = toKebabCase(id) + ".tsx";
8240
8260
  const filePath = resolve8(projectRoot, "components", "ui", fileName);
8241
- if (!existsSync15(filePath)) missingFiles.push(id);
8261
+ if (!existsSync14(filePath)) missingFiles.push(id);
8242
8262
  }
8243
8263
  }
8244
8264
  const provider = getComponentProvider();
@@ -8287,7 +8307,7 @@ async function fixCommand(opts = {}) {
8287
8307
  }
8288
8308
  }
8289
8309
  }
8290
- if (!dsm && existsSync15(project.configPath)) {
8310
+ if (!dsm && existsSync14(project.configPath)) {
8291
8311
  dsm = new DesignSystemManager9(project.configPath);
8292
8312
  await dsm.load();
8293
8313
  }
@@ -8296,8 +8316,8 @@ async function fixCommand(opts = {}) {
8296
8316
  let derivedName = null;
8297
8317
  try {
8298
8318
  const pkgPath = resolve8(projectRoot, "package.json");
8299
- if (existsSync15(pkgPath)) {
8300
- const pkg = JSON.parse(readFileSync11(pkgPath, "utf-8"));
8319
+ if (existsSync14(pkgPath)) {
8320
+ const pkg = JSON.parse(readFileSync10(pkgPath, "utf-8"));
8301
8321
  if (typeof pkg.name === "string" && pkg.name) {
8302
8322
  derivedName = toTitleCase2(pkg.name);
8303
8323
  }
@@ -8334,8 +8354,8 @@ async function fixCommand(opts = {}) {
8334
8354
  const configName = dsm.getConfig().name;
8335
8355
  if (configName && configName !== "My App") {
8336
8356
  const appLayoutPath = resolve8(projectRoot, "app", "(app)", "layout.tsx");
8337
- if (existsSync15(appLayoutPath)) {
8338
- let appLayoutCode = readFileSync11(appLayoutPath, "utf-8");
8357
+ if (existsSync14(appLayoutPath)) {
8358
+ let appLayoutCode = readFileSync10(appLayoutPath, "utf-8");
8339
8359
  if (appLayoutCode.includes("My App")) {
8340
8360
  appLayoutCode = appLayoutCode.replace(/My App/g, configName);
8341
8361
  if (!dryRun) {
@@ -8353,11 +8373,11 @@ async function fixCommand(opts = {}) {
8353
8373
  }
8354
8374
  }
8355
8375
  const sharedDir = resolve8(projectRoot, "components", "shared");
8356
- if (existsSync15(sharedDir)) {
8376
+ if (existsSync14(sharedDir)) {
8357
8377
  try {
8358
8378
  for (const f of readdirSync7(sharedDir).filter((n) => n.endsWith(".tsx"))) {
8359
- const sharedPath = join12(sharedDir, f);
8360
- const sharedCode = readFileSync11(sharedPath, "utf-8");
8379
+ const sharedPath = join11(sharedDir, f);
8380
+ const sharedCode = readFileSync10(sharedPath, "utf-8");
8361
8381
  if (sharedCode.includes("My App")) {
8362
8382
  const updated = sharedCode.replace(/My App/g, configName);
8363
8383
  if (!dryRun) {
@@ -8381,7 +8401,7 @@ async function fixCommand(opts = {}) {
8381
8401
  let syntaxFixed = 0;
8382
8402
  for (const file of userTsxFiles) {
8383
8403
  try {
8384
- const content = readFileSync11(file, "utf-8");
8404
+ const content = readFileSync10(file, "utf-8");
8385
8405
  const fixed = fixUnescapedLtInJsx(
8386
8406
  fixEscapedClosingQuotes(sanitizeMetadataStrings(ensureUseClientIfNeeded(content)))
8387
8407
  );
@@ -8424,7 +8444,7 @@ async function fixCommand(opts = {}) {
8424
8444
  console.log(chalk15.green(` \u2714 Verified group layouts: ${layoutTypes}`));
8425
8445
  const hasSidebar = plan.groups.some((g) => g.layout === "sidebar" || g.layout === "both");
8426
8446
  const sidebarPath = resolve8(projectRoot, "components", "shared", "sidebar.tsx");
8427
- if (hasSidebar && !existsSync15(sidebarPath) && !dryRun) {
8447
+ if (hasSidebar && !existsSync14(sidebarPath) && !dryRun) {
8428
8448
  if (!dsm) {
8429
8449
  dsm = new DesignSystemManager9(project.configPath);
8430
8450
  await dsm.load();
@@ -8443,8 +8463,8 @@ async function fixCommand(opts = {}) {
8443
8463
  }
8444
8464
  if (hasSidebar && !dryRun) {
8445
8465
  const rootLayoutPath = resolve8(projectRoot, "app", "layout.tsx");
8446
- if (existsSync15(rootLayoutPath)) {
8447
- let rootCode = readFileSync11(rootLayoutPath, "utf-8");
8466
+ if (existsSync14(rootLayoutPath)) {
8467
+ let rootCode = readFileSync10(rootLayoutPath, "utf-8");
8448
8468
  if (rootCode.includes("<Header")) {
8449
8469
  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) => {
8450
8470
  const inner = match.replace(/<\/?ShowWhenNotAuthRoute>/g, "").trim();
@@ -8462,8 +8482,8 @@ async function fixCommand(opts = {}) {
8462
8482
  }
8463
8483
  }
8464
8484
  const publicLayoutPath = resolve8(projectRoot, "app", "(public)", "layout.tsx");
8465
- const publicExists = existsSync15(publicLayoutPath);
8466
- const needsPublicLayout = !publicExists || !readFileSync11(publicLayoutPath, "utf-8").includes("<Header");
8485
+ const publicExists = existsSync14(publicLayoutPath);
8486
+ const needsPublicLayout = !publicExists || !readFileSync10(publicLayoutPath, "utf-8").includes("<Header");
8467
8487
  if (needsPublicLayout) {
8468
8488
  const { buildPublicLayoutCodeForSidebar } = await import("./code-generator-YSGVHVNN.js");
8469
8489
  mkdirSync7(resolve8(projectRoot, "app", "(public)"), { recursive: true });
@@ -8476,8 +8496,8 @@ async function fixCommand(opts = {}) {
8476
8496
  }
8477
8497
  }
8478
8498
  const sidebarComponentPath2 = resolve8(projectRoot, "components", "shared", "sidebar.tsx");
8479
- if (existsSync15(sidebarComponentPath2)) {
8480
- const existingSidebarCode = readFileSync11(sidebarComponentPath2, "utf-8");
8499
+ if (existsSync14(sidebarComponentPath2)) {
8500
+ const existingSidebarCode = readFileSync10(sidebarComponentPath2, "utf-8");
8481
8501
  const sidebarConfigName = dsm?.getConfig().name ?? "";
8482
8502
  const hasWrongName = existingSidebarCode.includes("My App") && sidebarConfigName !== "My App";
8483
8503
  const hasTrigger = existingSidebarCode.includes("SidebarTrigger");
@@ -8505,7 +8525,7 @@ async function fixCommand(opts = {}) {
8505
8525
  }
8506
8526
  const rootPagePath = resolve8(projectRoot, "app", "page.tsx");
8507
8527
  const publicPagePath = resolve8(projectRoot, "app", "(public)", "page.tsx");
8508
- if (existsSync15(rootPagePath) && !existsSync15(publicPagePath)) {
8528
+ if (existsSync14(rootPagePath) && !existsSync14(publicPagePath)) {
8509
8529
  const { renameSync } = await import("fs");
8510
8530
  mkdirSync7(resolve8(projectRoot, "app", "(public)"), { recursive: true });
8511
8531
  renameSync(rootPagePath, publicPagePath);
@@ -8513,7 +8533,7 @@ async function fixCommand(opts = {}) {
8513
8533
  console.log(chalk15.green(" \u2714 Moved app/page.tsx \u2192 app/(public)/page.tsx (gets Header/Footer)"));
8514
8534
  }
8515
8535
  const themeTogglePath = resolve8(projectRoot, "components", "shared", "theme-toggle.tsx");
8516
- if (!existsSync15(themeTogglePath)) {
8536
+ if (!existsSync14(themeTogglePath)) {
8517
8537
  const { generateThemeToggleCode } = await import("./code-generator-YSGVHVNN.js");
8518
8538
  mkdirSync7(resolve8(projectRoot, "components", "shared"), { recursive: true });
8519
8539
  const themeResult = safeWrite(themeTogglePath, generateThemeToggleCode(), projectRoot, backups);
@@ -8530,8 +8550,8 @@ async function fixCommand(opts = {}) {
8530
8550
  console.log(chalk15.yellow(` \u26A0 Layout repair skipped: ${err instanceof Error ? err.message : "unknown error"}`));
8531
8551
  }
8532
8552
  const appLayoutRepairPath = resolve8(projectRoot, "app", "(app)", "layout.tsx");
8533
- if (existsSync15(appLayoutRepairPath) && dsm) {
8534
- const appLayoutCode = readFileSync11(appLayoutRepairPath, "utf-8");
8553
+ if (existsSync14(appLayoutRepairPath) && dsm) {
8554
+ const appLayoutCode = readFileSync10(appLayoutRepairPath, "utf-8");
8535
8555
  const isMinimal = appLayoutCode.length < 500 && !appLayoutCode.includes("Header") && !appLayoutCode.includes("Footer") && !appLayoutCode.includes("Sidebar") && !appLayoutCode.includes("SidebarProvider") && !appLayoutCode.includes("SidebarTrigger") && !appLayoutCode.includes("Sheet");
8536
8556
  const navType = dsm.getConfig().navigation?.type || "header";
8537
8557
  if (isMinimal && navType !== "none") {
@@ -8559,7 +8579,7 @@ async function fixCommand(opts = {}) {
8559
8579
  const qualityFixDetails = [];
8560
8580
  for (const file of allValidationFiles) {
8561
8581
  try {
8562
- const content = readFileSync11(file, "utf-8");
8582
+ const content = readFileSync10(file, "utf-8");
8563
8583
  const { code: autoFixed, fixes: fileFixes } = await autoFixCode(content);
8564
8584
  if (autoFixed !== content) {
8565
8585
  if (!dryRun) {
@@ -8594,7 +8614,7 @@ async function fixCommand(opts = {}) {
8594
8614
  let mockFixed = 0;
8595
8615
  for (const file of allValidationFiles) {
8596
8616
  try {
8597
- const content = readFileSync11(file, "utf-8");
8617
+ const content = readFileSync10(file, "utf-8");
8598
8618
  const mockIssues = validateMockData(content);
8599
8619
  if (mockIssues.length > 0) {
8600
8620
  const fixed = applyMockDataFixes(content, mockIssues);
@@ -8625,7 +8645,7 @@ async function fixCommand(opts = {}) {
8625
8645
  for (const file of modifiedFiles) {
8626
8646
  if (!backups.has(file)) continue;
8627
8647
  const before = backups.get(file);
8628
- const after = readFileSync11(file, "utf-8");
8648
+ const after = readFileSync10(file, "utf-8");
8629
8649
  const issues = verifyIncrementalEdit(before, after);
8630
8650
  if (issues.length > 0) {
8631
8651
  for (const issue of issues) {
@@ -8638,7 +8658,7 @@ async function fixCommand(opts = {}) {
8638
8658
  const fileIssues = [];
8639
8659
  for (const file of allValidationFiles) {
8640
8660
  try {
8641
- const code = readFileSync11(file, "utf-8");
8661
+ const code = readFileSync10(file, "utf-8");
8642
8662
  const relativePath = file.replace(projectRoot + "/", "");
8643
8663
  const baseName = file.split("/").pop() || "";
8644
8664
  const isAuthPage = relativePath.includes("(auth)");
@@ -8748,26 +8768,66 @@ async function fixCommand(opts = {}) {
8748
8768
  }
8749
8769
  try {
8750
8770
  const tsconfigPath = resolve8(projectRoot, "tsconfig.json");
8751
- if (existsSync15(tsconfigPath)) {
8752
- const { execSync: execSync2 } = await import("child_process");
8753
- execSync2("npx tsc --noEmit 2>&1", {
8754
- cwd: projectRoot,
8755
- timeout: 3e4,
8756
- encoding: "utf-8"
8757
- });
8758
- fixes.push("TypeScript compilation clean");
8759
- console.log(chalk15.green(" \u2714 TypeScript compilation clean"));
8760
- }
8761
- } catch (err) {
8762
- const output = (err.stdout || "") + (err.stderr || "");
8763
- const errorLines = output.split("\n").filter((l) => l.includes("error TS"));
8764
- if (errorLines.length > 0) {
8765
- for (const line of errorLines.slice(0, 10)) {
8766
- remaining.push(line.trim());
8771
+ if (existsSync14(tsconfigPath)) {
8772
+ const { runTscCheck, applyDeterministicFixes } = await import("./tsc-autofix-S5PKMFSC.js");
8773
+ const { applyAiFixes } = await import("./tsc-ai-fix-O3EMRWV2.js");
8774
+ const tscErrors = runTscCheck(projectRoot);
8775
+ if (tscErrors.length === 0) {
8776
+ fixes.push("TypeScript compilation clean");
8777
+ console.log(chalk15.green(" \u2714 TypeScript compilation clean"));
8778
+ } else {
8779
+ const detResult = await applyDeterministicFixes(tscErrors, projectRoot, backups);
8780
+ if (detResult.fixed.length > 0) {
8781
+ fixes.push(`TypeScript: fixed ${detResult.fixed.length} file(s) deterministically`);
8782
+ console.log(chalk15.green(` \u2714 TypeScript: fixed ${detResult.fixed.length} file(s) deterministically`));
8783
+ }
8784
+ if (detResult.remaining.length > 0) {
8785
+ let aiProvider;
8786
+ try {
8787
+ const { createAIProvider: createAIProvider2 } = await import("./ai-provider-CGSIYFZT.js");
8788
+ aiProvider = await createAIProvider2("auto");
8789
+ } catch {
8790
+ }
8791
+ if (aiProvider?.editPageCode) {
8792
+ console.log(chalk15.dim(` \u23F3 Using AI to fix ${detResult.remaining.length} TypeScript error(s)...`));
8793
+ const aiResult = await applyAiFixes(detResult.remaining, projectRoot, backups, aiProvider);
8794
+ if (aiResult.fixed.length > 0) {
8795
+ fixes.push(`TypeScript: fixed ${aiResult.fixed.length} file(s) via AI`);
8796
+ console.log(chalk15.green(` \u2714 TypeScript: fixed ${aiResult.fixed.length} file(s) via AI`));
8797
+ }
8798
+ if (aiResult.failed.length > 0) {
8799
+ for (const e of aiResult.failed.slice(0, 10)) {
8800
+ remaining.push(`${e.file}(${e.line}): [${e.code}] ${e.message.split("\n")[0]}`);
8801
+ }
8802
+ if (aiResult.failed.length > 10) {
8803
+ remaining.push(`... and ${aiResult.failed.length - 10} more TypeScript errors`);
8804
+ }
8805
+ console.log(chalk15.yellow(` \u26A0 TypeScript: ${aiResult.failed.length} error(s) remaining`));
8806
+ }
8807
+ } else {
8808
+ for (const e of detResult.remaining.slice(0, 10)) {
8809
+ remaining.push(`${e.file}(${e.line}): [${e.code}] ${e.message.split("\n")[0]}`);
8810
+ }
8811
+ if (detResult.remaining.length > 10) {
8812
+ remaining.push(`... and ${detResult.remaining.length - 10} more TypeScript errors`);
8813
+ }
8814
+ console.log(
8815
+ chalk15.yellow(
8816
+ ` \u26A0 TypeScript: ${detResult.remaining.length} error(s) remaining. Configure API key for auto-fix.`
8817
+ )
8818
+ );
8819
+ }
8820
+ }
8821
+ const finalErrors = runTscCheck(projectRoot);
8822
+ if (finalErrors.length === 0) {
8823
+ console.log(chalk15.green(" \u2714 TypeScript compilation now clean"));
8824
+ }
8767
8825
  }
8768
- if (errorLines.length > 10) remaining.push(`... and ${errorLines.length - 10} more TypeScript errors`);
8769
- console.log(chalk15.yellow(` \u26A0 TypeScript: ${errorLines.length} error(s)`));
8770
8826
  }
8827
+ } catch (err) {
8828
+ console.log(
8829
+ chalk15.yellow(` \u26A0 TypeScript check skipped: ${err instanceof Error ? err.message : "unknown error"}`)
8830
+ );
8771
8831
  }
8772
8832
  if (fixes.length === 0 && totalErrors === 0 && totalWarnings === 0 && remaining.length === 0) {
8773
8833
  console.log(chalk15.green("\n \u2705 Everything looks good \u2014 no issues found\n"));
@@ -8798,7 +8858,7 @@ async function fixCommand(opts = {}) {
8798
8858
  // src/commands/check.ts
8799
8859
  import chalk16 from "chalk";
8800
8860
  import { resolve as resolve9 } from "path";
8801
- import { readdirSync as readdirSync8, readFileSync as readFileSync12, statSync as statSync3, existsSync as existsSync16 } from "fs";
8861
+ import { readdirSync as readdirSync8, readFileSync as readFileSync11, statSync as statSync3, existsSync as existsSync15 } from "fs";
8802
8862
  import { loadManifest as loadManifest10 } from "@getcoherent/core";
8803
8863
  var EXCLUDED_DIRS = /* @__PURE__ */ new Set(["node_modules", "design-system"]);
8804
8864
  function findTsxFiles(dir) {
@@ -8855,7 +8915,7 @@ async function checkCommand(opts = {}) {
8855
8915
  "NATIVE_TABLE"
8856
8916
  ]);
8857
8917
  for (const file of files) {
8858
- const code = readFileSync12(file, "utf-8");
8918
+ const code = readFileSync11(file, "utf-8");
8859
8919
  const relativePath = file.replace(projectRoot + "/", "");
8860
8920
  const baseName = file.split("/").pop() || "";
8861
8921
  const isAuthPage = relativePath.includes("(auth)");
@@ -8897,7 +8957,7 @@ async function checkCommand(opts = {}) {
8897
8957
  routeSet.add("/");
8898
8958
  routeSet.add("#");
8899
8959
  for (const file of files) {
8900
- const code = readFileSync12(file, "utf-8");
8960
+ const code = readFileSync11(file, "utf-8");
8901
8961
  const relativePath = file.replace(projectRoot + "/", "");
8902
8962
  const lines = code.split("\n");
8903
8963
  const linkHrefRe = /href\s*=\s*["'](\/[a-z0-9/-]*)["']/gi;
@@ -8930,7 +8990,7 @@ async function checkCommand(opts = {}) {
8930
8990
  if (manifest.shared.length > 0) {
8931
8991
  for (const entry of manifest.shared) {
8932
8992
  const fullPath = resolve9(project.root, entry.file);
8933
- if (!existsSync16(fullPath)) {
8993
+ if (!existsSync15(fullPath)) {
8934
8994
  result.pages.withErrors++;
8935
8995
  if (!opts.json) console.log(chalk16.red(`
8936
8996
  \u2717 Missing shared component file: ${entry.id} (${entry.file})`));
@@ -8955,7 +9015,7 @@ async function checkCommand(opts = {}) {
8955
9015
  let _nameMismatch = 0;
8956
9016
  for (const entry of manifest.shared) {
8957
9017
  const filePath = resolve9(projectRoot, entry.file);
8958
- const fileExists = existsSync16(filePath);
9018
+ const fileExists = existsSync15(filePath);
8959
9019
  if (!fileExists) {
8960
9020
  _orphaned++;
8961
9021
  if (!opts.json) {
@@ -8965,7 +9025,7 @@ async function checkCommand(opts = {}) {
8965
9025
  continue;
8966
9026
  }
8967
9027
  try {
8968
- const code = readFileSync12(filePath, "utf-8");
9028
+ const code = readFileSync11(filePath, "utf-8");
8969
9029
  const actualExports = extractExportedComponentNames(code);
8970
9030
  if (actualExports.length > 0 && !actualExports.includes(entry.name)) {
8971
9031
  _nameMismatch++;
@@ -9033,7 +9093,7 @@ async function checkCommand(opts = {}) {
9033
9093
  id: e.id,
9034
9094
  name: e.name,
9035
9095
  type: e.type,
9036
- status: existsSync16(resolve9(projectRoot, e.file)) ? "ok" : "unused",
9096
+ status: existsSync15(resolve9(projectRoot, e.file)) ? "ok" : "unused",
9037
9097
  message: "",
9038
9098
  suggestions: void 0
9039
9099
  }))
@@ -9047,11 +9107,11 @@ async function checkCommand(opts = {}) {
9047
9107
  const { inferPageTypeFromRoute: inferPageTypeFromRoute2 } = await import("./design-constraints-HGNEY3W3.js");
9048
9108
  const manifest = await loadManifest10(projectRoot);
9049
9109
  const appDir = resolve9(projectRoot, "app");
9050
- const pageFiles = existsSync16(appDir) ? findTsxFiles(appDir) : [];
9110
+ const pageFiles = existsSync15(appDir) ? findTsxFiles(appDir) : [];
9051
9111
  if (manifest.shared.length > 0 && pageFiles.length > 0) {
9052
9112
  const reuseWarnings = [];
9053
9113
  for (const file of pageFiles) {
9054
- const code = readFileSync12(file, "utf-8");
9114
+ const code = readFileSync11(file, "utf-8");
9055
9115
  const relativePath = file.replace(projectRoot + "/", "");
9056
9116
  const route = "/" + relativePath.replace(/^app\//, "").replace(/\/page\.tsx$/, "").replace(/^\(.*?\)\//, "");
9057
9117
  const pageType = inferPageTypeFromRoute2(route);
@@ -9162,12 +9222,12 @@ import {
9162
9222
  generateSharedComponent as generateSharedComponent4,
9163
9223
  integrateSharedLayoutIntoRootLayout as integrateSharedLayoutIntoRootLayout2
9164
9224
  } from "@getcoherent/core";
9165
- import { existsSync as existsSync17 } from "fs";
9225
+ import { existsSync as existsSync16 } from "fs";
9166
9226
  import { resolve as resolve10 } from "path";
9167
9227
 
9168
9228
  // src/utils/ds-files.ts
9169
9229
  import { mkdir as mkdir3, writeFile as writeFile4 } from "fs/promises";
9170
- import { join as join13, dirname as dirname5 } from "path";
9230
+ import { join as join12, dirname as dirname5 } from "path";
9171
9231
  import { DesignSystemGenerator } from "@getcoherent/core";
9172
9232
  var SHARED_DS_KEYS = [
9173
9233
  "app/design-system/shared/page.tsx",
@@ -9181,7 +9241,7 @@ async function writeDesignSystemFiles(projectRoot, config2, options) {
9181
9241
  const toWrite = options?.sharedOnly ? new Map([...files].filter(([path3]) => SHARED_DS_KEYS.includes(path3))) : files;
9182
9242
  const written = [];
9183
9243
  for (const [relativePath, content] of toWrite) {
9184
- const fullPath = join13(projectRoot, relativePath);
9244
+ const fullPath = join12(projectRoot, relativePath);
9185
9245
  await mkdir3(dirname5(fullPath), { recursive: true });
9186
9246
  await writeFile4(fullPath, content, "utf-8");
9187
9247
  written.push(relativePath);
@@ -9317,7 +9377,7 @@ function createComponentsCommand() {
9317
9377
  if (updated) console.log(chalk22.cyan(" Updated app/layout.tsx to use shared layout components.\n"));
9318
9378
  }
9319
9379
  const sharedPagePath = resolve10(project.root, "app/design-system/shared/page.tsx");
9320
- if (!existsSync17(sharedPagePath)) {
9380
+ if (!existsSync16(sharedPagePath)) {
9321
9381
  try {
9322
9382
  const dsm = new DesignSystemManager10(project.configPath);
9323
9383
  await dsm.load();
@@ -9343,8 +9403,8 @@ function createComponentsCommand() {
9343
9403
  import chalk23 from "chalk";
9344
9404
  import ora6 from "ora";
9345
9405
  import { writeFile as writeFile5, mkdir as mkdir4 } from "fs/promises";
9346
- import { resolve as resolve11, join as join14, dirname as dirname6 } from "path";
9347
- import { existsSync as existsSync18 } from "fs";
9406
+ import { resolve as resolve11, join as join13, dirname as dirname6 } from "path";
9407
+ import { existsSync as existsSync17 } from "fs";
9348
9408
  import {
9349
9409
  FigmaClient,
9350
9410
  parseFigmaFileResponse,
@@ -9491,7 +9551,7 @@ async function importFigmaAction(urlOrKey, opts) {
9491
9551
  stats.filesWritten.push(filePath);
9492
9552
  return;
9493
9553
  }
9494
- const fullPath = join14(projectRoot, filePath);
9554
+ const fullPath = join13(projectRoot, filePath);
9495
9555
  await mkdir4(dirname6(fullPath), { recursive: true });
9496
9556
  await writeFile5(fullPath, content, "utf-8");
9497
9557
  stats.filesWritten.push(filePath);
@@ -9593,7 +9653,7 @@ async function importFigmaAction(urlOrKey, opts) {
9593
9653
  spinner.start("Updating design-system.config.ts...");
9594
9654
  const configPath = resolve11(projectRoot, DESIGN_SYSTEM_CONFIG_PATH);
9595
9655
  const dsm = new DesignSystemManager11(configPath);
9596
- if (existsSync18(configPath)) {
9656
+ if (existsSync17(configPath)) {
9597
9657
  await dsm.load();
9598
9658
  const existing = dsm.getConfig();
9599
9659
  dsm.updateConfig({
@@ -9622,8 +9682,8 @@ export const config = ${JSON.stringify(fullConfig, null, 2)} as const
9622
9682
  stats.configUpdated = true;
9623
9683
  spinner.succeed("design-system.config.ts updated");
9624
9684
  spinner.start("Ensuring root layout...");
9625
- const layoutPath = join14(projectRoot, "app/layout.tsx");
9626
- if (!existsSync18(layoutPath)) {
9685
+ const layoutPath = join13(projectRoot, "app/layout.tsx");
9686
+ if (!existsSync17(layoutPath)) {
9627
9687
  await mkdir4(dirname6(layoutPath), { recursive: true });
9628
9688
  await writeFile5(layoutPath, MINIMAL_ROOT_LAYOUT, "utf-8");
9629
9689
  stats.filesWritten.push("app/layout.tsx");
@@ -9713,8 +9773,8 @@ async function dsRegenerateCommand() {
9713
9773
  // src/commands/update.ts
9714
9774
  import chalk25 from "chalk";
9715
9775
  import ora8 from "ora";
9716
- import { readFileSync as readFileSync13, existsSync as existsSync19 } from "fs";
9717
- import { join as join15 } from "path";
9776
+ import { readFileSync as readFileSync12, existsSync as existsSync18 } from "fs";
9777
+ import { join as join14 } from "path";
9718
9778
  import { DesignSystemManager as DesignSystemManager13, CLI_VERSION as CLI_VERSION4 } from "@getcoherent/core";
9719
9779
 
9720
9780
  // src/utils/migrations.ts
@@ -9883,20 +9943,20 @@ var EXPECTED_CSS_VARS = [
9883
9943
  "--sidebar-ring"
9884
9944
  ];
9885
9945
  function checkMissingCssVars(projectRoot) {
9886
- const globalsPath = join15(projectRoot, "app", "globals.css");
9887
- if (!existsSync19(globalsPath)) return [];
9946
+ const globalsPath = join14(projectRoot, "app", "globals.css");
9947
+ if (!existsSync18(globalsPath)) return [];
9888
9948
  try {
9889
- const content = readFileSync13(globalsPath, "utf-8");
9949
+ const content = readFileSync12(globalsPath, "utf-8");
9890
9950
  return EXPECTED_CSS_VARS.filter((v) => !content.includes(v));
9891
9951
  } catch {
9892
9952
  return [];
9893
9953
  }
9894
9954
  }
9895
9955
  function patchGlobalsCss(projectRoot, missingVars) {
9896
- const globalsPath = join15(projectRoot, "app", "globals.css");
9897
- if (!existsSync19(globalsPath) || missingVars.length === 0) return;
9898
- const { writeFileSync: writeFileSync12 } = __require("fs");
9899
- let content = readFileSync13(globalsPath, "utf-8");
9956
+ const globalsPath = join14(projectRoot, "app", "globals.css");
9957
+ if (!existsSync18(globalsPath) || missingVars.length === 0) return;
9958
+ const { writeFileSync: writeFileSync11 } = __require("fs");
9959
+ let content = readFileSync12(globalsPath, "utf-8");
9900
9960
  const defaultValues = {
9901
9961
  "--chart-1": "220 70% 50%",
9902
9962
  "--chart-2": "160 60% 45%",
@@ -9924,7 +9984,7 @@ function patchGlobalsCss(projectRoot, missingVars) {
9924
9984
  const lightSectionEnd = content.indexOf("}");
9925
9985
  if (lightSectionEnd > 0) {
9926
9986
  content = content.slice(0, lightSectionEnd) + "\n" + injection + "\n" + content.slice(lightSectionEnd);
9927
- writeFileSync12(globalsPath, content, "utf-8");
9987
+ writeFileSync11(globalsPath, content, "utf-8");
9928
9988
  }
9929
9989
  }
9930
9990
 
@@ -9974,26 +10034,26 @@ async function undoCommand(options) {
9974
10034
  // src/commands/sync.ts
9975
10035
  import chalk27 from "chalk";
9976
10036
  import ora9 from "ora";
9977
- import { existsSync as existsSync20, readFileSync as readFileSync14 } from "fs";
9978
- import { join as join16, relative as relative6, dirname as dirname7 } from "path";
10037
+ import { existsSync as existsSync19, readFileSync as readFileSync13 } from "fs";
10038
+ import { join as join15, relative as relative6, dirname as dirname7 } from "path";
9979
10039
  import { readdir as readdir3, readFile as readFile4 } from "fs/promises";
9980
10040
  import { DesignSystemManager as DesignSystemManager14 } from "@getcoherent/core";
9981
10041
  import { loadManifest as loadManifest12, saveManifest as saveManifest6, findSharedComponent } from "@getcoherent/core";
9982
10042
  function extractTokensFromProject(projectRoot) {
9983
10043
  const lightColors = {};
9984
10044
  const darkColors = {};
9985
- const globalsPath = join16(projectRoot, "app", "globals.css");
9986
- if (existsSync20(globalsPath)) {
9987
- const css = readFileSync14(globalsPath, "utf-8");
10045
+ const globalsPath = join15(projectRoot, "app", "globals.css");
10046
+ if (existsSync19(globalsPath)) {
10047
+ const css = readFileSync13(globalsPath, "utf-8");
9988
10048
  const rootMatch = css.match(/:root\s*\{([^}]+)\}/s);
9989
10049
  if (rootMatch) parseVarsInto(rootMatch[1], lightColors);
9990
10050
  const darkMatch = css.match(/\.dark\s*\{([^}]+)\}/s);
9991
10051
  if (darkMatch) parseVarsInto(darkMatch[1], darkColors);
9992
10052
  }
9993
- const layoutPath = join16(projectRoot, "app", "layout.tsx");
10053
+ const layoutPath = join15(projectRoot, "app", "layout.tsx");
9994
10054
  let layoutCode = "";
9995
- if (existsSync20(layoutPath)) {
9996
- layoutCode = readFileSync14(layoutPath, "utf-8");
10055
+ if (existsSync19(layoutPath)) {
10056
+ layoutCode = readFileSync13(layoutPath, "utf-8");
9997
10057
  const rootInline = layoutCode.match(/:root\s*\{([^}]+)\}/s);
9998
10058
  if (rootInline && Object.keys(lightColors).length === 0) {
9999
10059
  parseVarsInto(rootInline[1], lightColors);
@@ -10011,7 +10071,7 @@ function extractTokensFromProject(projectRoot) {
10011
10071
  defaultMode = "dark";
10012
10072
  }
10013
10073
  let radius;
10014
- const allCss = [existsSync20(globalsPath) ? readFileSync14(globalsPath, "utf-8") : "", layoutCode].join("\n");
10074
+ const allCss = [existsSync19(globalsPath) ? readFileSync13(globalsPath, "utf-8") : "", layoutCode].join("\n");
10015
10075
  const radiusMatch = allCss.match(/--radius:\s*([^;]+);/);
10016
10076
  if (radiusMatch) radius = radiusMatch[1].trim();
10017
10077
  return {
@@ -10034,8 +10094,8 @@ function parseVarsInto(block, target) {
10034
10094
  }
10035
10095
  async function detectCustomComponents(projectRoot, allPageCode) {
10036
10096
  const results = [];
10037
- const componentsDir = join16(projectRoot, "components");
10038
- if (!existsSync20(componentsDir)) return results;
10097
+ const componentsDir = join15(projectRoot, "components");
10098
+ if (!existsSync19(componentsDir)) return results;
10039
10099
  const files = [];
10040
10100
  await walkForTsx(componentsDir, files, ["ui"]);
10041
10101
  const fileResults = await Promise.all(
@@ -10062,7 +10122,7 @@ async function walkForTsx(dir, files, skipDirs) {
10062
10122
  return;
10063
10123
  }
10064
10124
  for (const e of entries) {
10065
- const full = join16(dir, e.name);
10125
+ const full = join15(dir, e.name);
10066
10126
  if (e.isDirectory()) {
10067
10127
  if (skipDirs.includes(e.name) || e.name.startsWith(".")) continue;
10068
10128
  await walkForTsx(full, files, skipDirs);
@@ -10136,7 +10196,7 @@ async function discoverPages(appDir) {
10136
10196
  return;
10137
10197
  }
10138
10198
  for (const entry of entries) {
10139
- const full = join16(dir, entry.name);
10199
+ const full = join15(dir, entry.name);
10140
10200
  if (entry.isDirectory()) {
10141
10201
  if (["design-system", "api", "_not-found"].includes(entry.name)) continue;
10142
10202
  if (entry.name.startsWith(".")) continue;
@@ -10225,8 +10285,8 @@ async function syncCommand(options = {}) {
10225
10285
  if (dryRun) console.log(chalk27.yellow(" [dry-run] No files will be written\n"));
10226
10286
  const spinner = ora9("Scanning project files...").start();
10227
10287
  try {
10228
- const appDir = join16(project.root, "app");
10229
- if (!existsSync20(appDir)) {
10288
+ const appDir = join15(project.root, "app");
10289
+ if (!existsSync19(appDir)) {
10230
10290
  spinner.fail("No app/ directory found");
10231
10291
  process.exit(1);
10232
10292
  }
@@ -10456,53 +10516,53 @@ async function syncCommand(options = {}) {
10456
10516
  // src/commands/migrate.ts
10457
10517
  import chalk28 from "chalk";
10458
10518
  import ora10 from "ora";
10459
- import { existsSync as existsSync21, mkdirSync as mkdirSync8, cpSync, rmSync as rmSync6, writeFileSync as writeFileSync10, readFileSync as readFileSync15, readdirSync as readdirSync9 } from "fs";
10460
- import { join as join17 } from "path";
10519
+ import { existsSync as existsSync20, mkdirSync as mkdirSync8, cpSync, rmSync as rmSync6, writeFileSync as writeFileSync9, readFileSync as readFileSync14, readdirSync as readdirSync9 } from "fs";
10520
+ import { join as join16 } from "path";
10461
10521
  function backupDir(projectRoot) {
10462
10522
  const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
10463
- return join17(projectRoot, ".coherent", "backups", `pre-migrate-${ts}`);
10523
+ return join16(projectRoot, ".coherent", "backups", `pre-migrate-${ts}`);
10464
10524
  }
10465
10525
  function guardPath(projectRoot) {
10466
- return join17(projectRoot, ".coherent", "migration-in-progress");
10526
+ return join16(projectRoot, ".coherent", "migration-in-progress");
10467
10527
  }
10468
10528
  function createBackup2(projectRoot) {
10469
- const uiDir = join17(projectRoot, "components", "ui");
10529
+ const uiDir = join16(projectRoot, "components", "ui");
10470
10530
  const dest = backupDir(projectRoot);
10471
10531
  mkdirSync8(dest, { recursive: true });
10472
- if (existsSync21(uiDir)) {
10473
- cpSync(uiDir, join17(dest, "components-ui"), { recursive: true });
10532
+ if (existsSync20(uiDir)) {
10533
+ cpSync(uiDir, join16(dest, "components-ui"), { recursive: true });
10474
10534
  }
10475
- const configPath = join17(projectRoot, "design-system.config.ts");
10476
- if (existsSync21(configPath)) {
10477
- cpSync(configPath, join17(dest, "design-system.config.ts"));
10535
+ const configPath = join16(projectRoot, "design-system.config.ts");
10536
+ if (existsSync20(configPath)) {
10537
+ cpSync(configPath, join16(dest, "design-system.config.ts"));
10478
10538
  }
10479
10539
  return dest;
10480
10540
  }
10481
10541
  function setGuard(projectRoot, backupPath) {
10482
10542
  const guard = guardPath(projectRoot);
10483
- mkdirSync8(join17(projectRoot, ".coherent"), { recursive: true });
10484
- writeFileSync10(guard, JSON.stringify({ backup: backupPath, startedAt: (/* @__PURE__ */ new Date()).toISOString() }));
10543
+ mkdirSync8(join16(projectRoot, ".coherent"), { recursive: true });
10544
+ writeFileSync9(guard, JSON.stringify({ backup: backupPath, startedAt: (/* @__PURE__ */ new Date()).toISOString() }));
10485
10545
  }
10486
10546
  function clearGuard(projectRoot) {
10487
10547
  const guard = guardPath(projectRoot);
10488
- if (existsSync21(guard)) rmSync6(guard);
10548
+ if (existsSync20(guard)) rmSync6(guard);
10489
10549
  }
10490
10550
  function rollback(projectRoot) {
10491
10551
  const guard = guardPath(projectRoot);
10492
- if (!existsSync21(guard)) return false;
10552
+ if (!existsSync20(guard)) return false;
10493
10553
  try {
10494
- const data = JSON.parse(readFileSync15(guard, "utf-8"));
10554
+ const data = JSON.parse(readFileSync14(guard, "utf-8"));
10495
10555
  const backup = data.backup;
10496
- if (!existsSync21(backup)) return false;
10497
- const uiBackup = join17(backup, "components-ui");
10498
- const uiDir = join17(projectRoot, "components", "ui");
10499
- if (existsSync21(uiBackup)) {
10500
- if (existsSync21(uiDir)) rmSync6(uiDir, { recursive: true });
10556
+ if (!existsSync20(backup)) return false;
10557
+ const uiBackup = join16(backup, "components-ui");
10558
+ const uiDir = join16(projectRoot, "components", "ui");
10559
+ if (existsSync20(uiBackup)) {
10560
+ if (existsSync20(uiDir)) rmSync6(uiDir, { recursive: true });
10501
10561
  cpSync(uiBackup, uiDir, { recursive: true });
10502
10562
  }
10503
- const configBackup = join17(backup, "design-system.config.ts");
10504
- const configDest = join17(projectRoot, "design-system.config.ts");
10505
- if (existsSync21(configBackup)) {
10563
+ const configBackup = join16(backup, "design-system.config.ts");
10564
+ const configDest = join16(projectRoot, "design-system.config.ts");
10565
+ if (existsSync20(configBackup)) {
10506
10566
  cpSync(configBackup, configDest);
10507
10567
  }
10508
10568
  clearGuard(projectRoot);
@@ -10530,13 +10590,13 @@ async function migrateAction(options) {
10530
10590
  return;
10531
10591
  }
10532
10592
  const guard = guardPath(projectRoot);
10533
- if (existsSync21(guard)) {
10593
+ if (existsSync20(guard)) {
10534
10594
  console.log(chalk28.yellow("A migration is already in progress."));
10535
10595
  console.log(chalk28.dim("Run `coherent migrate --rollback` to undo, or delete .coherent/migration-in-progress"));
10536
10596
  return;
10537
10597
  }
10538
- const uiDir = join17(projectRoot, "components", "ui");
10539
- if (!existsSync21(uiDir)) {
10598
+ const uiDir = join16(projectRoot, "components", "ui");
10599
+ if (!existsSync20(uiDir)) {
10540
10600
  console.log(chalk28.yellow("No components/ui directory found. Nothing to migrate."));
10541
10601
  return;
10542
10602
  }
@@ -10562,8 +10622,8 @@ Found ${migratable.length} component(s) to migrate:`));
10562
10622
  setGuard(projectRoot, backup);
10563
10623
  try {
10564
10624
  for (const id of migratable) {
10565
- const filePath = join17(uiDir, `${id}.tsx`);
10566
- if (existsSync21(filePath)) rmSync6(filePath);
10625
+ const filePath = join16(uiDir, `${id}.tsx`);
10626
+ if (existsSync20(filePath)) rmSync6(filePath);
10567
10627
  }
10568
10628
  const results = await provider.installBatch(migratable, projectRoot, { force: true });
10569
10629
  let migrated = 0;
@@ -10585,20 +10645,20 @@ Found ${migratable.length} component(s) to migrate:`));
10585
10645
  }
10586
10646
 
10587
10647
  // src/utils/update-notifier.ts
10588
- import { existsSync as existsSync22, mkdirSync as mkdirSync9, readFileSync as readFileSync16, writeFileSync as writeFileSync11 } from "fs";
10589
- import { join as join18 } from "path";
10648
+ import { existsSync as existsSync21, mkdirSync as mkdirSync9, readFileSync as readFileSync15, writeFileSync as writeFileSync10 } from "fs";
10649
+ import { join as join17 } from "path";
10590
10650
  import { homedir } from "os";
10591
10651
  import chalk29 from "chalk";
10592
10652
  import { CLI_VERSION as CLI_VERSION5 } from "@getcoherent/core";
10593
10653
  var DEBUG5 = process.env.COHERENT_DEBUG === "1";
10594
10654
  var PACKAGE_NAME = "@getcoherent/cli";
10595
- var CACHE_DIR = join18(homedir(), ".coherent");
10596
- var CACHE_FILE = join18(CACHE_DIR, "update-check.json");
10655
+ var CACHE_DIR = join17(homedir(), ".coherent");
10656
+ var CACHE_FILE = join17(CACHE_DIR, "update-check.json");
10597
10657
  var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
10598
10658
  function readCache() {
10599
10659
  try {
10600
- if (!existsSync22(CACHE_FILE)) return null;
10601
- const raw = readFileSync16(CACHE_FILE, "utf-8");
10660
+ if (!existsSync21(CACHE_FILE)) return null;
10661
+ const raw = readFileSync15(CACHE_FILE, "utf-8");
10602
10662
  return JSON.parse(raw);
10603
10663
  } catch (e) {
10604
10664
  if (DEBUG5) console.error("Failed to read update cache:", e);
@@ -10607,8 +10667,8 @@ function readCache() {
10607
10667
  }
10608
10668
  function writeCache(data) {
10609
10669
  try {
10610
- if (!existsSync22(CACHE_DIR)) mkdirSync9(CACHE_DIR, { recursive: true });
10611
- writeFileSync11(CACHE_FILE, JSON.stringify(data), "utf-8");
10670
+ if (!existsSync21(CACHE_DIR)) mkdirSync9(CACHE_DIR, { recursive: true });
10671
+ writeFileSync10(CACHE_FILE, JSON.stringify(data), "utf-8");
10612
10672
  } catch (e) {
10613
10673
  if (DEBUG5) console.error("Failed to write update cache:", e);
10614
10674
  }
@@ -0,0 +1,98 @@
1
+ import {
2
+ runTscCheck
3
+ } from "./chunk-XPBD3L7V.js";
4
+ import {
5
+ safeWrite
6
+ } from "./chunk-U6M76BKY.js";
7
+ import "./chunk-3RG5ZIWI.js";
8
+
9
+ // src/utils/tsc-ai-fix.ts
10
+ import { readFileSync } from "fs";
11
+ import { resolve } from "path";
12
+ var MAX_AI_FILES = 5;
13
+ async function applyAiFixes(errors, projectRoot, backups, aiProvider) {
14
+ if (!aiProvider?.editPageCode) {
15
+ return { fixed: [], failed: errors };
16
+ }
17
+ const fileErrors = /* @__PURE__ */ new Map();
18
+ for (const err of errors) {
19
+ const list = fileErrors.get(err.file) || [];
20
+ list.push(err);
21
+ fileErrors.set(err.file, list);
22
+ }
23
+ const fixed = [];
24
+ const failed = [];
25
+ let filesProcessed = 0;
26
+ for (const [file, errs] of fileErrors) {
27
+ filesProcessed++;
28
+ if (filesProcessed > MAX_AI_FILES) {
29
+ failed.push(...errs);
30
+ continue;
31
+ }
32
+ const absPath = resolve(projectRoot, file);
33
+ let code;
34
+ try {
35
+ code = readFileSync(absPath, "utf-8");
36
+ } catch {
37
+ failed.push(...errs);
38
+ continue;
39
+ }
40
+ const relatedContext = gatherRelatedContext(errs, projectRoot);
41
+ const errorList = errs.map((e) => `Line ${e.line}: [${e.code}] ${e.message}`).join("\n");
42
+ const instruction = [
43
+ "Fix these TypeScript compilation errors:",
44
+ errorList,
45
+ "",
46
+ relatedContext ? `Reference interfaces (DO NOT modify these):
47
+ ${relatedContext}` : "",
48
+ "",
49
+ "Rules:",
50
+ "- Fix the data/props to match the expected types",
51
+ "- Do NOT change component interfaces or imports from shared components",
52
+ "- Keep all existing functionality intact"
53
+ ].filter(Boolean).join("\n");
54
+ try {
55
+ const fixedCode = await aiProvider.editPageCode(code, instruction, file);
56
+ if (!fixedCode || fixedCode.length < 50) {
57
+ failed.push(...errs);
58
+ continue;
59
+ }
60
+ const { ok } = safeWrite(absPath, fixedCode, projectRoot, backups);
61
+ if (!ok) {
62
+ failed.push(...errs);
63
+ continue;
64
+ }
65
+ const afterErrors = runTscCheck(projectRoot).filter((e) => e.file === file);
66
+ if (afterErrors.length >= errs.length) {
67
+ const original = backups.get(absPath);
68
+ if (original) safeWrite(absPath, original, projectRoot, backups);
69
+ failed.push(...errs);
70
+ } else {
71
+ fixed.push(file);
72
+ if (afterErrors.length > 0) failed.push(...afterErrors);
73
+ }
74
+ } catch {
75
+ failed.push(...errs);
76
+ }
77
+ }
78
+ return { fixed, failed };
79
+ }
80
+ function gatherRelatedContext(errors, projectRoot) {
81
+ const relatedFiles = /* @__PURE__ */ new Set();
82
+ for (const err of errors) {
83
+ for (const f of err.relatedFiles) relatedFiles.add(f);
84
+ }
85
+ const parts = [];
86
+ for (const file of relatedFiles) {
87
+ try {
88
+ const content = readFileSync(resolve(projectRoot, file), "utf-8");
89
+ parts.push(`// --- ${file} ---
90
+ ${content}`);
91
+ } catch {
92
+ }
93
+ }
94
+ return parts.join("\n\n");
95
+ }
96
+ export {
97
+ applyAiFixes
98
+ };
@@ -0,0 +1,16 @@
1
+ import {
2
+ applyDeterministicFixes,
3
+ fixFieldRename,
4
+ fixMissingEventHandler,
5
+ fixUnionType,
6
+ runTscCheck
7
+ } from "./chunk-XPBD3L7V.js";
8
+ import "./chunk-U6M76BKY.js";
9
+ import "./chunk-3RG5ZIWI.js";
10
+ export {
11
+ applyDeterministicFixes,
12
+ fixFieldRename,
13
+ fixMissingEventHandler,
14
+ fixUnionType,
15
+ runTscCheck
16
+ };
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "0.6.46",
6
+ "version": "0.6.47",
7
7
  "description": "CLI interface for Coherent Design Method",
8
8
  "type": "module",
9
9
  "main": "./dist/index.js",