@getcoherent/cli 0.5.14 → 0.5.15

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.
Files changed (2) hide show
  1. package/dist/index.js +280 -84
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -1227,9 +1227,7 @@ var COMPONENT_APIS = {
1227
1227
  </CommandGroup>
1228
1228
  </CommandList>
1229
1229
  </Command>`,
1230
- antiPatterns: [
1231
- "NEVER build custom search palette \u2014 use Command/CommandDialog"
1232
- ]
1230
+ antiPatterns: ["NEVER build custom search palette \u2014 use Command/CommandDialog"]
1233
1231
  },
1234
1232
  tabs: {
1235
1233
  name: "Tabs",
@@ -1269,7 +1267,16 @@ var COMPONENT_APIS = {
1269
1267
  },
1270
1268
  table: {
1271
1269
  name: "Table",
1272
- subcomponents: ["Table", "TableHeader", "TableBody", "TableFooter", "TableRow", "TableHead", "TableCell", "TableCaption"],
1270
+ subcomponents: [
1271
+ "Table",
1272
+ "TableHeader",
1273
+ "TableBody",
1274
+ "TableFooter",
1275
+ "TableRow",
1276
+ "TableHead",
1277
+ "TableCell",
1278
+ "TableCaption"
1279
+ ],
1273
1280
  importPath: "@/components/ui/table",
1274
1281
  keyProps: {},
1275
1282
  usage: `<Table>
@@ -1280,9 +1287,7 @@ var COMPONENT_APIS = {
1280
1287
  <TableRow><TableCell>Value</TableCell></TableRow>
1281
1288
  </TableBody>
1282
1289
  </Table>`,
1283
- antiPatterns: [
1284
- "NEVER use native <table> \u2014 use shadcn Table for consistent styling"
1285
- ]
1290
+ antiPatterns: ["NEVER use native <table> \u2014 use shadcn Table for consistent styling"]
1286
1291
  },
1287
1292
  accordion: {
1288
1293
  name: "Accordion",
@@ -1349,17 +1354,15 @@ var ShadcnProvider = class {
1349
1354
  if (!force && deps.existsSync(componentPath)) return;
1350
1355
  try {
1351
1356
  await new Promise((resolve16, reject) => {
1352
- deps.exec(
1353
- `npx shadcn@latest add ${name} --yes --overwrite`,
1354
- { cwd: projectRoot, timeout: 15e3 },
1355
- (err) => {
1356
- if (err) reject(err);
1357
- else resolve16();
1358
- }
1359
- );
1357
+ deps.exec(`npx shadcn@latest add ${name} --yes --overwrite`, { cwd: projectRoot, timeout: 15e3 }, (err) => {
1358
+ if (err) reject(err);
1359
+ else resolve16();
1360
+ });
1360
1361
  });
1361
1362
  } catch {
1362
- console.warn(`Could not install ${name} (network error or timeout). Run \`npx shadcn@latest add ${name}\` manually.`);
1363
+ console.warn(
1364
+ `Could not install ${name} (network error or timeout). Run \`npx shadcn@latest add ${name}\` manually.`
1365
+ );
1363
1366
  }
1364
1367
  }
1365
1368
  async installComponent(id, projectRoot, options) {
@@ -1452,10 +1455,7 @@ var ShadcnProvider = class {
1452
1455
  "ring"
1453
1456
  ];
1454
1457
  const lines = sidebarVars.map((v) => ` --color-sidebar-${v}: var(--sidebar-${v});`);
1455
- const chartLines = Array.from(
1456
- { length: 5 },
1457
- (_, i) => ` --color-chart-${i + 1}: var(--chart-${i + 1});`
1458
- );
1458
+ const chartLines = Array.from({ length: 5 }, (_, i) => ` --color-chart-${i + 1}: var(--chart-${i + 1});`);
1459
1459
  return `@theme inline {
1460
1460
  ${lines.join("\n")}
1461
1461
  ${chartLines.join("\n")}
@@ -1678,7 +1678,8 @@ function createMinimalConfig() {
1678
1678
  framework: "next",
1679
1679
  typescript: true,
1680
1680
  cssFramework: "tailwind",
1681
- autoScaffold: false
1681
+ autoScaffold: false,
1682
+ homePagePlaceholder: true
1682
1683
  },
1683
1684
  createdAt: now,
1684
1685
  updatedAt: now
@@ -3747,7 +3748,7 @@ async function createAppRouteGroupLayout(projectPath) {
3747
3748
  import chalk13 from "chalk";
3748
3749
  import ora2 from "ora";
3749
3750
  import { resolve as resolve9, relative as relative2, join as join11 } from "path";
3750
- import { existsSync as existsSync16, readFileSync as readFileSync10, mkdirSync as mkdirSync6, readdirSync as readdirSync2 } from "fs";
3751
+ import { existsSync as existsSync16, readFileSync as readFileSync11, mkdirSync as mkdirSync6, readdirSync as readdirSync3 } from "fs";
3751
3752
  import {
3752
3753
  DesignSystemManager as DesignSystemManager7,
3753
3754
  ComponentManager as ComponentManager5,
@@ -3911,6 +3912,27 @@ var PAGE_TEMPLATES = {
3911
3912
  "Label"
3912
3913
  ]
3913
3914
  },
3915
+ register: {
3916
+ description: "Registration page with centered card form",
3917
+ sections: [
3918
+ 'Centered layout: outer div className="flex min-h-svh flex-col items-center justify-center p-6 md:p-10". Inner div className="w-full max-w-sm".',
3919
+ 'Card with CardHeader: CardTitle "Create an account" (text-2xl font-bold), CardDescription "Enter your details to get started" (text-sm text-muted-foreground).',
3920
+ 'CardContent with form: name Input, email Input (type="email"), password Input (type="password"), confirm password Input (type="password"), and a Button "Create account" (w-full).',
3921
+ 'CardFooter: text "Already have an account?" with a Sign in link. All text is text-sm text-muted-foreground.',
3922
+ 'This page uses "use client" (has useState for form state). Do NOT include export const metadata.'
3923
+ ],
3924
+ components: [
3925
+ "Card",
3926
+ "CardHeader",
3927
+ "CardTitle",
3928
+ "CardDescription",
3929
+ "CardContent",
3930
+ "CardFooter",
3931
+ "Button",
3932
+ "Input",
3933
+ "Label"
3934
+ ]
3935
+ },
3914
3936
  pricing: {
3915
3937
  description: "Pricing page with tier comparison cards",
3916
3938
  sections: [
@@ -4037,6 +4059,43 @@ var PAGE_TEMPLATES = {
4037
4059
  "Page header. Timeline: each version with version badge, date, list of entries (type: text). Border-left timeline pattern. Badge component for version/date."
4038
4060
  ],
4039
4061
  components: ["Badge"]
4062
+ },
4063
+ team: {
4064
+ description: "Team page with member cards",
4065
+ sections: [
4066
+ 'Page header: h1 "Our Team" className="text-2xl font-bold tracking-tight" + p className="text-sm text-muted-foreground"',
4067
+ 'Grid of team member Cards (className="grid gap-4 md:grid-cols-2 lg:grid-cols-4"). Each card: avatar placeholder (bg-muted rounded-full size-12 with initials), name (text-sm font-semibold), role (text-sm text-muted-foreground).'
4068
+ ],
4069
+ components: ["Card", "CardContent"]
4070
+ },
4071
+ tasks: {
4072
+ description: "Task list page with status badges and search",
4073
+ sections: [
4074
+ 'Page header: h1 "Tasks" + description. Search input with Search icon.',
4075
+ "Task list: divide-y container. Each row: status badge (colored), task title, priority badge, assignee name. Use flex items-center justify-between.",
4076
+ 'This page uses "use client" (has useState for search). Do NOT include export const metadata.'
4077
+ ],
4078
+ components: ["Input", "Badge"]
4079
+ },
4080
+ "task-detail": {
4081
+ description: "Task detail page with info and activity",
4082
+ sections: [
4083
+ "Back button linking to /tasks. Page header with task title and description.",
4084
+ "Two-column layout (md:grid-cols-2): Left Card with task details (status, priority, assignee, due date). Right Card with activity timeline.",
4085
+ 'This page uses "use client" (has useState). Do NOT include export const metadata.'
4086
+ ],
4087
+ components: ["Card", "CardHeader", "CardTitle", "CardContent", "Button"]
4088
+ },
4089
+ "reset-password": {
4090
+ description: "Reset password page with centered card form",
4091
+ sections: [
4092
+ 'Centered layout: outer div className="flex min-h-svh flex-col items-center justify-center p-6 md:p-10". Inner div className="w-full max-w-sm".',
4093
+ 'Card with CardHeader: CardTitle "Reset Password" (text-xl), CardDescription.',
4094
+ 'CardContent with form: new password Input (type="password"), confirm password Input (type="password"), Button "Reset password" (w-full).',
4095
+ 'Footer text: "Remember your password?" with Sign in link.',
4096
+ 'This page uses "use client" (has useState for form state). Do NOT include export const metadata.'
4097
+ ],
4098
+ components: ["Card", "CardHeader", "CardTitle", "CardDescription", "CardContent", "Button", "Input", "Label"]
4040
4099
  }
4041
4100
  };
4042
4101
  var AUTH_ROUTE_SEGMENTS = /* @__PURE__ */ new Set([
@@ -4057,8 +4116,9 @@ function detectPageType(pageName) {
4057
4116
  const normalized = pageName.toLowerCase();
4058
4117
  if (/dashboard|admin|overview/.test(normalized)) return "dashboard";
4059
4118
  if (/login|signin|sign-in/.test(normalized)) return "login";
4119
+ if (/register|signup|sign.?up/.test(normalized)) return "register";
4060
4120
  if (/pricing|plans|subscription/.test(normalized)) return "pricing";
4061
- if (/about|team|company/.test(normalized)) return "about";
4121
+ if (/about|company/.test(normalized)) return "about";
4062
4122
  if (/contact|support|help/.test(normalized)) return "contact";
4063
4123
  if (/settings|preferences|account/.test(normalized)) return "settings";
4064
4124
  if (/home|landing|hero/.test(normalized)) return "landing";
@@ -4069,6 +4129,10 @@ function detectPageType(pageName) {
4069
4129
  if (/gallery|portfolio|images/.test(normalized)) return "gallery";
4070
4130
  if (/faq|frequently|questions/.test(normalized)) return "faq";
4071
4131
  if (/changelog|release|versions/.test(normalized)) return "changelog";
4132
+ if (/team|members/.test(normalized)) return "team";
4133
+ if (/tasks?/.test(normalized) && /detail|\[id\]/.test(normalized)) return "task-detail";
4134
+ if (/tasks?/.test(normalized)) return "tasks";
4135
+ if (/reset.?password/.test(normalized)) return "reset-password";
4072
4136
  return null;
4073
4137
  }
4074
4138
  function expandPageRequest(pageName, userRequest) {
@@ -4154,6 +4218,8 @@ LINKS & INTERACTIVE STATES (consistency is critical):
4154
4218
  - ALL links on the SAME page MUST use the SAME style. Never mix underlined and non-underlined text links.
4155
4219
  - ALL Button variants MUST have: hover: state, focus-visible:ring-2 focus-visible:ring-ring, active: state, disabled:opacity-50.
4156
4220
  - ALL interactive elements MUST have visible hover and focus-visible states.
4221
+ - CRITICAL: Every <Link> MUST have an href prop. Missing href causes runtime errors. Never use <Link className="..."> or <Button asChild><Link> without href.
4222
+ - When shared components exist (@/components/shared/*), ALWAYS import and use them instead of re-implementing similar patterns inline.
4157
4223
 
4158
4224
  ICONS:
4159
4225
  - Size: ALWAYS size-4 (16px). Color: ALWAYS text-muted-foreground. Import: ALWAYS from lucide-react.
@@ -4905,6 +4971,11 @@ async function parseModification(message, context, provider = "auto", options) {
4905
4971
  const navigation = !Array.isArray(raw2) && raw2?.navigation ? raw2.navigation : void 0;
4906
4972
  return { requests: requestsArray2, uxRecommendations: void 0, navigation };
4907
4973
  }
4974
+ if (options?.lightweight) {
4975
+ const raw2 = await ai.parseModification(message);
4976
+ const requestsArray2 = Array.isArray(raw2) ? raw2 : raw2?.requests ?? [];
4977
+ return { requests: requestsArray2, uxRecommendations: void 0 };
4978
+ }
4908
4979
  const componentRegistry = buildComponentRegistry(context.componentManager);
4909
4980
  let enhancedMessage = message;
4910
4981
  let isExpandedPageRequest = false;
@@ -5013,6 +5084,7 @@ For editing an existing shared component use type "modify-layout-block" with tar
5013
5084
  return `You are a design-forward UI architect. Your goal is to create interfaces that are not just functional, but visually distinctive and memorable \u2014 while staying within shadcn/ui and Tailwind CSS.
5014
5085
 
5015
5086
  Parse the user's natural language request into structured modification requests.
5087
+ ${sharedSection}
5016
5088
  ${designThinking}
5017
5089
  ${coreRules}
5018
5090
  ${designQuality}
@@ -5037,7 +5109,6 @@ LINKING RULES (CRITICAL \u2014 prevents broken links):
5037
5109
  - Navigation components should link to ALL existing page routes.
5038
5110
 
5039
5111
  ${componentRegistry}
5040
- ${sharedSection}
5041
5112
 
5042
5113
  Available shadcn/ui components (can be auto-installed): ${availableShadcn.join(", ")}
5043
5114
 
@@ -5264,6 +5335,17 @@ Return valid JSON only, no markdown code fence. Use this shape:
5264
5335
  { "requests": [ ... array of ModificationRequest ... ], "uxRecommendations": "optional markdown or omit key" }
5265
5336
  Legacy: returning only a JSON array of requests is still accepted.`;
5266
5337
  }
5338
+ function buildLightweightPagePrompt(pageName, route, styleContext, sharedComponentsSummary) {
5339
+ return [
5340
+ `Generate complete pageCode for a page called "${pageName}" at route "${route}".`,
5341
+ `Output valid TSX with a default export React component.`,
5342
+ `Use shadcn/ui components (import from @/components/ui/*). Use Tailwind CSS semantic tokens only.`,
5343
+ styleContext ? `Follow this style context:
5344
+ ${styleContext}` : "",
5345
+ sharedComponentsSummary ? `Available shared components:
5346
+ ${sharedComponentsSummary}` : ""
5347
+ ].filter(Boolean).join("\n\n");
5348
+ }
5267
5349
  async function checkComponentReuse(requests, componentManager) {
5268
5350
  const enhanced = [];
5269
5351
  for (const request of requests) {
@@ -6251,6 +6333,17 @@ function validatePageQuality(code, validRoutes) {
6251
6333
  severity: "error"
6252
6334
  });
6253
6335
  }
6336
+ const linkWithoutHrefRe = /<(?:Link|a)\b(?![^>]*\bhref\s*=)[^>]*>/g;
6337
+ let linkNoHrefMatch;
6338
+ while ((linkNoHrefMatch = linkWithoutHrefRe.exec(code)) !== null) {
6339
+ const matchLine = code.slice(0, linkNoHrefMatch.index).split("\n").length;
6340
+ issues.push({
6341
+ line: matchLine,
6342
+ type: "LINK_MISSING_HREF",
6343
+ message: "<Link> or <a> without href prop \u2014 causes Next.js runtime error. Add href attribute.",
6344
+ severity: "error"
6345
+ });
6346
+ }
6254
6347
  issues.push(...detectComponentIssues(code));
6255
6348
  return issues;
6256
6349
  }
@@ -6707,6 +6800,11 @@ ${selectImport}`
6707
6800
  if (fixed !== beforeAsChildFlex) {
6708
6801
  fixes.push("added inline-flex to Button asChild children (base-ui compat)");
6709
6802
  }
6803
+ const beforeLinkHrefFix = fixed;
6804
+ fixed = fixed.replace(/<(Link|a)\b(?![^>]*\bhref\s*=)([^>]*)>/g, '<$1 href="/"$2>');
6805
+ if (fixed !== beforeLinkHrefFix) {
6806
+ fixes.push('added href="/" to <Link>/<a> missing href');
6807
+ }
6710
6808
  const { code: fixedByRules, fixes: ruleFixes } = applyComponentRules(fixed);
6711
6809
  if (ruleFixes.length > 0) {
6712
6810
  fixed = fixedByRules;
@@ -7397,7 +7495,10 @@ function applyDefaults(request) {
7397
7495
 
7398
7496
  // src/commands/chat/split-generator.ts
7399
7497
  import { z } from "zod";
7400
- import { loadManifest as loadManifest5, generateSharedComponent as generateSharedComponent2 } from "@getcoherent/core";
7498
+ import {
7499
+ loadManifest as loadManifest5,
7500
+ generateSharedComponent as generateSharedComponent2
7501
+ } from "@getcoherent/core";
7401
7502
 
7402
7503
  // src/utils/page-analyzer.ts
7403
7504
  var FORM_COMPONENTS = /* @__PURE__ */ new Set(["Input", "Textarea", "Label", "Select", "Checkbox", "Switch"]);
@@ -7604,6 +7705,13 @@ function buildSharedComponentsSummary(manifest) {
7604
7705
  Import: @/components/shared/${importPath}${propsLine}`;
7605
7706
  }).join("\n");
7606
7707
  }
7708
+ function buildSharedComponentsNote(sharedComponentsSummary) {
7709
+ if (!sharedComponentsSummary) return void 0;
7710
+ return `SHARED COMPONENTS \u2014 MANDATORY REUSE:
7711
+ Before implementing any section, check this list. Import and use matching components from @/components/shared/. Do NOT re-implement these patterns inline.
7712
+
7713
+ ${sharedComponentsSummary}`;
7714
+ }
7607
7715
  async function splitGeneratePages(spinner, message, modCtx, provider, parseOpts) {
7608
7716
  let pageNames = [];
7609
7717
  spinner.start("Phase 1/5 \u2014 Planning pages...");
@@ -7667,7 +7775,8 @@ async function splitGeneratePages(spinner, message, modCtx, provider, parseOpts)
7667
7775
  let homeRequest = null;
7668
7776
  let homePageCode = "";
7669
7777
  let reusedExistingAnchor = false;
7670
- if (projectRoot && remainingPages.length > 0) {
7778
+ const isPlaceholder = modCtx.config?.settings?.homePagePlaceholder === true;
7779
+ if (projectRoot && remainingPages.length > 0 && !isPlaceholder) {
7671
7780
  const existingCode = readAnchorPageCodeFromDisk(projectRoot, homePage.route);
7672
7781
  if (existingCode) {
7673
7782
  reusedExistingAnchor = true;
@@ -7733,7 +7842,8 @@ async function splitGeneratePages(spinner, message, modCtx, provider, parseOpts)
7733
7842
  return homeRequest ? [homeRequest] : [];
7734
7843
  }
7735
7844
  spinner.start(`Phase 4/5 \u2014 Generating ${remainingPages.length} pages in parallel...`);
7736
- const sharedNote = "Header and Footer are shared components rendered by the root layout. Do NOT include any site-wide <header>, <nav>, or <footer> in this page. Start with the main content directly.";
7845
+ const sharedLayoutNote = "Header and Footer are shared components rendered by the root layout. Do NOT include any site-wide <header>, <nav>, or <footer> in this page. Start with the main content directly.";
7846
+ const sharedComponentsNote = buildSharedComponentsNote(parseOpts.sharedComponentsSummary);
7737
7847
  const routeNote = `EXISTING ROUTES in this project: ${allRoutes}. All internal links MUST point to one of these routes. If a target doesn't exist, use href="#".`;
7738
7848
  const alignmentNote = 'CRITICAL LAYOUT RULE: Every <section> must wrap its content in a container div matching the header width. Use the EXACT same container classes as shown in the style context (e.g. className="container max-w-6xl px-4" or className="max-w-6xl mx-auto px-4"). Inner content can use narrower max-w for text centering, but the outer section container MUST match.';
7739
7849
  const existingPagesContext = buildExistingPagesContext(modCtx.config);
@@ -7742,13 +7852,17 @@ async function splitGeneratePages(spinner, message, modCtx, provider, parseOpts)
7742
7852
  const remainingRequests = await pMap(
7743
7853
  remainingPages,
7744
7854
  async ({ name, id, route }) => {
7855
+ const isAuth = isAuthRoute(route) || isAuthRoute(name);
7856
+ const authNote = isAuth ? 'For this auth page: use centered card layout with outer div className="flex min-h-svh flex-col items-center justify-center p-6 md:p-10" and inner div className="w-full max-w-sm". Do NOT use section containers or full-width wrappers. The auth layout provides centering \u2014 just output the card content.' : void 0;
7745
7857
  const prompt = [
7746
7858
  `Create ONE page called "${name}" at route "${route}".`,
7747
7859
  `Context: ${message}.`,
7748
7860
  `Generate complete pageCode for this single page only. Do not generate other pages.`,
7749
- sharedNote,
7861
+ sharedLayoutNote,
7862
+ sharedComponentsNote,
7750
7863
  routeNote,
7751
7864
  alignmentNote,
7865
+ authNote,
7752
7866
  existingPagesContext,
7753
7867
  styleContext
7754
7868
  ].filter(Boolean).join("\n\n");
@@ -7768,18 +7882,24 @@ async function splitGeneratePages(spinner, message, modCtx, provider, parseOpts)
7768
7882
  );
7769
7883
  const allRequests = reusedExistingAnchor ? [...remainingRequests] : homeRequest ? [homeRequest, ...remainingRequests] : [...remainingRequests];
7770
7884
  const emptyPages = allRequests.filter((r) => r.type === "add-page" && !r.changes?.pageCode);
7771
- if (emptyPages.length > 0 && emptyPages.length <= 5) {
7885
+ if (emptyPages.length > 0) {
7772
7886
  spinner.text = `Retrying ${emptyPages.length} page(s) without code...`;
7773
7887
  for (const req of emptyPages) {
7774
7888
  const page = req.changes;
7775
7889
  const pageName = page.name || page.id || "page";
7776
7890
  const pageRoute = page.route || `/${pageName.toLowerCase()}`;
7777
7891
  try {
7892
+ const lightweightPrompt = buildLightweightPagePrompt(
7893
+ pageName,
7894
+ pageRoute,
7895
+ styleContext || "",
7896
+ parseOpts.sharedComponentsSummary
7897
+ );
7778
7898
  const retryResult = await parseModification(
7779
- `Create ONE page called "${pageName}" at route "${pageRoute}". Context: ${message}. Generate complete pageCode for this single page only.`,
7899
+ lightweightPrompt,
7780
7900
  modCtx,
7781
7901
  provider,
7782
- parseOpts
7902
+ { ...parseOpts, lightweight: true }
7783
7903
  );
7784
7904
  const codePage = retryResult.requests.find((r) => r.type === "add-page");
7785
7905
  if (codePage && codePage.changes?.pageCode) {
@@ -7825,7 +7945,9 @@ async function extractSharedComponents(homePageCode, projectRoot, aiProvider) {
7825
7945
  } catch {
7826
7946
  return { components: [], summary: buildSharedComponentsSummary(manifest) };
7827
7947
  }
7828
- const reservedSet = new Set(getComponentProvider().listNames().map((n) => n.toLowerCase()));
7948
+ const reservedSet = new Set(
7949
+ getComponentProvider().listNames().map((n) => n.toLowerCase())
7950
+ );
7829
7951
  const existingSet = new Set(manifest.shared.map((e) => e.name.toLowerCase()));
7830
7952
  const seenNames = /* @__PURE__ */ new Set();
7831
7953
  const filtered = rawItems.filter((item) => {
@@ -7916,7 +8038,7 @@ import {
7916
8038
 
7917
8039
  // src/commands/chat/code-generator.ts
7918
8040
  import { resolve as resolve6 } from "path";
7919
- import { existsSync as existsSync14 } from "fs";
8041
+ import { existsSync as existsSync14, readdirSync as readdirSync2, readFileSync as readFileSync9 } from "fs";
7920
8042
  import { mkdir as mkdir3 } from "fs/promises";
7921
8043
  import { dirname as dirname5 } from "path";
7922
8044
  import {
@@ -8096,6 +8218,28 @@ async function regenerateLayout(config2, projectRoot, options = { navChanged: fa
8096
8218
  }
8097
8219
  }
8098
8220
  }
8221
+ async function scanAndInstallSharedDeps(projectRoot) {
8222
+ const sharedDir = resolve6(projectRoot, "components", "shared");
8223
+ if (!existsSync14(sharedDir)) return [];
8224
+ const files = readdirSync2(sharedDir).filter((f) => f.endsWith(".tsx") || f.endsWith(".ts"));
8225
+ const installed = [];
8226
+ const provider = getComponentProvider();
8227
+ for (const file of files) {
8228
+ const code = readFileSync9(resolve6(sharedDir, file), "utf-8");
8229
+ const importMatches = [...code.matchAll(/@\/components\/ui\/([a-z0-9-]+)/g)];
8230
+ for (const [, componentId] of importMatches) {
8231
+ const uiPath = resolve6(projectRoot, "components", "ui", `${componentId}.tsx`);
8232
+ if (!existsSync14(uiPath) && provider.has(componentId)) {
8233
+ try {
8234
+ await provider.installComponent(componentId, projectRoot);
8235
+ installed.push(componentId);
8236
+ } catch {
8237
+ }
8238
+ }
8239
+ }
8240
+ }
8241
+ return [...new Set(installed)];
8242
+ }
8099
8243
  async function ensureAppRouteGroupLayout(projectRoot, navType, forceUpdate = false) {
8100
8244
  const layoutPath = resolve6(projectRoot, "app", "(app)", "layout.tsx");
8101
8245
  if (existsSync14(layoutPath) && !forceUpdate) return;
@@ -8153,6 +8297,10 @@ async function regenerateFiles(modified, config2, projectRoot, options = { navCh
8153
8297
  navChanged: options.navChanged,
8154
8298
  storedHashes: options.storedHashes
8155
8299
  });
8300
+ const sharedInstalled = await scanAndInstallSharedDeps(projectRoot);
8301
+ if (sharedInstalled.length > 0 && process.env.COHERENT_DEBUG === "1") {
8302
+ console.log(chalk9.dim(` Auto-installed shared deps: ${sharedInstalled.join(", ")}`));
8303
+ }
8156
8304
  }
8157
8305
  if (componentIds.size > 0) {
8158
8306
  const twGen = new TailwindConfigGenerator(config2);
@@ -8898,7 +9046,7 @@ async function applyModification(request, dsm, cm, pm, projectRoot, aiProvider,
8898
9046
  }
8899
9047
  const { code: layoutStripped, stripped } = stripInlineLayoutElements(codeToWrite);
8900
9048
  codeToWrite = layoutStripped;
8901
- if (!isMarketingRoute(route)) {
9049
+ if (!isMarketingRoute(route) && !isAuthRoute(route)) {
8902
9050
  const { code: normalized, fixed: wrapperFixed } = normalizePageWrapper(codeToWrite);
8903
9051
  if (wrapperFixed) {
8904
9052
  codeToWrite = normalized;
@@ -9098,7 +9246,7 @@ ${pagesCtx}`
9098
9246
  }
9099
9247
  const { code: layoutStripped, stripped } = stripInlineLayoutElements(codeToWrite);
9100
9248
  codeToWrite = layoutStripped;
9101
- if (!isMarketingRoute(route)) {
9249
+ if (!isMarketingRoute(route) && !isAuthRoute(route)) {
9102
9250
  const { code: normalized, fixed: wrapperFixed } = normalizePageWrapper(codeToWrite);
9103
9251
  if (wrapperFixed) {
9104
9252
  codeToWrite = normalized;
@@ -9219,6 +9367,11 @@ function inferPageType(route, name) {
9219
9367
  if (/\bchangelog\b/.test(key)) return "changelog";
9220
9368
  if (/\babout\b/.test(key)) return "about";
9221
9369
  if (/\bsettings?\b/.test(key)) return "settings";
9370
+ if (/\bteam\b|\bmember\b/.test(key)) return "team";
9371
+ if (/\btasks?\b/.test(key) && /\[id\]|\bdetail\b/.test(key)) return "task-detail";
9372
+ if (/\btasks?\b/.test(key)) return "tasks";
9373
+ if (/\breset.?password\b/.test(key)) return "reset-password";
9374
+ if (/\bprofile\b|\baccount\b/.test(key)) return "profile";
9222
9375
  return null;
9223
9376
  }
9224
9377
  function getDefaultContent(pageType, pageName) {
@@ -9262,6 +9415,26 @@ function getDefaultContent(pageType, pageName) {
9262
9415
  settings: {
9263
9416
  title: "Settings",
9264
9417
  description: "Manage your account and preferences"
9418
+ },
9419
+ team: {
9420
+ title: "Our Team",
9421
+ description: "Meet the people behind the product"
9422
+ },
9423
+ tasks: {
9424
+ title: "Tasks",
9425
+ description: "Manage and track your tasks"
9426
+ },
9427
+ "task-detail": {
9428
+ title: "Task Detail",
9429
+ description: "View task details and activity"
9430
+ },
9431
+ "reset-password": {
9432
+ title: "Reset Password",
9433
+ description: "Enter your new password"
9434
+ },
9435
+ profile: {
9436
+ title: "Profile",
9437
+ description: "View and edit your profile"
9265
9438
  }
9266
9439
  };
9267
9440
  return defaults[pageType] || { title: pageName, description: "" };
@@ -9279,7 +9452,7 @@ function hasNavChanged(before, after) {
9279
9452
  // src/commands/chat/interactive.ts
9280
9453
  import chalk12 from "chalk";
9281
9454
  import { resolve as resolve8 } from "path";
9282
- import { existsSync as existsSync15, readFileSync as readFileSync9, writeFileSync as writeFileSync8, mkdirSync as mkdirSync5 } from "fs";
9455
+ import { existsSync as existsSync15, readFileSync as readFileSync10, writeFileSync as writeFileSync8, mkdirSync as mkdirSync5 } from "fs";
9283
9456
  import { DesignSystemManager as DesignSystemManager6, ComponentManager as ComponentManager4, loadManifest as loadManifest7 } from "@getcoherent/core";
9284
9457
  var DEBUG3 = process.env.COHERENT_DEBUG === "1";
9285
9458
  async function interactiveChat(options, chatCommandFn) {
@@ -9305,7 +9478,7 @@ async function interactiveChat(options, chatCommandFn) {
9305
9478
  try {
9306
9479
  mkdirSync5(historyDir, { recursive: true });
9307
9480
  if (existsSync15(historyFile)) {
9308
- history = readFileSync9(historyFile, "utf-8").split("\n").filter(Boolean).slice(-200);
9481
+ history = readFileSync10(historyFile, "utf-8").split("\n").filter(Boolean).slice(-200);
9309
9482
  }
9310
9483
  } catch (e) {
9311
9484
  if (DEBUG3) console.error("Failed to load REPL history:", e);
@@ -9772,7 +9945,7 @@ async function chatCommand(message, options) {
9772
9945
  try {
9773
9946
  const sharedPath = resolve9(projectRoot, entry.file);
9774
9947
  if (existsSync16(sharedPath)) {
9775
- const sharedCode = readFileSync10(sharedPath, "utf-8");
9948
+ const sharedCode = readFileSync11(sharedPath, "utf-8");
9776
9949
  const sharedImports = sharedCode.matchAll(/@\/components\/ui\/([a-z0-9-]+)/g);
9777
9950
  for (const m of sharedImports) {
9778
9951
  if (m[1]) allNeededComponentIds.add(m[1]);
@@ -9814,7 +9987,10 @@ async function chatCommand(message, options) {
9814
9987
  if (DEBUG4) console.log(chalk13.gray(` [DEBUG] installComponent result: ${result.success}`));
9815
9988
  if (result.success && result.componentDef) {
9816
9989
  if (!cm.read(componentId)) {
9817
- if (DEBUG4) console.log(chalk13.gray(` [DEBUG] Registering ${result.componentDef.id} (${result.componentDef.name})`));
9990
+ if (DEBUG4)
9991
+ console.log(
9992
+ chalk13.gray(` [DEBUG] Registering ${result.componentDef.id} (${result.componentDef.name})`)
9993
+ );
9818
9994
  const regResult = await cm.register(result.componentDef);
9819
9995
  if (DEBUG4) {
9820
9996
  console.log(
@@ -9894,6 +10070,17 @@ async function chatCommand(message, options) {
9894
10070
  const result = await applyModification(request, dsm, cm, pm, projectRoot, provider, message);
9895
10071
  results.push(result);
9896
10072
  }
10073
+ for (const request of normalizedRequests) {
10074
+ const changes = request.changes;
10075
+ if ((request.type === "add-page" || request.type === "update-page") && changes?.route === "/" && changes?.pageCode) {
10076
+ const cfg = dsm.getConfig();
10077
+ if (cfg.settings.homePagePlaceholder) {
10078
+ cfg.settings.homePagePlaceholder = false;
10079
+ dsm.updateConfig(cfg);
10080
+ }
10081
+ break;
10082
+ }
10083
+ }
9897
10084
  const currentConfig = dsm.getConfig();
9898
10085
  const autoScaffoldEnabled = currentConfig.settings.autoScaffold === true;
9899
10086
  const scaffoldedPages = [];
@@ -9907,7 +10094,7 @@ async function chatCommand(message, options) {
9907
10094
  let pageCode = "";
9908
10095
  if (existsSync16(pageFilePath)) {
9909
10096
  try {
9910
- pageCode = readFileSync10(pageFilePath, "utf-8");
10097
+ pageCode = readFileSync11(pageFilePath, "utf-8");
9911
10098
  } catch {
9912
10099
  }
9913
10100
  }
@@ -10018,7 +10205,7 @@ async function chatCommand(message, options) {
10018
10205
  for (const mod of result.modified) {
10019
10206
  if (mod.startsWith("app/") && mod.endsWith("/page.tsx")) {
10020
10207
  try {
10021
- const code = readFileSync10(resolve9(projectRoot, mod), "utf-8");
10208
+ const code = readFileSync11(resolve9(projectRoot, mod), "utf-8");
10022
10209
  const issues = validatePageQuality(code, allRoutes).filter(
10023
10210
  (i) => i.type === "BROKEN_INTERNAL_LINK"
10024
10211
  );
@@ -10088,6 +10275,10 @@ async function chatCommand(message, options) {
10088
10275
  await regenerateFiles(Array.from(allModified), updatedConfig, projectRoot, { navChanged, storedHashes });
10089
10276
  spinner.succeed("Files regenerated");
10090
10277
  }
10278
+ const finalDeps = await scanAndInstallSharedDeps(projectRoot);
10279
+ if (finalDeps.length > 0) {
10280
+ console.log(chalk13.dim(` Auto-installed shared deps: ${finalDeps.join(", ")}`));
10281
+ }
10091
10282
  try {
10092
10283
  fixGlobalsCss(projectRoot, updatedConfig);
10093
10284
  } catch {
@@ -10098,7 +10289,7 @@ async function chatCommand(message, options) {
10098
10289
  const layoutFile = resolve9(projectRoot, "app", "layout.tsx");
10099
10290
  const filesToHash = [layoutFile];
10100
10291
  if (existsSync16(sharedDir)) {
10101
- for (const f of readdirSync2(sharedDir)) {
10292
+ for (const f of readdirSync3(sharedDir)) {
10102
10293
  if (f.endsWith(".tsx")) filesToHash.push(resolve9(sharedDir, f));
10103
10294
  }
10104
10295
  }
@@ -10218,18 +10409,18 @@ ${uxRecommendations}
10218
10409
  import chalk14 from "chalk";
10219
10410
  import ora3 from "ora";
10220
10411
  import { spawn } from "child_process";
10221
- import { existsSync as existsSync19, rmSync as rmSync3, readFileSync as readFileSync13, writeFileSync as writeFileSync10 } from "fs";
10412
+ import { existsSync as existsSync19, rmSync as rmSync3, readFileSync as readFileSync14, writeFileSync as writeFileSync10, readdirSync as readdirSync5 } from "fs";
10222
10413
  import { resolve as resolve10, join as join14 } from "path";
10223
10414
  import { readdir as readdir2 } from "fs/promises";
10224
10415
  import { DesignSystemManager as DesignSystemManager8, ComponentGenerator as ComponentGenerator3 } from "@getcoherent/core";
10225
10416
 
10226
10417
  // src/utils/file-watcher.ts
10227
- import { readFileSync as readFileSync12, writeFileSync as writeFileSync9, existsSync as existsSync18 } from "fs";
10418
+ import { readFileSync as readFileSync13, writeFileSync as writeFileSync9, existsSync as existsSync18 } from "fs";
10228
10419
  import { relative as relative4, join as join13 } from "path";
10229
10420
  import { loadManifest as loadManifest9, saveManifest as saveManifest3 } from "@getcoherent/core";
10230
10421
 
10231
10422
  // src/utils/component-integrity.ts
10232
- import { existsSync as existsSync17, readFileSync as readFileSync11, readdirSync as readdirSync3 } from "fs";
10423
+ import { existsSync as existsSync17, readFileSync as readFileSync12, readdirSync as readdirSync4 } from "fs";
10233
10424
  import { join as join12, relative as relative3 } from "path";
10234
10425
  function extractExportedComponentNames(code) {
10235
10426
  const names = [];
@@ -10263,7 +10454,7 @@ function findPagesImporting(projectRoot, componentName, componentFile) {
10263
10454
  for (const absPath of pageFiles) {
10264
10455
  if (absPath.includes("design-system")) continue;
10265
10456
  try {
10266
- const code = readFileSync11(absPath, "utf-8");
10457
+ const code = readFileSync12(absPath, "utf-8");
10267
10458
  const hasNamedImport = new RegExp(`import\\s+\\{[^}]*\\b${componentName}\\b[^}]*\\}\\s+from\\s+['"]`).test(code);
10268
10459
  const hasDefaultImport = new RegExp(`import\\s+${componentName}\\s+from\\s+['"]`).test(code);
10269
10460
  const hasPathImport = code.includes(`@/${componentImportPath}`);
@@ -10279,7 +10470,7 @@ function isUsedInLayout(projectRoot, componentName) {
10279
10470
  const layoutPath = join12(projectRoot, "app", "layout.tsx");
10280
10471
  if (!existsSync17(layoutPath)) return false;
10281
10472
  try {
10282
- const code = readFileSync11(layoutPath, "utf-8");
10473
+ const code = readFileSync12(layoutPath, "utf-8");
10283
10474
  return code.includes(componentName);
10284
10475
  } catch {
10285
10476
  return false;
@@ -10300,7 +10491,7 @@ function findUnregisteredComponents(projectRoot, manifest) {
10300
10491
  const relFile = relative3(projectRoot, absPath);
10301
10492
  if (registeredFiles.has(relFile)) continue;
10302
10493
  try {
10303
- const code = readFileSync11(absPath, "utf-8");
10494
+ const code = readFileSync12(absPath, "utf-8");
10304
10495
  const exports = extractExportedComponentNames(code);
10305
10496
  for (const name of exports) {
10306
10497
  if (registeredNames.has(name)) continue;
@@ -10322,7 +10513,7 @@ function findInlineDuplicates(projectRoot, manifest) {
10322
10513
  if (absPath.includes("design-system")) continue;
10323
10514
  let code;
10324
10515
  try {
10325
- code = readFileSync11(absPath, "utf-8");
10516
+ code = readFileSync12(absPath, "utf-8");
10326
10517
  } catch {
10327
10518
  continue;
10328
10519
  }
@@ -10354,7 +10545,7 @@ function findComponentFileByExportName(projectRoot, componentName) {
10354
10545
  );
10355
10546
  for (const absPath of files) {
10356
10547
  try {
10357
- const code = readFileSync11(absPath, "utf-8");
10548
+ const code = readFileSync12(absPath, "utf-8");
10358
10549
  const exports = extractExportedComponentNames(code);
10359
10550
  if (exports.includes(componentName)) {
10360
10551
  return relative3(projectRoot, absPath);
@@ -10399,7 +10590,7 @@ function reconcileComponents(projectRoot, manifest) {
10399
10590
  }
10400
10591
  let code;
10401
10592
  try {
10402
- code = readFileSync11(join12(projectRoot, entry.file), "utf-8");
10593
+ code = readFileSync12(join12(projectRoot, entry.file), "utf-8");
10403
10594
  } catch {
10404
10595
  return true;
10405
10596
  }
@@ -10476,7 +10667,7 @@ function collectFiles(dir, filter, skipDirs = []) {
10476
10667
  function walk(d) {
10477
10668
  let entries;
10478
10669
  try {
10479
- entries = readdirSync3(d, { withFileTypes: true });
10670
+ entries = readdirSync4(d, { withFileTypes: true });
10480
10671
  } catch {
10481
10672
  return;
10482
10673
  }
@@ -10522,7 +10713,7 @@ function getWatcherConfig(projectRoot) {
10522
10713
  try {
10523
10714
  const pkgPath = join13(projectRoot, "package.json");
10524
10715
  if (!existsSync18(pkgPath)) return defaultWatcherConfig();
10525
- const pkg = JSON.parse(readFileSync12(pkgPath, "utf-8"));
10716
+ const pkg = JSON.parse(readFileSync13(pkgPath, "utf-8"));
10526
10717
  const c = pkg?.coherent?.watcher ?? {};
10527
10718
  return {
10528
10719
  enabled: c.enabled !== false,
@@ -10550,7 +10741,7 @@ async function handleFileChange(projectRoot, filePath) {
10550
10741
  if (relativePath.includes("node_modules") || relativePath.includes(".next")) return;
10551
10742
  let content;
10552
10743
  try {
10553
- content = readFileSync12(filePath, "utf-8");
10744
+ content = readFileSync13(filePath, "utf-8");
10554
10745
  } catch {
10555
10746
  return;
10556
10747
  }
@@ -10623,7 +10814,7 @@ async function detectNewComponent(projectRoot, filePath) {
10623
10814
  const manifest = await loadManifest9(projectRoot);
10624
10815
  const alreadyRegistered = manifest.shared.some((s) => s.file === relativePath);
10625
10816
  if (alreadyRegistered) return;
10626
- const code = readFileSync12(filePath, "utf-8");
10817
+ const code = readFileSync13(filePath, "utf-8");
10627
10818
  const exports = extractExportedComponentNames(code);
10628
10819
  if (exports.length > 0) {
10629
10820
  const alreadyByName = exports.every((n) => manifest.shared.some((s) => s.name === n));
@@ -10747,7 +10938,7 @@ async function validateSyntax(projectRoot) {
10747
10938
  const appDir = join14(projectRoot, "app");
10748
10939
  const pages = await listPageFiles(appDir);
10749
10940
  for (const file of pages) {
10750
- const content = readFileSync13(file, "utf-8");
10941
+ const content = readFileSync14(file, "utf-8");
10751
10942
  const fixed = fixUnescapedLtInJsx(sanitizeMetadataStrings(ensureUseClientIfNeeded(content)));
10752
10943
  if (fixed !== content) {
10753
10944
  writeFileSync10(file, fixed, "utf-8");
@@ -10760,9 +10951,14 @@ async function fixMissingComponentExports(projectRoot) {
10760
10951
  const uiDir = join14(projectRoot, "components", "ui");
10761
10952
  if (!existsSync19(appDir) || !existsSync19(uiDir)) return;
10762
10953
  const pages = await listPageFiles(appDir);
10954
+ const sharedDir = join14(projectRoot, "components", "shared");
10955
+ if (existsSync19(sharedDir)) {
10956
+ const sharedFiles = readdirSync5(sharedDir).filter((f) => f.endsWith(".tsx") || f.endsWith(".ts")).map((f) => join14(sharedDir, f));
10957
+ pages.push(...sharedFiles);
10958
+ }
10763
10959
  const neededExports = /* @__PURE__ */ new Map();
10764
10960
  for (const file of pages) {
10765
- const content = readFileSync13(file, "utf-8");
10961
+ const content = readFileSync14(file, "utf-8");
10766
10962
  const importRe = /import\s*\{([^}]+)\}\s*from\s*['"]@\/components\/ui\/([^'"]+)['"]/g;
10767
10963
  let m;
10768
10964
  while ((m = importRe.exec(content)) !== null) {
@@ -10806,7 +11002,7 @@ async function fixMissingComponentExports(projectRoot) {
10806
11002
  }
10807
11003
  continue;
10808
11004
  }
10809
- const content = readFileSync13(componentFile, "utf-8");
11005
+ const content = readFileSync14(componentFile, "utf-8");
10810
11006
  const exportRe = /export\s+(?:const|function|class)\s+(\w+)|export\s*\{([^}]+)\}/g;
10811
11007
  const existingExports = /* @__PURE__ */ new Set();
10812
11008
  let em;
@@ -10859,7 +11055,7 @@ async function backfillPageAnalysis(projectRoot) {
10859
11055
  filePath = join14(projectRoot, "app", route.slice(1), "page.tsx");
10860
11056
  }
10861
11057
  if (!existsSync19(filePath)) continue;
10862
- const code = readFileSync13(filePath, "utf-8");
11058
+ const code = readFileSync14(filePath, "utf-8");
10863
11059
  if (code.length < 50) continue;
10864
11060
  page.pageAnalysis = analyzePageCode(code);
10865
11061
  changed = true;
@@ -11100,7 +11296,7 @@ async function previewCommand() {
11100
11296
  import chalk15 from "chalk";
11101
11297
  import ora4 from "ora";
11102
11298
  import { spawn as spawn2 } from "child_process";
11103
- import { existsSync as existsSync20, rmSync as rmSync4, readdirSync as readdirSync4 } from "fs";
11299
+ import { existsSync as existsSync20, rmSync as rmSync4, readdirSync as readdirSync6 } from "fs";
11104
11300
  import { resolve as resolve11, join as join15, dirname as dirname7 } from "path";
11105
11301
  import { readdir as readdir3, readFile as readFile6, writeFile as writeFile5, mkdir as mkdir5, copyFile as copyFile2 } from "fs/promises";
11106
11302
  var COPY_EXCLUDE = /* @__PURE__ */ new Set([
@@ -11221,7 +11417,7 @@ function countComponents(outRoot) {
11221
11417
  const dir = join15(outRoot, "components", sub);
11222
11418
  if (!existsSync20(dir)) continue;
11223
11419
  try {
11224
- n += readdirSync4(dir).filter((f) => f.endsWith(".tsx") || f.endsWith(".jsx")).length;
11420
+ n += readdirSync6(dir).filter((f) => f.endsWith(".tsx") || f.endsWith(".jsx")).length;
11225
11421
  } catch {
11226
11422
  }
11227
11423
  }
@@ -11540,7 +11736,7 @@ async function regenerateDocsCommand() {
11540
11736
 
11541
11737
  // src/commands/fix.ts
11542
11738
  import chalk18 from "chalk";
11543
- import { readdirSync as readdirSync5, readFileSync as readFileSync14, existsSync as existsSync21, writeFileSync as writeFileSync11, rmSync as rmSync5, mkdirSync as mkdirSync7 } from "fs";
11739
+ import { readdirSync as readdirSync7, readFileSync as readFileSync15, existsSync as existsSync21, writeFileSync as writeFileSync11, rmSync as rmSync5, mkdirSync as mkdirSync7 } from "fs";
11544
11740
  import { resolve as resolve12, join as join16 } from "path";
11545
11741
  import {
11546
11742
  DesignSystemManager as DesignSystemManager11,
@@ -11565,7 +11761,7 @@ function extractComponentIdsFromCode2(code) {
11565
11761
  function listTsxFiles(dir) {
11566
11762
  const files = [];
11567
11763
  try {
11568
- const entries = readdirSync5(dir, { withFileTypes: true });
11764
+ const entries = readdirSync7(dir, { withFileTypes: true });
11569
11765
  for (const e of entries) {
11570
11766
  const full = join16(dir, e.name);
11571
11767
  if (e.isDirectory() && e.name !== "node_modules" && !e.name.startsWith(".")) {
@@ -11624,7 +11820,7 @@ async function fixCommand(opts = {}) {
11624
11820
  const componentsTsxFiles = listTsxFiles(resolve12(projectRoot, "components"));
11625
11821
  const allComponentIds = /* @__PURE__ */ new Set();
11626
11822
  for (const file of [...allTsxFiles, ...componentsTsxFiles]) {
11627
- const content = readFileSync14(file, "utf-8");
11823
+ const content = readFileSync15(file, "utf-8");
11628
11824
  extractComponentIdsFromCode2(content).forEach((id) => allComponentIds.add(id));
11629
11825
  }
11630
11826
  let dsm = null;
@@ -11696,7 +11892,7 @@ async function fixCommand(opts = {}) {
11696
11892
  const userTsxFiles = allTsxFiles.filter((f) => !f.includes("/design-system/"));
11697
11893
  let syntaxFixed = 0;
11698
11894
  for (const file of userTsxFiles) {
11699
- const content = readFileSync14(file, "utf-8");
11895
+ const content = readFileSync15(file, "utf-8");
11700
11896
  const fixed = fixUnescapedLtInJsx(
11701
11897
  fixEscapedClosingQuotes(sanitizeMetadataStrings(ensureUseClientIfNeeded(content)))
11702
11898
  );
@@ -11714,7 +11910,7 @@ async function fixCommand(opts = {}) {
11714
11910
  let qualityFixCount = 0;
11715
11911
  const qualityFixDetails = [];
11716
11912
  for (const file of userTsxFiles) {
11717
- const content = readFileSync14(file, "utf-8");
11913
+ const content = readFileSync15(file, "utf-8");
11718
11914
  const { code: autoFixed, fixes: fileFixes } = await autoFixCode(content);
11719
11915
  if (autoFixed !== content) {
11720
11916
  if (!dryRun) writeFileSync11(file, autoFixed, "utf-8");
@@ -11733,7 +11929,7 @@ async function fixCommand(opts = {}) {
11733
11929
  let totalWarnings = 0;
11734
11930
  const fileIssues = [];
11735
11931
  for (const file of allTsxFiles) {
11736
- const code = dryRun ? readFileSync14(file, "utf-8") : readFileSync14(file, "utf-8");
11932
+ const code = dryRun ? readFileSync15(file, "utf-8") : readFileSync15(file, "utf-8");
11737
11933
  const relativePath = file.replace(projectRoot + "/", "");
11738
11934
  const baseName = file.split("/").pop() || "";
11739
11935
  const isAuthPage = relativePath.includes("(auth)");
@@ -11856,13 +12052,13 @@ async function fixCommand(opts = {}) {
11856
12052
  // src/commands/check.ts
11857
12053
  import chalk19 from "chalk";
11858
12054
  import { resolve as resolve13 } from "path";
11859
- import { readdirSync as readdirSync6, readFileSync as readFileSync15, statSync as statSync2, existsSync as existsSync22 } from "fs";
12055
+ import { readdirSync as readdirSync8, readFileSync as readFileSync16, statSync as statSync2, existsSync as existsSync22 } from "fs";
11860
12056
  import { loadManifest as loadManifest11 } from "@getcoherent/core";
11861
12057
  var EXCLUDED_DIRS = /* @__PURE__ */ new Set(["node_modules", "design-system"]);
11862
12058
  function findTsxFiles(dir) {
11863
12059
  const results = [];
11864
12060
  try {
11865
- const entries = readdirSync6(dir);
12061
+ const entries = readdirSync8(dir);
11866
12062
  for (const entry of entries) {
11867
12063
  const full = resolve13(dir, entry);
11868
12064
  const stat = statSync2(full);
@@ -11913,7 +12109,7 @@ async function checkCommand(opts = {}) {
11913
12109
  "NATIVE_TABLE"
11914
12110
  ]);
11915
12111
  for (const file of files) {
11916
- const code = readFileSync15(file, "utf-8");
12112
+ const code = readFileSync16(file, "utf-8");
11917
12113
  const relativePath = file.replace(projectRoot + "/", "");
11918
12114
  const baseName = file.split("/").pop() || "";
11919
12115
  const isAuthPage = relativePath.includes("(auth)");
@@ -11955,7 +12151,7 @@ async function checkCommand(opts = {}) {
11955
12151
  routeSet.add("/");
11956
12152
  routeSet.add("#");
11957
12153
  for (const file of files) {
11958
- const code = readFileSync15(file, "utf-8");
12154
+ const code = readFileSync16(file, "utf-8");
11959
12155
  const relativePath = file.replace(projectRoot + "/", "");
11960
12156
  const lines = code.split("\n");
11961
12157
  const linkHrefRe = /href\s*=\s*["'](\/[a-z0-9/-]*)["']/gi;
@@ -12023,7 +12219,7 @@ async function checkCommand(opts = {}) {
12023
12219
  continue;
12024
12220
  }
12025
12221
  try {
12026
- const code = readFileSync15(filePath, "utf-8");
12222
+ const code = readFileSync16(filePath, "utf-8");
12027
12223
  const actualExports = extractExportedComponentNames(code);
12028
12224
  if (actualExports.length > 0 && !actualExports.includes(entry.name)) {
12029
12225
  _nameMismatch++;
@@ -12714,7 +12910,7 @@ async function dsRegenerateCommand() {
12714
12910
  // src/commands/update.ts
12715
12911
  import chalk28 from "chalk";
12716
12912
  import ora8 from "ora";
12717
- import { readFileSync as readFileSync16, existsSync as existsSync25 } from "fs";
12913
+ import { readFileSync as readFileSync17, existsSync as existsSync25 } from "fs";
12718
12914
  import { join as join19 } from "path";
12719
12915
  import { DesignSystemManager as DesignSystemManager15, CLI_VERSION as CLI_VERSION4 } from "@getcoherent/core";
12720
12916
 
@@ -12887,7 +13083,7 @@ function checkMissingCssVars(projectRoot) {
12887
13083
  const globalsPath = join19(projectRoot, "app", "globals.css");
12888
13084
  if (!existsSync25(globalsPath)) return [];
12889
13085
  try {
12890
- const content = readFileSync16(globalsPath, "utf-8");
13086
+ const content = readFileSync17(globalsPath, "utf-8");
12891
13087
  return EXPECTED_CSS_VARS.filter((v) => !content.includes(v));
12892
13088
  } catch {
12893
13089
  return [];
@@ -12897,7 +13093,7 @@ function patchGlobalsCss(projectRoot, missingVars) {
12897
13093
  const globalsPath = join19(projectRoot, "app", "globals.css");
12898
13094
  if (!existsSync25(globalsPath) || missingVars.length === 0) return;
12899
13095
  const { writeFileSync: writeFileSync14 } = __require("fs");
12900
- let content = readFileSync16(globalsPath, "utf-8");
13096
+ let content = readFileSync17(globalsPath, "utf-8");
12901
13097
  const defaultValues = {
12902
13098
  "--chart-1": "220 70% 50%",
12903
13099
  "--chart-2": "160 60% 45%",
@@ -12975,7 +13171,7 @@ async function undoCommand(options) {
12975
13171
  // src/commands/sync.ts
12976
13172
  import chalk30 from "chalk";
12977
13173
  import ora9 from "ora";
12978
- import { existsSync as existsSync26, readFileSync as readFileSync17 } from "fs";
13174
+ import { existsSync as existsSync26, readFileSync as readFileSync18 } from "fs";
12979
13175
  import { join as join20, relative as relative5, dirname as dirname10 } from "path";
12980
13176
  import { readdir as readdir4, readFile as readFile7 } from "fs/promises";
12981
13177
  import { DesignSystemManager as DesignSystemManager16 } from "@getcoherent/core";
@@ -12985,7 +13181,7 @@ function extractTokensFromProject(projectRoot) {
12985
13181
  const darkColors = {};
12986
13182
  const globalsPath = join20(projectRoot, "app", "globals.css");
12987
13183
  if (existsSync26(globalsPath)) {
12988
- const css = readFileSync17(globalsPath, "utf-8");
13184
+ const css = readFileSync18(globalsPath, "utf-8");
12989
13185
  const rootMatch = css.match(/:root\s*\{([^}]+)\}/s);
12990
13186
  if (rootMatch) parseVarsInto(rootMatch[1], lightColors);
12991
13187
  const darkMatch = css.match(/\.dark\s*\{([^}]+)\}/s);
@@ -12994,7 +13190,7 @@ function extractTokensFromProject(projectRoot) {
12994
13190
  const layoutPath = join20(projectRoot, "app", "layout.tsx");
12995
13191
  let layoutCode = "";
12996
13192
  if (existsSync26(layoutPath)) {
12997
- layoutCode = readFileSync17(layoutPath, "utf-8");
13193
+ layoutCode = readFileSync18(layoutPath, "utf-8");
12998
13194
  const rootInline = layoutCode.match(/:root\s*\{([^}]+)\}/s);
12999
13195
  if (rootInline && Object.keys(lightColors).length === 0) {
13000
13196
  parseVarsInto(rootInline[1], lightColors);
@@ -13012,7 +13208,7 @@ function extractTokensFromProject(projectRoot) {
13012
13208
  defaultMode = "dark";
13013
13209
  }
13014
13210
  let radius;
13015
- const allCss = [existsSync26(globalsPath) ? readFileSync17(globalsPath, "utf-8") : "", layoutCode].join("\n");
13211
+ const allCss = [existsSync26(globalsPath) ? readFileSync18(globalsPath, "utf-8") : "", layoutCode].join("\n");
13016
13212
  const radiusMatch = allCss.match(/--radius:\s*([^;]+);/);
13017
13213
  if (radiusMatch) radius = radiusMatch[1].trim();
13018
13214
  return {
@@ -13442,7 +13638,7 @@ async function syncCommand(options = {}) {
13442
13638
  // src/commands/migrate.ts
13443
13639
  import chalk31 from "chalk";
13444
13640
  import ora10 from "ora";
13445
- import { existsSync as existsSync27, mkdirSync as mkdirSync8, cpSync, rmSync as rmSync6, writeFileSync as writeFileSync12, readFileSync as readFileSync18, readdirSync as readdirSync7 } from "fs";
13641
+ import { existsSync as existsSync27, mkdirSync as mkdirSync8, cpSync, rmSync as rmSync6, writeFileSync as writeFileSync12, readFileSync as readFileSync19, readdirSync as readdirSync9 } from "fs";
13446
13642
  import { join as join21 } from "path";
13447
13643
  function backupDir(projectRoot) {
13448
13644
  const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
@@ -13477,7 +13673,7 @@ function rollback(projectRoot) {
13477
13673
  const guard = guardPath(projectRoot);
13478
13674
  if (!existsSync27(guard)) return false;
13479
13675
  try {
13480
- const data = JSON.parse(readFileSync18(guard, "utf-8"));
13676
+ const data = JSON.parse(readFileSync19(guard, "utf-8"));
13481
13677
  const backup = data.backup;
13482
13678
  if (!existsSync27(backup)) return false;
13483
13679
  const uiBackup = join21(backup, "components-ui");
@@ -13528,7 +13724,7 @@ async function migrateAction(options) {
13528
13724
  }
13529
13725
  const provider = getComponentProvider();
13530
13726
  const managedIds = new Set(provider.listNames());
13531
- const files = readdirSync7(uiDir).filter((f) => f.endsWith(".tsx"));
13727
+ const files = readdirSync9(uiDir).filter((f) => f.endsWith(".tsx"));
13532
13728
  const migratable = files.map((f) => f.replace(".tsx", "")).filter((id) => managedIds.has(id));
13533
13729
  if (migratable.length === 0) {
13534
13730
  console.log(chalk31.green("All components are already up to date."));
@@ -13571,7 +13767,7 @@ Found ${migratable.length} component(s) to migrate:`));
13571
13767
  }
13572
13768
 
13573
13769
  // src/utils/update-notifier.ts
13574
- import { existsSync as existsSync28, mkdirSync as mkdirSync9, readFileSync as readFileSync19, writeFileSync as writeFileSync13 } from "fs";
13770
+ import { existsSync as existsSync28, mkdirSync as mkdirSync9, readFileSync as readFileSync20, writeFileSync as writeFileSync13 } from "fs";
13575
13771
  import { join as join22 } from "path";
13576
13772
  import { homedir } from "os";
13577
13773
  import chalk32 from "chalk";
@@ -13584,7 +13780,7 @@ var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
13584
13780
  function readCache() {
13585
13781
  try {
13586
13782
  if (!existsSync28(CACHE_FILE)) return null;
13587
- const raw = readFileSync19(CACHE_FILE, "utf-8");
13783
+ const raw = readFileSync20(CACHE_FILE, "utf-8");
13588
13784
  return JSON.parse(raw);
13589
13785
  } catch (e) {
13590
13786
  if (DEBUG5) console.error("Failed to read update cache:", e);
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "0.5.14",
6
+ "version": "0.5.15",
7
7
  "description": "CLI interface for Coherent Design Method",
8
8
  "type": "module",
9
9
  "main": "./dist/index.js",
@@ -43,7 +43,7 @@
43
43
  "ora": "^7.0.1",
44
44
  "prompts": "^2.4.2",
45
45
  "zod": "^3.22.4",
46
- "@getcoherent/core": "0.5.14"
46
+ "@getcoherent/core": "0.5.15"
47
47
  },
48
48
  "devDependencies": {
49
49
  "@types/node": "^20.11.0",