@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.
@@ -6,7 +6,7 @@ import {
6
6
  getPageGroup,
7
7
  installPackages,
8
8
  sanitizeMetadataStrings
9
- } from "./chunk-KJRBBLXT.js";
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-YOPF773K.js");
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", "Yesterday"), absolute for older ("Jan 26, 2026"). Never ISO format in UI.
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).
@@ -2,7 +2,7 @@ import {
2
2
  CORE_CONSTRAINTS,
3
3
  getDesignQualityForType,
4
4
  inferPageTypeFromRoute
5
- } from "./chunk-5AHG4NNX.js";
5
+ } from "./chunk-E23FJX2I.js";
6
6
  import {
7
7
  autoFixCode
8
8
  } from "./chunk-NOM47EB4.js";
@@ -12,10 +12,10 @@ import {
12
12
  regeneratePage,
13
13
  scanAndInstallSharedDeps,
14
14
  validateAndFixGeneratedCode
15
- } from "./chunk-QE66D55S.js";
16
- import "./chunk-KJRBBLXT.js";
15
+ } from "./chunk-4I7ATX6G.js";
16
+ import "./chunk-VLBVBF6V.js";
17
17
  import "./chunk-4TLYDTT3.js";
18
- import "./chunk-5AHG4NNX.js";
18
+ import "./chunk-E23FJX2I.js";
19
19
  import "./chunk-NOM47EB4.js";
20
20
  import "./chunk-3RG5ZIWI.js";
21
21
  export {
@@ -18,7 +18,7 @@ import {
18
18
  getDesignQualityForType,
19
19
  inferPageTypeFromRoute,
20
20
  selectContextualRules
21
- } from "./chunk-5AHG4NNX.js";
21
+ } from "./chunk-E23FJX2I.js";
22
22
  import "./chunk-3RG5ZIWI.js";
23
23
  export {
24
24
  CORE_CONSTRAINTS,
package/dist/index.js CHANGED
@@ -34,7 +34,7 @@ import {
34
34
  warnIfVolatile,
35
35
  warnInlineDuplicates,
36
36
  writeFile
37
- } from "./chunk-QE66D55S.js";
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-KJRBBLXT.js";
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-5AHG4NNX.js";
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-YOPF773K.js");
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-EIP2XM7T.js");
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
- const allTsxFiles = listTsxFiles(appDir);
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
- const userTsxFiles = allTsxFiles.filter((f) => !f.includes("/design-system/"));
8380
+ let userTsxFiles = allTsxFiles.filter((f) => !f.includes("/design-system/"));
8381
8381
  let syntaxFixed = 0;
8382
8382
  for (const file of userTsxFiles) {
8383
- const content = readFileSync11(file, "utf-8");
8384
- const fixed = fixUnescapedLtInJsx(
8385
- fixEscapedClosingQuotes(sanitizeMetadataStrings(ensureUseClientIfNeeded(content)))
8386
- );
8387
- if (fixed !== content) {
8388
- if (!dryRun) {
8389
- const result = safeWrite(file, fixed, projectRoot, backups);
8390
- if (result.ok) {
8391
- modifiedFiles.push(file);
8392
- syntaxFixed++;
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
- console.log(chalk15.yellow(` \u26A0 Syntax fix rolled back for ${relative5(projectRoot, file)} (parse error)`));
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-YOPF773K.js");
8408
- const { ensurePlanGroupLayouts: ensurePlanGroupLayouts2 } = await import("./code-generator-ASIANBH2.js");
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-ASIANBH2.js");
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-ASIANBH2.js");
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-ASIANBH2.js");
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 userTsxFiles) {
8551
- const content = readFileSync11(file, "utf-8");
8552
- const { code: autoFixed, fixes: fileFixes } = await autoFixCode(content);
8553
- if (autoFixed !== content) {
8554
- if (!dryRun) {
8555
- const qResult = safeWrite(file, autoFixed, projectRoot, backups);
8556
- if (qResult.ok) {
8557
- modifiedFiles.push(file);
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 allTsxFiles) {
8591
- const code = dryRun ? readFileSync11(file, "utf-8") : readFileSync11(file, "utf-8");
8592
- const relativePath = file.replace(projectRoot + "/", "");
8593
- const baseName = file.split("/").pop() || "";
8594
- const isAuthPage = relativePath.includes("(auth)");
8595
- const isNonPageFile = baseName === "layout.tsx" || baseName === "AppNav.tsx" || baseName === "not-found.tsx" || baseName === "ShowWhenNotAuthRoute.tsx";
8596
- const isHomePage = relativePath === "app/page.tsx";
8597
- const isDesignSystem = relativePath.includes("design-system");
8598
- if (isDesignSystem) continue;
8599
- const issues = validatePageQuality(code);
8600
- const suppressH1 = isNonPageFile || isAuthPage;
8601
- const filteredIssues = issues.filter((i) => {
8602
- if (suppressH1 && (i.type === "NO_H1" || i.type === "MULTIPLE_H1")) return false;
8603
- if (isHomePage && i.type === "NO_EMPTY_STATE") return false;
8604
- return true;
8605
- });
8606
- if (filteredIssues.length === 0) continue;
8607
- const errors = filteredIssues.filter((i) => i.severity === "error").length;
8608
- const warnings = filteredIssues.filter((i) => i.severity === "warning").length;
8609
- totalErrors += errors;
8610
- totalWarnings += warnings;
8611
- const report = formatIssues(filteredIssues);
8612
- fileIssues.push({ path: relativePath, report });
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-EIP2XM7T.js");
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: writeFileSync13 } = __require("fs");
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
- writeFileSync13(globalsPath, content, "utf-8");
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 writeFileSync11, readFileSync as readFileSync15, readdirSync as readdirSync9 } from "fs";
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
- writeFileSync11(guard, JSON.stringify({ backup: backupPath, startedAt: (/* @__PURE__ */ new Date()).toISOString() }));
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 writeFileSync12 } from "fs";
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
- writeFileSync12(CACHE_FILE, JSON.stringify(data), "utf-8");
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-KJRBBLXT.js";
15
- import "./chunk-5AHG4NNX.js";
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.44",
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.