@getcoherent/cli 0.6.44 → 0.6.46
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-QE66D55S.js → chunk-4I7ATX6G.js} +2 -2
- package/dist/{chunk-5AHG4NNX.js → chunk-E23FJX2I.js} +16 -1
- package/dist/{chunk-KJRBBLXT.js → chunk-VLBVBF6V.js} +1 -1
- package/dist/{code-generator-ASIANBH2.js → code-generator-YSGVHVNN.js} +3 -3
- package/dist/{design-constraints-EIP2XM7T.js → design-constraints-HGNEY3W3.js} +1 -1
- package/dist/index.js +147 -68
- package/dist/mock-data-validator-JEWUOMFY.js +70 -0
- package/dist/{plan-generator-YOPF773K.js → plan-generator-PIDLFRWZ.js} +2 -2
- package/package.json +10 -10
- package/LICENSE +0 -21
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
getPageGroup,
|
|
7
7
|
installPackages,
|
|
8
8
|
sanitizeMetadataStrings
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-VLBVBF6V.js";
|
|
10
10
|
import {
|
|
11
11
|
toKebabCase
|
|
12
12
|
} from "./chunk-4TLYDTT3.js";
|
|
@@ -2147,7 +2147,7 @@ async function regeneratePage(pageId, config, projectRoot) {
|
|
|
2147
2147
|
const code = await generator.generate(page, appType);
|
|
2148
2148
|
const route = page.route || "/";
|
|
2149
2149
|
const isAuth = isAuthRoute(route) || isAuthRoute(page.name || page.id || "");
|
|
2150
|
-
const { loadPlan: loadPlanForPath } = await import("./plan-generator-
|
|
2150
|
+
const { loadPlan: loadPlanForPath } = await import("./plan-generator-PIDLFRWZ.js");
|
|
2151
2151
|
const planForPath = loadPlanForPath(projectRoot);
|
|
2152
2152
|
const filePath = routeToFsPath(projectRoot, route, planForPath || isAuth);
|
|
2153
2153
|
await mkdir3(dirname3(filePath), { recursive: true });
|
|
@@ -93,6 +93,15 @@ COMPONENT VARIANT RULES (CRITICAL):
|
|
|
93
93
|
CONTENT (zero placeholders):
|
|
94
94
|
- NEVER: "Lorem ipsum", "Card content", "Description here"
|
|
95
95
|
- ALWAYS: Real, contextual content. Realistic metric names, values, dates.
|
|
96
|
+
|
|
97
|
+
MOCK/SAMPLE DATA (for demo arrays, fake users, fake tasks, etc.):
|
|
98
|
+
- Dates: ALWAYS ISO 8601 strings in data ("2024-06-15T10:30:00Z").
|
|
99
|
+
Display with date formatting: new Date(item.date).toLocaleDateString() or
|
|
100
|
+
Intl.RelativeTimeFormat, or date-fns if already imported.
|
|
101
|
+
BAD: { createdAt: "2 hours ago" }
|
|
102
|
+
GOOD: { createdAt: "2024-06-15T10:30:00Z" }
|
|
103
|
+
- Images: "/placeholder.svg?height=40&width=40" (Next.js placeholder). Never broken paths.
|
|
104
|
+
- IDs: sequential numbers (1, 2, 3) or short slugs ("proj-1"). Never random UUIDs.
|
|
96
105
|
`;
|
|
97
106
|
var DESIGN_QUALITY_COMMON = `
|
|
98
107
|
## DESIGN QUALITY \u2014 COMMON
|
|
@@ -509,11 +518,17 @@ EMPTY STATES: See the Empty State reference pattern in DESIGN QUALITY \u2014 APP
|
|
|
509
518
|
- Filtered empty: "No items match your filters." + reset filters button.
|
|
510
519
|
|
|
511
520
|
DATA FORMATTING:
|
|
512
|
-
- Dates: use relative for recent ("2 hours ago"
|
|
521
|
+
- Dates in rendered output: use relative for recent ("2 hours ago"), absolute for older ("Jan 26, 2026"). Never show raw ISO in the UI.
|
|
522
|
+
- Dates in source data (mock arrays, state): ALWAYS store as ISO 8601 strings. Compute display format at render time.
|
|
513
523
|
- Numbers: use Intl.NumberFormat or toLocaleString(). 1,234 not 1234. Always include separator for 1000+.
|
|
514
524
|
- Currency: $1,234.56 format. Symbol before number. Two decimal places for amounts.
|
|
515
525
|
- Percentages: one decimal max. "+12.5%" with sign for changes.
|
|
516
526
|
|
|
527
|
+
MOCK DATA IN COMPONENTS:
|
|
528
|
+
- All date/time values in sample data arrays MUST be valid ISO 8601 strings.
|
|
529
|
+
- Render with: new Date(item.date).toLocaleDateString(), Intl.RelativeTimeFormat, or date-fns if imported.
|
|
530
|
+
- NEVER store display strings ("2 hours ago", "Yesterday") in data \u2014 always compute from ISO date.
|
|
531
|
+
|
|
517
532
|
STATUS INDICATORS (dot + text):
|
|
518
533
|
- Pattern: <div className="flex items-center gap-2"><div className="size-2 rounded-full bg-emerald-500" /><span className="text-sm">Active</span></div>
|
|
519
534
|
- Colors: bg-emerald-500 (active/online), bg-destructive (error/offline), bg-yellow-500 (warning), bg-muted-foreground (inactive).
|
|
@@ -12,10 +12,10 @@ import {
|
|
|
12
12
|
regeneratePage,
|
|
13
13
|
scanAndInstallSharedDeps,
|
|
14
14
|
validateAndFixGeneratedCode
|
|
15
|
-
} from "./chunk-
|
|
16
|
-
import "./chunk-
|
|
15
|
+
} from "./chunk-4I7ATX6G.js";
|
|
16
|
+
import "./chunk-VLBVBF6V.js";
|
|
17
17
|
import "./chunk-4TLYDTT3.js";
|
|
18
|
-
import "./chunk-
|
|
18
|
+
import "./chunk-E23FJX2I.js";
|
|
19
19
|
import "./chunk-NOM47EB4.js";
|
|
20
20
|
import "./chunk-3RG5ZIWI.js";
|
|
21
21
|
export {
|
package/dist/index.js
CHANGED
|
@@ -34,7 +34,7 @@ import {
|
|
|
34
34
|
warnIfVolatile,
|
|
35
35
|
warnInlineDuplicates,
|
|
36
36
|
writeFile
|
|
37
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-4I7ATX6G.js";
|
|
38
38
|
import {
|
|
39
39
|
COHERENT_REQUIRED_PACKAGES,
|
|
40
40
|
ensureUseClientIfNeeded,
|
|
@@ -52,7 +52,7 @@ import {
|
|
|
52
52
|
sanitizeMetadataStrings,
|
|
53
53
|
savePlan,
|
|
54
54
|
updateArchitecturePlan
|
|
55
|
-
} from "./chunk-
|
|
55
|
+
} from "./chunk-VLBVBF6V.js";
|
|
56
56
|
import {
|
|
57
57
|
toKebabCase,
|
|
58
58
|
toTitleCase
|
|
@@ -70,7 +70,7 @@ import {
|
|
|
70
70
|
getDesignQualityForType,
|
|
71
71
|
inferPageTypeFromRoute,
|
|
72
72
|
selectContextualRules
|
|
73
|
-
} from "./chunk-
|
|
73
|
+
} from "./chunk-E23FJX2I.js";
|
|
74
74
|
import {
|
|
75
75
|
fixGlobalsCss,
|
|
76
76
|
generateV4GlobalsCss,
|
|
@@ -3896,7 +3896,7 @@ async function splitGeneratePages(spinner, message, modCtx, provider, parseOpts)
|
|
|
3896
3896
|
if (plan && plan.sharedComponents.length > 0) {
|
|
3897
3897
|
spinner.start(`Phase 4.5/6 \u2014 Generating ${plan.sharedComponents.length} shared components from plan...`);
|
|
3898
3898
|
try {
|
|
3899
|
-
const { generateSharedComponentsFromPlan } = await import("./plan-generator-
|
|
3899
|
+
const { generateSharedComponentsFromPlan } = await import("./plan-generator-PIDLFRWZ.js");
|
|
3900
3900
|
const generated = await generateSharedComponentsFromPlan(
|
|
3901
3901
|
plan,
|
|
3902
3902
|
styleContext,
|
|
@@ -6224,7 +6224,7 @@ Return JSON: { "requests": [{ "type": "add-page", "changes": { "name": "${compon
|
|
|
6224
6224
|
}
|
|
6225
6225
|
try {
|
|
6226
6226
|
const { validateReuse } = await import("./reuse-validator-XR2ZEYC4.js");
|
|
6227
|
-
const { inferPageTypeFromRoute: inferPageTypeFromRoute2 } = await import("./design-constraints-
|
|
6227
|
+
const { inferPageTypeFromRoute: inferPageTypeFromRoute2 } = await import("./design-constraints-HGNEY3W3.js");
|
|
6228
6228
|
const manifest2 = await loadManifest7(projectRoot);
|
|
6229
6229
|
const reuseplan = projectRoot ? loadPlan(projectRoot) : null;
|
|
6230
6230
|
if (manifest2.shared.length > 0) {
|
|
@@ -8214,7 +8214,7 @@ async function fixCommand(opts = {}) {
|
|
|
8214
8214
|
}
|
|
8215
8215
|
}
|
|
8216
8216
|
const appDir = resolve8(projectRoot, "app");
|
|
8217
|
-
|
|
8217
|
+
let allTsxFiles = listTsxFiles(appDir);
|
|
8218
8218
|
const componentsTsxFiles = listTsxFiles(resolve8(projectRoot, "components"));
|
|
8219
8219
|
const allComponentIds = /* @__PURE__ */ new Set();
|
|
8220
8220
|
for (const file of [...allTsxFiles, ...componentsTsxFiles]) {
|
|
@@ -8377,25 +8377,31 @@ async function fixCommand(opts = {}) {
|
|
|
8377
8377
|
}
|
|
8378
8378
|
}
|
|
8379
8379
|
}
|
|
8380
|
-
|
|
8380
|
+
let userTsxFiles = allTsxFiles.filter((f) => !f.includes("/design-system/"));
|
|
8381
8381
|
let syntaxFixed = 0;
|
|
8382
8382
|
for (const file of userTsxFiles) {
|
|
8383
|
-
|
|
8384
|
-
|
|
8385
|
-
|
|
8386
|
-
|
|
8387
|
-
|
|
8388
|
-
if (
|
|
8389
|
-
|
|
8390
|
-
|
|
8391
|
-
|
|
8392
|
-
|
|
8383
|
+
try {
|
|
8384
|
+
const content = readFileSync11(file, "utf-8");
|
|
8385
|
+
const fixed = fixUnescapedLtInJsx(
|
|
8386
|
+
fixEscapedClosingQuotes(sanitizeMetadataStrings(ensureUseClientIfNeeded(content)))
|
|
8387
|
+
);
|
|
8388
|
+
if (fixed !== content) {
|
|
8389
|
+
if (!dryRun) {
|
|
8390
|
+
const result = safeWrite(file, fixed, projectRoot, backups);
|
|
8391
|
+
if (result.ok) {
|
|
8392
|
+
modifiedFiles.push(file);
|
|
8393
|
+
syntaxFixed++;
|
|
8394
|
+
} else {
|
|
8395
|
+
console.log(chalk15.yellow(` \u26A0 Syntax fix rolled back for ${relative5(projectRoot, file)} (parse error)`));
|
|
8396
|
+
}
|
|
8393
8397
|
} else {
|
|
8394
|
-
|
|
8398
|
+
syntaxFixed++;
|
|
8395
8399
|
}
|
|
8396
|
-
} else {
|
|
8397
|
-
syntaxFixed++;
|
|
8398
8400
|
}
|
|
8401
|
+
} catch (err) {
|
|
8402
|
+
remaining.push(
|
|
8403
|
+
`${relative5(projectRoot, file)}: syntax fix error \u2014 ${err instanceof Error ? err.message : "unknown"}`
|
|
8404
|
+
);
|
|
8399
8405
|
}
|
|
8400
8406
|
}
|
|
8401
8407
|
if (syntaxFixed > 0) {
|
|
@@ -8404,8 +8410,8 @@ async function fixCommand(opts = {}) {
|
|
|
8404
8410
|
console.log(chalk15.green(` \u2714 ${verb} syntax: ${syntaxFixed} file(s) (use client, metadata, quotes)`));
|
|
8405
8411
|
}
|
|
8406
8412
|
try {
|
|
8407
|
-
const { loadPlan: loadPlan2 } = await import("./plan-generator-
|
|
8408
|
-
const { ensurePlanGroupLayouts: ensurePlanGroupLayouts2 } = await import("./code-generator-
|
|
8413
|
+
const { loadPlan: loadPlan2 } = await import("./plan-generator-PIDLFRWZ.js");
|
|
8414
|
+
const { ensurePlanGroupLayouts: ensurePlanGroupLayouts2 } = await import("./code-generator-YSGVHVNN.js");
|
|
8409
8415
|
const plan = loadPlan2(projectRoot);
|
|
8410
8416
|
if (plan) {
|
|
8411
8417
|
if (!dsm) {
|
|
@@ -8459,7 +8465,7 @@ async function fixCommand(opts = {}) {
|
|
|
8459
8465
|
const publicExists = existsSync15(publicLayoutPath);
|
|
8460
8466
|
const needsPublicLayout = !publicExists || !readFileSync11(publicLayoutPath, "utf-8").includes("<Header");
|
|
8461
8467
|
if (needsPublicLayout) {
|
|
8462
|
-
const { buildPublicLayoutCodeForSidebar } = await import("./code-generator-
|
|
8468
|
+
const { buildPublicLayoutCodeForSidebar } = await import("./code-generator-YSGVHVNN.js");
|
|
8463
8469
|
mkdirSync7(resolve8(projectRoot, "app", "(public)"), { recursive: true });
|
|
8464
8470
|
const publicResult = safeWrite(publicLayoutPath, buildPublicLayoutCodeForSidebar(), projectRoot, backups);
|
|
8465
8471
|
if (publicResult.ok) {
|
|
@@ -8508,7 +8514,7 @@ async function fixCommand(opts = {}) {
|
|
|
8508
8514
|
}
|
|
8509
8515
|
const themeTogglePath = resolve8(projectRoot, "components", "shared", "theme-toggle.tsx");
|
|
8510
8516
|
if (!existsSync15(themeTogglePath)) {
|
|
8511
|
-
const { generateThemeToggleCode } = await import("./code-generator-
|
|
8517
|
+
const { generateThemeToggleCode } = await import("./code-generator-YSGVHVNN.js");
|
|
8512
8518
|
mkdirSync7(resolve8(projectRoot, "components", "shared"), { recursive: true });
|
|
8513
8519
|
const themeResult = safeWrite(themeTogglePath, generateThemeToggleCode(), projectRoot, backups);
|
|
8514
8520
|
if (themeResult.ok) {
|
|
@@ -8529,7 +8535,7 @@ async function fixCommand(opts = {}) {
|
|
|
8529
8535
|
const isMinimal = appLayoutCode.length < 500 && !appLayoutCode.includes("Header") && !appLayoutCode.includes("Footer") && !appLayoutCode.includes("Sidebar") && !appLayoutCode.includes("SidebarProvider") && !appLayoutCode.includes("SidebarTrigger") && !appLayoutCode.includes("Sheet");
|
|
8530
8536
|
const navType = dsm.getConfig().navigation?.type || "header";
|
|
8531
8537
|
if (isMinimal && navType !== "none") {
|
|
8532
|
-
const { buildAppLayoutCode, buildGroupLayoutCode } = await import("./code-generator-
|
|
8538
|
+
const { buildAppLayoutCode, buildGroupLayoutCode } = await import("./code-generator-YSGVHVNN.js");
|
|
8533
8539
|
const isSidebar = navType === "sidebar" || navType === "both";
|
|
8534
8540
|
const newLayout = isSidebar ? buildAppLayoutCode(navType, dsm.getConfig().name) : buildGroupLayoutCode("header", dsm.getConfig().pages?.map((p) => p.name) || [], dsm.getConfig().name);
|
|
8535
8541
|
if (!dryRun) {
|
|
@@ -8544,26 +8550,36 @@ async function fixCommand(opts = {}) {
|
|
|
8544
8550
|
}
|
|
8545
8551
|
}
|
|
8546
8552
|
}
|
|
8553
|
+
allTsxFiles = listTsxFiles(appDir);
|
|
8554
|
+
userTsxFiles = allTsxFiles.filter((f) => !f.includes("/design-system/"));
|
|
8555
|
+
const sharedTsxFiles = listTsxFiles(resolve8(projectRoot, "components", "shared"));
|
|
8556
|
+
const allValidationFiles = [...userTsxFiles, ...sharedTsxFiles];
|
|
8547
8557
|
if (!skipQuality) {
|
|
8548
8558
|
let qualityFixCount = 0;
|
|
8549
8559
|
const qualityFixDetails = [];
|
|
8550
|
-
for (const file of
|
|
8551
|
-
|
|
8552
|
-
|
|
8553
|
-
|
|
8554
|
-
if (
|
|
8555
|
-
|
|
8556
|
-
|
|
8557
|
-
|
|
8560
|
+
for (const file of allValidationFiles) {
|
|
8561
|
+
try {
|
|
8562
|
+
const content = readFileSync11(file, "utf-8");
|
|
8563
|
+
const { code: autoFixed, fixes: fileFixes } = await autoFixCode(content);
|
|
8564
|
+
if (autoFixed !== content) {
|
|
8565
|
+
if (!dryRun) {
|
|
8566
|
+
const qResult = safeWrite(file, autoFixed, projectRoot, backups);
|
|
8567
|
+
if (qResult.ok) {
|
|
8568
|
+
modifiedFiles.push(file);
|
|
8569
|
+
qualityFixCount++;
|
|
8570
|
+
qualityFixDetails.push(...fileFixes);
|
|
8571
|
+
} else {
|
|
8572
|
+
console.log(chalk15.yellow(` \u26A0 Quality fix rolled back for ${relative5(projectRoot, file)} (parse error)`));
|
|
8573
|
+
}
|
|
8574
|
+
} else {
|
|
8558
8575
|
qualityFixCount++;
|
|
8559
8576
|
qualityFixDetails.push(...fileFixes);
|
|
8560
|
-
} else {
|
|
8561
|
-
console.log(chalk15.yellow(` \u26A0 Quality fix rolled back for ${relative5(projectRoot, file)} (parse error)`));
|
|
8562
8577
|
}
|
|
8563
|
-
} else {
|
|
8564
|
-
qualityFixCount++;
|
|
8565
|
-
qualityFixDetails.push(...fileFixes);
|
|
8566
8578
|
}
|
|
8579
|
+
} catch (err) {
|
|
8580
|
+
remaining.push(
|
|
8581
|
+
`${relative5(projectRoot, file)}: quality fix error \u2014 ${err instanceof Error ? err.message : "unknown"}`
|
|
8582
|
+
);
|
|
8567
8583
|
}
|
|
8568
8584
|
}
|
|
8569
8585
|
if (qualityFixCount > 0) {
|
|
@@ -8573,6 +8589,39 @@ async function fixCommand(opts = {}) {
|
|
|
8573
8589
|
console.log(chalk15.green(` \u2714 ${verb} ${uniqueFixes.length} quality issue type(s): ${uniqueFixes.join(", ")}`));
|
|
8574
8590
|
}
|
|
8575
8591
|
}
|
|
8592
|
+
try {
|
|
8593
|
+
const { validateMockData, applyMockDataFixes } = await import("./mock-data-validator-JEWUOMFY.js");
|
|
8594
|
+
let mockFixed = 0;
|
|
8595
|
+
for (const file of allValidationFiles) {
|
|
8596
|
+
try {
|
|
8597
|
+
const content = readFileSync11(file, "utf-8");
|
|
8598
|
+
const mockIssues = validateMockData(content);
|
|
8599
|
+
if (mockIssues.length > 0) {
|
|
8600
|
+
const fixed = applyMockDataFixes(content, mockIssues);
|
|
8601
|
+
if (fixed !== content && !dryRun) {
|
|
8602
|
+
const result = safeWrite(file, fixed, projectRoot, backups);
|
|
8603
|
+
if (result.ok) {
|
|
8604
|
+
mockFixed++;
|
|
8605
|
+
modifiedFiles.push(file);
|
|
8606
|
+
}
|
|
8607
|
+
} else if (dryRun) {
|
|
8608
|
+
mockFixed++;
|
|
8609
|
+
}
|
|
8610
|
+
}
|
|
8611
|
+
} catch (fileErr) {
|
|
8612
|
+
remaining.push(
|
|
8613
|
+
`${relative5(projectRoot, file)}: mock data fix error \u2014 ${fileErr instanceof Error ? fileErr.message : "unknown"}`
|
|
8614
|
+
);
|
|
8615
|
+
}
|
|
8616
|
+
}
|
|
8617
|
+
if (mockFixed > 0) {
|
|
8618
|
+
const verb = dryRun ? "Would fix" : "Fixed";
|
|
8619
|
+
fixes.push(`${verb} mock data in ${mockFixed} file(s)`);
|
|
8620
|
+
console.log(chalk15.green(` \u2714 ${verb} mock data: ${mockFixed} file(s)`));
|
|
8621
|
+
}
|
|
8622
|
+
} catch (importErr) {
|
|
8623
|
+
console.log(chalk15.dim(" \u2298 mock-data-validator not available, skipping"));
|
|
8624
|
+
}
|
|
8576
8625
|
for (const file of modifiedFiles) {
|
|
8577
8626
|
if (!backups.has(file)) continue;
|
|
8578
8627
|
const before = backups.get(file);
|
|
@@ -8587,29 +8636,36 @@ async function fixCommand(opts = {}) {
|
|
|
8587
8636
|
let totalErrors = 0;
|
|
8588
8637
|
let totalWarnings = 0;
|
|
8589
8638
|
const fileIssues = [];
|
|
8590
|
-
for (const file of
|
|
8591
|
-
|
|
8592
|
-
|
|
8593
|
-
|
|
8594
|
-
|
|
8595
|
-
|
|
8596
|
-
|
|
8597
|
-
|
|
8598
|
-
|
|
8599
|
-
|
|
8600
|
-
|
|
8601
|
-
|
|
8602
|
-
|
|
8603
|
-
|
|
8604
|
-
|
|
8605
|
-
|
|
8606
|
-
|
|
8607
|
-
|
|
8608
|
-
|
|
8609
|
-
|
|
8610
|
-
|
|
8611
|
-
|
|
8612
|
-
|
|
8639
|
+
for (const file of allValidationFiles) {
|
|
8640
|
+
try {
|
|
8641
|
+
const code = readFileSync11(file, "utf-8");
|
|
8642
|
+
const relativePath = file.replace(projectRoot + "/", "");
|
|
8643
|
+
const baseName = file.split("/").pop() || "";
|
|
8644
|
+
const isAuthPage = relativePath.includes("(auth)");
|
|
8645
|
+
const isSharedComponent = relativePath.includes("components/shared/");
|
|
8646
|
+
const isNonPageFile = baseName === "layout.tsx" || baseName === "AppNav.tsx" || baseName === "not-found.tsx" || baseName === "ShowWhenNotAuthRoute.tsx";
|
|
8647
|
+
const isHomePage = relativePath === "app/page.tsx";
|
|
8648
|
+
const isDesignSystem = relativePath.includes("design-system");
|
|
8649
|
+
if (isDesignSystem) continue;
|
|
8650
|
+
const issues = validatePageQuality(code);
|
|
8651
|
+
const suppressH1 = isNonPageFile || isAuthPage || isSharedComponent;
|
|
8652
|
+
const filteredIssues = issues.filter((i) => {
|
|
8653
|
+
if (suppressH1 && (i.type === "NO_H1" || i.type === "MULTIPLE_H1")) return false;
|
|
8654
|
+
if (isHomePage && i.type === "NO_EMPTY_STATE") return false;
|
|
8655
|
+
return true;
|
|
8656
|
+
});
|
|
8657
|
+
if (filteredIssues.length === 0) continue;
|
|
8658
|
+
const errors = filteredIssues.filter((i) => i.severity === "error").length;
|
|
8659
|
+
const warnings = filteredIssues.filter((i) => i.severity === "warning").length;
|
|
8660
|
+
totalErrors += errors;
|
|
8661
|
+
totalWarnings += warnings;
|
|
8662
|
+
const report = formatIssues(filteredIssues);
|
|
8663
|
+
fileIssues.push({ path: relativePath, report });
|
|
8664
|
+
} catch (err) {
|
|
8665
|
+
remaining.push(
|
|
8666
|
+
`${relative5(projectRoot, file)}: validation error \u2014 ${err instanceof Error ? err.message : "unknown"}`
|
|
8667
|
+
);
|
|
8668
|
+
}
|
|
8613
8669
|
}
|
|
8614
8670
|
try {
|
|
8615
8671
|
let manifest = await loadManifest9(project.root);
|
|
@@ -8690,6 +8746,29 @@ async function fixCommand(opts = {}) {
|
|
|
8690
8746
|
);
|
|
8691
8747
|
}
|
|
8692
8748
|
}
|
|
8749
|
+
try {
|
|
8750
|
+
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());
|
|
8767
|
+
}
|
|
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
|
+
}
|
|
8771
|
+
}
|
|
8693
8772
|
if (fixes.length === 0 && totalErrors === 0 && totalWarnings === 0 && remaining.length === 0) {
|
|
8694
8773
|
console.log(chalk15.green("\n \u2705 Everything looks good \u2014 no issues found\n"));
|
|
8695
8774
|
console.log(chalk15.cyan(" Run: coherent preview\n"));
|
|
@@ -8965,7 +9044,7 @@ async function checkCommand(opts = {}) {
|
|
|
8965
9044
|
if (!skipShared) {
|
|
8966
9045
|
try {
|
|
8967
9046
|
const { validateReuse } = await import("./reuse-validator-XR2ZEYC4.js");
|
|
8968
|
-
const { inferPageTypeFromRoute: inferPageTypeFromRoute2 } = await import("./design-constraints-
|
|
9047
|
+
const { inferPageTypeFromRoute: inferPageTypeFromRoute2 } = await import("./design-constraints-HGNEY3W3.js");
|
|
8969
9048
|
const manifest = await loadManifest10(projectRoot);
|
|
8970
9049
|
const appDir = resolve9(projectRoot, "app");
|
|
8971
9050
|
const pageFiles = existsSync16(appDir) ? findTsxFiles(appDir) : [];
|
|
@@ -9816,7 +9895,7 @@ function checkMissingCssVars(projectRoot) {
|
|
|
9816
9895
|
function patchGlobalsCss(projectRoot, missingVars) {
|
|
9817
9896
|
const globalsPath = join15(projectRoot, "app", "globals.css");
|
|
9818
9897
|
if (!existsSync19(globalsPath) || missingVars.length === 0) return;
|
|
9819
|
-
const { writeFileSync:
|
|
9898
|
+
const { writeFileSync: writeFileSync12 } = __require("fs");
|
|
9820
9899
|
let content = readFileSync13(globalsPath, "utf-8");
|
|
9821
9900
|
const defaultValues = {
|
|
9822
9901
|
"--chart-1": "220 70% 50%",
|
|
@@ -9845,7 +9924,7 @@ function patchGlobalsCss(projectRoot, missingVars) {
|
|
|
9845
9924
|
const lightSectionEnd = content.indexOf("}");
|
|
9846
9925
|
if (lightSectionEnd > 0) {
|
|
9847
9926
|
content = content.slice(0, lightSectionEnd) + "\n" + injection + "\n" + content.slice(lightSectionEnd);
|
|
9848
|
-
|
|
9927
|
+
writeFileSync12(globalsPath, content, "utf-8");
|
|
9849
9928
|
}
|
|
9850
9929
|
}
|
|
9851
9930
|
|
|
@@ -10377,7 +10456,7 @@ async function syncCommand(options = {}) {
|
|
|
10377
10456
|
// src/commands/migrate.ts
|
|
10378
10457
|
import chalk28 from "chalk";
|
|
10379
10458
|
import ora10 from "ora";
|
|
10380
|
-
import { existsSync as existsSync21, mkdirSync as mkdirSync8, cpSync, rmSync as rmSync6, writeFileSync as
|
|
10459
|
+
import { existsSync as existsSync21, mkdirSync as mkdirSync8, cpSync, rmSync as rmSync6, writeFileSync as writeFileSync10, readFileSync as readFileSync15, readdirSync as readdirSync9 } from "fs";
|
|
10381
10460
|
import { join as join17 } from "path";
|
|
10382
10461
|
function backupDir(projectRoot) {
|
|
10383
10462
|
const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
@@ -10402,7 +10481,7 @@ function createBackup2(projectRoot) {
|
|
|
10402
10481
|
function setGuard(projectRoot, backupPath) {
|
|
10403
10482
|
const guard = guardPath(projectRoot);
|
|
10404
10483
|
mkdirSync8(join17(projectRoot, ".coherent"), { recursive: true });
|
|
10405
|
-
|
|
10484
|
+
writeFileSync10(guard, JSON.stringify({ backup: backupPath, startedAt: (/* @__PURE__ */ new Date()).toISOString() }));
|
|
10406
10485
|
}
|
|
10407
10486
|
function clearGuard(projectRoot) {
|
|
10408
10487
|
const guard = guardPath(projectRoot);
|
|
@@ -10506,7 +10585,7 @@ Found ${migratable.length} component(s) to migrate:`));
|
|
|
10506
10585
|
}
|
|
10507
10586
|
|
|
10508
10587
|
// src/utils/update-notifier.ts
|
|
10509
|
-
import { existsSync as existsSync22, mkdirSync as mkdirSync9, readFileSync as readFileSync16, writeFileSync as
|
|
10588
|
+
import { existsSync as existsSync22, mkdirSync as mkdirSync9, readFileSync as readFileSync16, writeFileSync as writeFileSync11 } from "fs";
|
|
10510
10589
|
import { join as join18 } from "path";
|
|
10511
10590
|
import { homedir } from "os";
|
|
10512
10591
|
import chalk29 from "chalk";
|
|
@@ -10529,7 +10608,7 @@ function readCache() {
|
|
|
10529
10608
|
function writeCache(data) {
|
|
10530
10609
|
try {
|
|
10531
10610
|
if (!existsSync22(CACHE_DIR)) mkdirSync9(CACHE_DIR, { recursive: true });
|
|
10532
|
-
|
|
10611
|
+
writeFileSync11(CACHE_FILE, JSON.stringify(data), "utf-8");
|
|
10533
10612
|
} catch (e) {
|
|
10534
10613
|
if (DEBUG5) console.error("Failed to write update cache:", e);
|
|
10535
10614
|
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import "./chunk-3RG5ZIWI.js";
|
|
2
|
+
|
|
3
|
+
// src/utils/mock-data-validator.ts
|
|
4
|
+
function generateRecentIsoDate(offsetHours = 0) {
|
|
5
|
+
const d = /* @__PURE__ */ new Date();
|
|
6
|
+
d.setHours(d.getHours() - offsetHours);
|
|
7
|
+
return d.toISOString();
|
|
8
|
+
}
|
|
9
|
+
function getLineAndCol(code, index) {
|
|
10
|
+
const lines = code.slice(0, index).split("\n");
|
|
11
|
+
return { line: lines.length, column: (lines[lines.length - 1]?.length ?? 0) + 1 };
|
|
12
|
+
}
|
|
13
|
+
function validateMockData(code) {
|
|
14
|
+
const issues = [];
|
|
15
|
+
let offset = 0;
|
|
16
|
+
const dateCtorRe = /new Date\(["']([^"']+)["']\)/g;
|
|
17
|
+
let m;
|
|
18
|
+
while ((m = dateCtorRe.exec(code)) !== null) {
|
|
19
|
+
const dateStr = m[1];
|
|
20
|
+
if (isNaN(new Date(dateStr).getTime())) {
|
|
21
|
+
const { line, column } = getLineAndCol(code, m.index);
|
|
22
|
+
const valueStart = m.index + m[0].indexOf(dateStr);
|
|
23
|
+
const valueEnd = valueStart + dateStr.length;
|
|
24
|
+
issues.push({
|
|
25
|
+
line,
|
|
26
|
+
column,
|
|
27
|
+
message: `Invalid Date: new Date("${dateStr}") will throw at runtime`,
|
|
28
|
+
fixable: true,
|
|
29
|
+
replacement: {
|
|
30
|
+
start: valueStart,
|
|
31
|
+
end: valueEnd,
|
|
32
|
+
text: generateRecentIsoDate(offset++)
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
const mockFieldRe = /(?:timestamp|date|createdAt|updatedAt|time|startDate|endDate|dueDate)\s*:\s*["']((?:\d+\s+(?:hours?|minutes?|days?|weeks?|months?|years?)\s+ago)|yesterday|today|last\s+\w+|just\s+now|recently)["']/gi;
|
|
38
|
+
while ((m = mockFieldRe.exec(code)) !== null) {
|
|
39
|
+
const dateStr = m[1];
|
|
40
|
+
const { line, column } = getLineAndCol(code, m.index);
|
|
41
|
+
const fullMatch = m[0];
|
|
42
|
+
const valueStart = m.index + fullMatch.indexOf(dateStr);
|
|
43
|
+
const valueEnd = valueStart + dateStr.length;
|
|
44
|
+
issues.push({
|
|
45
|
+
line,
|
|
46
|
+
column,
|
|
47
|
+
message: `Mock data "${dateStr}" is a display string, not a valid Date \u2014 use ISO 8601`,
|
|
48
|
+
fixable: true,
|
|
49
|
+
replacement: {
|
|
50
|
+
start: valueStart,
|
|
51
|
+
end: valueEnd,
|
|
52
|
+
text: generateRecentIsoDate(offset++)
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
return issues;
|
|
57
|
+
}
|
|
58
|
+
function applyMockDataFixes(code, issues) {
|
|
59
|
+
const fixable = issues.filter((i) => i.fixable && i.replacement).sort((a, b) => b.replacement.start - a.replacement.start);
|
|
60
|
+
let result = code;
|
|
61
|
+
for (const issue of fixable) {
|
|
62
|
+
const r = issue.replacement;
|
|
63
|
+
result = result.slice(0, r.start) + r.text + result.slice(r.end);
|
|
64
|
+
}
|
|
65
|
+
return result;
|
|
66
|
+
}
|
|
67
|
+
export {
|
|
68
|
+
applyMockDataFixes,
|
|
69
|
+
validateMockData
|
|
70
|
+
};
|
|
@@ -11,8 +11,8 @@ import {
|
|
|
11
11
|
routeToKey,
|
|
12
12
|
savePlan,
|
|
13
13
|
updateArchitecturePlan
|
|
14
|
-
} from "./chunk-
|
|
15
|
-
import "./chunk-
|
|
14
|
+
} from "./chunk-VLBVBF6V.js";
|
|
15
|
+
import "./chunk-E23FJX2I.js";
|
|
16
16
|
import "./chunk-NOM47EB4.js";
|
|
17
17
|
import "./chunk-3RG5ZIWI.js";
|
|
18
18
|
export {
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "0.6.
|
|
6
|
+
"version": "0.6.46",
|
|
7
7
|
"description": "CLI interface for Coherent Design Method",
|
|
8
8
|
"type": "module",
|
|
9
9
|
"main": "./dist/index.js",
|
|
@@ -33,8 +33,15 @@
|
|
|
33
33
|
],
|
|
34
34
|
"author": "Coherent Design Method",
|
|
35
35
|
"license": "MIT",
|
|
36
|
+
"scripts": {
|
|
37
|
+
"dev": "tsup --watch",
|
|
38
|
+
"build": "tsup",
|
|
39
|
+
"typecheck": "tsc --noEmit",
|
|
40
|
+
"test": "vitest"
|
|
41
|
+
},
|
|
36
42
|
"dependencies": {
|
|
37
43
|
"@anthropic-ai/sdk": "^0.32.0",
|
|
44
|
+
"@getcoherent/core": "workspace:*",
|
|
38
45
|
"chalk": "^5.3.0",
|
|
39
46
|
"chokidar": "^4.0.1",
|
|
40
47
|
"commander": "^11.1.0",
|
|
@@ -42,8 +49,7 @@
|
|
|
42
49
|
"open": "^10.1.0",
|
|
43
50
|
"ora": "^7.0.1",
|
|
44
51
|
"prompts": "^2.4.2",
|
|
45
|
-
"zod": "^3.22.4"
|
|
46
|
-
"@getcoherent/core": "0.6.44"
|
|
52
|
+
"zod": "^3.22.4"
|
|
47
53
|
},
|
|
48
54
|
"devDependencies": {
|
|
49
55
|
"@types/node": "^20.11.0",
|
|
@@ -52,11 +58,5 @@
|
|
|
52
58
|
"react": "^19.2.4",
|
|
53
59
|
"tsup": "^8.0.1",
|
|
54
60
|
"typescript": "^5.3.3"
|
|
55
|
-
},
|
|
56
|
-
"scripts": {
|
|
57
|
-
"dev": "tsup --watch",
|
|
58
|
-
"build": "tsup",
|
|
59
|
-
"typecheck": "tsc --noEmit",
|
|
60
|
-
"test": "vitest"
|
|
61
61
|
}
|
|
62
|
-
}
|
|
62
|
+
}
|
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2025 Sergei Kovtun
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|