@getcoherent/cli 0.5.14 → 0.6.0

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/index.js CHANGED
@@ -1,3 +1,10 @@
1
+ import {
2
+ generateArchitecturePlan,
3
+ getPageGroup,
4
+ getPageType,
5
+ loadPlan,
6
+ savePlan
7
+ } from "./chunk-4M2RBSYF.js";
1
8
  import {
2
9
  __require
3
10
  } from "./chunk-3RG5ZIWI.js";
@@ -1227,9 +1234,7 @@ var COMPONENT_APIS = {
1227
1234
  </CommandGroup>
1228
1235
  </CommandList>
1229
1236
  </Command>`,
1230
- antiPatterns: [
1231
- "NEVER build custom search palette \u2014 use Command/CommandDialog"
1232
- ]
1237
+ antiPatterns: ["NEVER build custom search palette \u2014 use Command/CommandDialog"]
1233
1238
  },
1234
1239
  tabs: {
1235
1240
  name: "Tabs",
@@ -1269,7 +1274,16 @@ var COMPONENT_APIS = {
1269
1274
  },
1270
1275
  table: {
1271
1276
  name: "Table",
1272
- subcomponents: ["Table", "TableHeader", "TableBody", "TableFooter", "TableRow", "TableHead", "TableCell", "TableCaption"],
1277
+ subcomponents: [
1278
+ "Table",
1279
+ "TableHeader",
1280
+ "TableBody",
1281
+ "TableFooter",
1282
+ "TableRow",
1283
+ "TableHead",
1284
+ "TableCell",
1285
+ "TableCaption"
1286
+ ],
1273
1287
  importPath: "@/components/ui/table",
1274
1288
  keyProps: {},
1275
1289
  usage: `<Table>
@@ -1280,9 +1294,7 @@ var COMPONENT_APIS = {
1280
1294
  <TableRow><TableCell>Value</TableCell></TableRow>
1281
1295
  </TableBody>
1282
1296
  </Table>`,
1283
- antiPatterns: [
1284
- "NEVER use native <table> \u2014 use shadcn Table for consistent styling"
1285
- ]
1297
+ antiPatterns: ["NEVER use native <table> \u2014 use shadcn Table for consistent styling"]
1286
1298
  },
1287
1299
  accordion: {
1288
1300
  name: "Accordion",
@@ -1349,17 +1361,15 @@ var ShadcnProvider = class {
1349
1361
  if (!force && deps.existsSync(componentPath)) return;
1350
1362
  try {
1351
1363
  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
- );
1364
+ deps.exec(`npx shadcn@latest add ${name} --yes --overwrite`, { cwd: projectRoot, timeout: 15e3 }, (err) => {
1365
+ if (err) reject(err);
1366
+ else resolve16();
1367
+ });
1360
1368
  });
1361
1369
  } catch {
1362
- console.warn(`Could not install ${name} (network error or timeout). Run \`npx shadcn@latest add ${name}\` manually.`);
1370
+ console.warn(
1371
+ `Could not install ${name} (network error or timeout). Run \`npx shadcn@latest add ${name}\` manually.`
1372
+ );
1363
1373
  }
1364
1374
  }
1365
1375
  async installComponent(id, projectRoot, options) {
@@ -1452,10 +1462,7 @@ var ShadcnProvider = class {
1452
1462
  "ring"
1453
1463
  ];
1454
1464
  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
- );
1465
+ const chartLines = Array.from({ length: 5 }, (_, i) => ` --color-chart-${i + 1}: var(--chart-${i + 1});`);
1459
1466
  return `@theme inline {
1460
1467
  ${lines.join("\n")}
1461
1468
  ${chartLines.join("\n")}
@@ -1678,7 +1685,8 @@ function createMinimalConfig() {
1678
1685
  framework: "next",
1679
1686
  typescript: true,
1680
1687
  cssFramework: "tailwind",
1681
- autoScaffold: false
1688
+ autoScaffold: false,
1689
+ homePagePlaceholder: true
1682
1690
  },
1683
1691
  createdAt: now,
1684
1692
  updatedAt: now
@@ -1983,8 +1991,8 @@ function fixEscapedClosingQuotes(code) {
1983
1991
  }
1984
1992
  function fixUnescapedLtInJsx(code) {
1985
1993
  let out = code;
1986
- out = out.replace(/>([^<]*)<(\d)/g, ">$1&lt;$2");
1987
- out = out.replace(/>([^<]*)<([^/a-zA-Z!{>])/g, ">$1&lt;$2");
1994
+ out = out.replace(/>([^<\n]*)<(\d)/g, ">$1&lt;$2");
1995
+ out = out.replace(/>([^<\n]*)<([^/a-zA-Z!{>\n])/g, ">$1&lt;$2");
1988
1996
  return out;
1989
1997
  }
1990
1998
 
@@ -3744,10 +3752,10 @@ async function createAppRouteGroupLayout(projectPath) {
3744
3752
  }
3745
3753
 
3746
3754
  // src/commands/chat.ts
3747
- import chalk13 from "chalk";
3755
+ import chalk14 from "chalk";
3748
3756
  import ora2 from "ora";
3749
3757
  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";
3758
+ import { existsSync as existsSync16, readFileSync as readFileSync11, mkdirSync as mkdirSync6, readdirSync as readdirSync3 } from "fs";
3751
3759
  import {
3752
3760
  DesignSystemManager as DesignSystemManager7,
3753
3761
  ComponentManager as ComponentManager5,
@@ -3911,6 +3919,27 @@ var PAGE_TEMPLATES = {
3911
3919
  "Label"
3912
3920
  ]
3913
3921
  },
3922
+ register: {
3923
+ description: "Registration page with centered card form",
3924
+ sections: [
3925
+ '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".',
3926
+ 'Card with CardHeader: CardTitle "Create an account" (text-2xl font-bold), CardDescription "Enter your details to get started" (text-sm text-muted-foreground).',
3927
+ '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).',
3928
+ 'CardFooter: text "Already have an account?" with a Sign in link. All text is text-sm text-muted-foreground.',
3929
+ 'This page uses "use client" (has useState for form state). Do NOT include export const metadata.'
3930
+ ],
3931
+ components: [
3932
+ "Card",
3933
+ "CardHeader",
3934
+ "CardTitle",
3935
+ "CardDescription",
3936
+ "CardContent",
3937
+ "CardFooter",
3938
+ "Button",
3939
+ "Input",
3940
+ "Label"
3941
+ ]
3942
+ },
3914
3943
  pricing: {
3915
3944
  description: "Pricing page with tier comparison cards",
3916
3945
  sections: [
@@ -4037,11 +4066,49 @@ var PAGE_TEMPLATES = {
4037
4066
  "Page header. Timeline: each version with version badge, date, list of entries (type: text). Border-left timeline pattern. Badge component for version/date."
4038
4067
  ],
4039
4068
  components: ["Badge"]
4069
+ },
4070
+ team: {
4071
+ description: "Team page with member cards",
4072
+ sections: [
4073
+ 'Page header: h1 "Our Team" className="text-2xl font-bold tracking-tight" + p className="text-sm text-muted-foreground"',
4074
+ '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).'
4075
+ ],
4076
+ components: ["Card", "CardContent"]
4077
+ },
4078
+ tasks: {
4079
+ description: "Task list page with status badges and search",
4080
+ sections: [
4081
+ 'Page header: h1 "Tasks" + description. Search input with Search icon.',
4082
+ "Task list: divide-y container. Each row: status badge (colored), task title, priority badge, assignee name. Use flex items-center justify-between.",
4083
+ 'This page uses "use client" (has useState for search). Do NOT include export const metadata.'
4084
+ ],
4085
+ components: ["Input", "Badge"]
4086
+ },
4087
+ "task-detail": {
4088
+ description: "Task detail page with info and activity",
4089
+ sections: [
4090
+ "Back button linking to /tasks. Page header with task title and description.",
4091
+ "Two-column layout (md:grid-cols-2): Left Card with task details (status, priority, assignee, due date). Right Card with activity timeline.",
4092
+ 'This page uses "use client" (has useState). Do NOT include export const metadata.'
4093
+ ],
4094
+ components: ["Card", "CardHeader", "CardTitle", "CardContent", "Button"]
4095
+ },
4096
+ "reset-password": {
4097
+ description: "Reset password page with centered card form",
4098
+ sections: [
4099
+ '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".',
4100
+ 'Card with CardHeader: CardTitle "Reset Password" (text-xl), CardDescription.',
4101
+ 'CardContent with form: new password Input (type="password"), confirm password Input (type="password"), Button "Reset password" (w-full).',
4102
+ 'Footer text: "Remember your password?" with Sign in link.',
4103
+ 'This page uses "use client" (has useState for form state). Do NOT include export const metadata.'
4104
+ ],
4105
+ components: ["Card", "CardHeader", "CardTitle", "CardDescription", "CardContent", "Button", "Input", "Label"]
4040
4106
  }
4041
4107
  };
4042
4108
  var AUTH_ROUTE_SEGMENTS = /* @__PURE__ */ new Set([
4043
4109
  "login",
4044
4110
  "signin",
4111
+ "sign-in",
4045
4112
  "sign-up",
4046
4113
  "signup",
4047
4114
  "register",
@@ -4057,8 +4124,9 @@ function detectPageType(pageName) {
4057
4124
  const normalized = pageName.toLowerCase();
4058
4125
  if (/dashboard|admin|overview/.test(normalized)) return "dashboard";
4059
4126
  if (/login|signin|sign-in/.test(normalized)) return "login";
4127
+ if (/register|signup|sign.?up/.test(normalized)) return "register";
4060
4128
  if (/pricing|plans|subscription/.test(normalized)) return "pricing";
4061
- if (/about|team|company/.test(normalized)) return "about";
4129
+ if (/about|company/.test(normalized)) return "about";
4062
4130
  if (/contact|support|help/.test(normalized)) return "contact";
4063
4131
  if (/settings|preferences|account/.test(normalized)) return "settings";
4064
4132
  if (/home|landing|hero/.test(normalized)) return "landing";
@@ -4069,6 +4137,10 @@ function detectPageType(pageName) {
4069
4137
  if (/gallery|portfolio|images/.test(normalized)) return "gallery";
4070
4138
  if (/faq|frequently|questions/.test(normalized)) return "faq";
4071
4139
  if (/changelog|release|versions/.test(normalized)) return "changelog";
4140
+ if (/team|members/.test(normalized)) return "team";
4141
+ if (/tasks?/.test(normalized) && /detail|\[id\]/.test(normalized)) return "task-detail";
4142
+ if (/tasks?/.test(normalized)) return "tasks";
4143
+ if (/reset.?password/.test(normalized)) return "reset-password";
4072
4144
  return null;
4073
4145
  }
4074
4146
  function expandPageRequest(pageName, userRequest) {
@@ -4154,6 +4226,8 @@ LINKS & INTERACTIVE STATES (consistency is critical):
4154
4226
  - ALL links on the SAME page MUST use the SAME style. Never mix underlined and non-underlined text links.
4155
4227
  - ALL Button variants MUST have: hover: state, focus-visible:ring-2 focus-visible:ring-ring, active: state, disabled:opacity-50.
4156
4228
  - ALL interactive elements MUST have visible hover and focus-visible states.
4229
+ - CRITICAL: Every <Link> MUST have an href prop. Missing href causes runtime errors. Never use <Link className="..."> or <Button asChild><Link> without href.
4230
+ - When shared components exist (@/components/shared/*), ALWAYS import and use them instead of re-implementing similar patterns inline.
4157
4231
 
4158
4232
  ICONS:
4159
4233
  - Size: ALWAYS size-4 (16px). Color: ALWAYS text-muted-foreground. Import: ALWAYS from lucide-react.
@@ -4183,12 +4257,11 @@ CONTENT (zero placeholders):
4183
4257
  - NEVER: "Lorem ipsum", "Card content", "Description here"
4184
4258
  - ALWAYS: Real, contextual content. Realistic metric names, values, dates.
4185
4259
  `;
4186
- var DESIGN_QUALITY = `
4187
- ## DESIGN QUALITY (apply to EVERY page)
4260
+ var DESIGN_QUALITY_COMMON = `
4261
+ ## DESIGN QUALITY \u2014 COMMON
4188
4262
 
4189
4263
  ### Typography Hierarchy
4190
4264
  - Page headline (h1): text-4xl md:text-5xl lg:text-6xl font-bold tracking-tight leading-[1.1]
4191
- - Landing/marketing hero headline: text-5xl md:text-6xl lg:text-7xl font-bold tracking-tight leading-[1.05]
4192
4265
  - Section titles (h2): text-2xl md:text-3xl font-bold
4193
4266
  - Card titles (h3): text-sm font-semibold (never text-base or text-lg)
4194
4267
  - Body text: text-sm text-muted-foreground leading-relaxed
@@ -4201,6 +4274,29 @@ var DESIGN_QUALITY = `
4201
4274
  - Sections alternate between bg-background and bg-muted/5 for rhythm
4202
4275
  - Section dividers: border-t border-border/10 (subtle, not heavy)
4203
4276
 
4277
+ ### Buttons with Icons
4278
+ - Buttons containing text + icon: ALWAYS use inline-flex items-center gap-2 whitespace-nowrap
4279
+ - Icon inside button: h-4 w-4 (never larger), placed AFTER text for arrows, BEFORE text for action icons
4280
+ - NEVER let button content wrap to multiple lines \u2014 use whitespace-nowrap on the Button component
4281
+ - CTA buttons: use the Button component, NEVER raw <button> or <a> styled as button
4282
+
4283
+ ### Accent Color Discipline
4284
+ - ONE accent color per page (primary or emerald-400)
4285
+ - Use for: CTAs, terminal text, check icons, feature icon backgrounds, active states
4286
+ - NEVER mix blue + purple + emerald on same page
4287
+ - Badge: outline style (border-border/30 bg-transparent) not filled color
4288
+ - Status icons: text-emerald-400 for positive, text-red-400 for negative
4289
+
4290
+ ### Dark Theme Implementation
4291
+ - html element: className="dark"
4292
+ - Background: use CSS variables from globals.css dark section
4293
+ - Text: text-foreground for primary, text-muted-foreground for secondary
4294
+ - NEVER hardcode dark colors (bg-gray-900) \u2014 always use semantic tokens
4295
+ - Cards and elevated elements: slightly lighter than background (bg-card or bg-zinc-900/50)
4296
+ `;
4297
+ var DESIGN_QUALITY_MARKETING = `
4298
+ ## DESIGN QUALITY \u2014 MARKETING PAGES
4299
+
4204
4300
  ### Spacing Rhythm (3 distinct levels)
4205
4301
  - Between sections: py-20 md:py-28 (generous)
4206
4302
  - Within sections (title to content): mb-12 md:mb-16
@@ -4208,11 +4304,8 @@ var DESIGN_QUALITY = `
4208
4304
  - Between cards in grid: gap-5 (tight)
4209
4305
  - NEVER uniform spacing everywhere \u2014 contrast creates rhythm
4210
4306
 
4211
- ### Buttons with Icons
4212
- - Buttons containing text + icon: ALWAYS use inline-flex items-center gap-2 whitespace-nowrap
4213
- - Icon inside button: h-4 w-4 (never larger), placed AFTER text for arrows, BEFORE text for action icons
4214
- - NEVER let button content wrap to multiple lines \u2014 use whitespace-nowrap on the Button component
4215
- - CTA buttons: use the Button component, NEVER raw <button> or <a> styled as button
4307
+ ### Hero headline
4308
+ - Landing/marketing hero headline: text-5xl md:text-6xl lg:text-7xl font-bold tracking-tight leading-[1.05]
4216
4309
 
4217
4310
  ### Icons in Feature Cards
4218
4311
  - Wrap in colored container: bg-primary/10 rounded-lg p-2.5
@@ -4228,14 +4321,7 @@ var DESIGN_QUALITY = `
4228
4321
  - Title bar (optional): flex with 3 dots (bg-zinc-700 rounded-full w-2.5 h-2.5) + title text-zinc-500 text-[11px]
4229
4322
  - Copy button: text-zinc-500 hover:text-zinc-300
4230
4323
 
4231
- ### Accent Color Discipline
4232
- - ONE accent color per page (primary or emerald-400)
4233
- - Use for: CTAs, terminal text, check icons, feature icon backgrounds, active states
4234
- - NEVER mix blue + purple + emerald on same page
4235
- - Badge: outline style (border-border/30 bg-transparent) not filled color
4236
- - Status icons: text-emerald-400 for positive, text-red-400 for negative
4237
-
4238
- ### Hero Section (landing/marketing pages)
4324
+ ### Hero Section
4239
4325
  - Minimum height: min-h-[80vh] flex items-center justify-center
4240
4326
  - Content: centered, max-w-3xl, flex flex-col items-center text-center gap-8
4241
4327
  - Badge above headline: small, outline, text-xs tracking-wide
@@ -4252,8 +4338,6 @@ var DESIGN_QUALITY = `
4252
4338
  ### Step/Process Sections
4253
4339
  - Numbered steps: circle with border, number inside (w-10 h-10 rounded-full border border-border/30 text-sm)
4254
4340
  - Label above: text-xs font-semibold tracking-widest uppercase text-muted-foreground
4255
- - Each step has a code block showing the command
4256
- - Description below: text-sm text-muted-foreground
4257
4341
 
4258
4342
  ### Footer
4259
4343
  - Minimal: border-t border-border/10, py-10
@@ -4261,13 +4345,66 @@ var DESIGN_QUALITY = `
4261
4345
  - Links: hover:text-foreground transition-colors
4262
4346
  - Layout: flex justify-between on desktop, stack on mobile
4263
4347
 
4264
- ### Dark Theme Implementation
4265
- - html element: className="dark"
4266
- - Background: use CSS variables from globals.css dark section
4267
- - Text: text-foreground for primary, text-muted-foreground for secondary
4268
- - NEVER hardcode dark colors (bg-gray-900) \u2014 always use semantic tokens
4269
- - Cards and elevated elements: slightly lighter than background (bg-card or bg-zinc-900/50)
4348
+ NEVER include app-style elements (sidebar widgets, data tables, filters) on marketing pages.
4349
+ `;
4350
+ var DESIGN_QUALITY_APP = `
4351
+ ## DESIGN QUALITY \u2014 APP PAGES
4352
+
4353
+ ### Spacing
4354
+ - gap-4 md:gap-6 between sections
4355
+ - p-4 lg:p-6 content padding
4356
+ - Within cards: p-4 to p-6 (compact)
4357
+ - Between cards in grid: gap-4 (tight)
4358
+
4359
+ ### Layout
4360
+ - Data tables, card grids, filters, stat rows
4361
+ - Page wrapper: flex flex-1 flex-col gap-4 p-4 lg:p-6
4362
+ - Stats grid: grid gap-4 md:grid-cols-2 lg:grid-cols-4
4363
+ - Content: functional, scannable, data-dense
4364
+
4365
+ NEVER include marketing sections (hero, pricing, testimonials) on app pages.
4270
4366
  `;
4367
+ var DESIGN_QUALITY_AUTH = `
4368
+ ## DESIGN QUALITY \u2014 AUTH PAGES
4369
+
4370
+ ### Layout
4371
+ - Centered card: flex min-h-svh items-center justify-center p-6 md:p-10
4372
+ - Card width: w-full max-w-sm
4373
+ - No navigation, no section containers, no sidebar
4374
+ - Single focused form with clear CTA
4375
+ - Card \u2192 CardHeader (title + description) \u2192 CardContent (form) \u2192 CardFooter (link to other auth page)
4376
+
4377
+ NEVER include navigation bars, sidebars, or multi-section layouts on auth pages.
4378
+ `;
4379
+ function getDesignQualityForType(type) {
4380
+ switch (type) {
4381
+ case "marketing":
4382
+ return DESIGN_QUALITY_MARKETING;
4383
+ case "app":
4384
+ return DESIGN_QUALITY_APP;
4385
+ case "auth":
4386
+ return DESIGN_QUALITY_AUTH;
4387
+ }
4388
+ }
4389
+ function inferPageTypeFromRoute(route) {
4390
+ const slug = route.replace(/^\//, "").split("/")[0] || "";
4391
+ const authSlugs = /* @__PURE__ */ new Set([
4392
+ "login",
4393
+ "register",
4394
+ "sign-up",
4395
+ "signup",
4396
+ "sign-in",
4397
+ "signin",
4398
+ "forgot-password",
4399
+ "reset-password"
4400
+ ]);
4401
+ const marketingSlugs = /* @__PURE__ */ new Set(["pricing", "features", "about", "blog", "contact", "terms", "privacy"]);
4402
+ if (authSlugs.has(slug)) return "auth";
4403
+ if (marketingSlugs.has(slug) || slug === "") return "marketing";
4404
+ return "app";
4405
+ }
4406
+ var DESIGN_QUALITY = `${DESIGN_QUALITY_COMMON}
4407
+ ${DESIGN_QUALITY_MARKETING}`;
4271
4408
  var VISUAL_DEPTH = `
4272
4409
  ## VISUAL DEPTH TECHNIQUES (pick 1-3 per page based on context)
4273
4410
 
@@ -4905,6 +5042,11 @@ async function parseModification(message, context, provider = "auto", options) {
4905
5042
  const navigation = !Array.isArray(raw2) && raw2?.navigation ? raw2.navigation : void 0;
4906
5043
  return { requests: requestsArray2, uxRecommendations: void 0, navigation };
4907
5044
  }
5045
+ if (options?.lightweight) {
5046
+ const raw2 = await ai.parseModification(message);
5047
+ const requestsArray2 = Array.isArray(raw2) ? raw2 : raw2?.requests ?? [];
5048
+ return { requests: requestsArray2, uxRecommendations: void 0 };
5049
+ }
4908
5050
  const componentRegistry = buildComponentRegistry(context.componentManager);
4909
5051
  let enhancedMessage = message;
4910
5052
  let isExpandedPageRequest = false;
@@ -5013,6 +5155,7 @@ For editing an existing shared component use type "modify-layout-block" with tar
5013
5155
  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
5156
 
5015
5157
  Parse the user's natural language request into structured modification requests.
5158
+ ${sharedSection}
5016
5159
  ${designThinking}
5017
5160
  ${coreRules}
5018
5161
  ${designQuality}
@@ -5037,7 +5180,6 @@ LINKING RULES (CRITICAL \u2014 prevents broken links):
5037
5180
  - Navigation components should link to ALL existing page routes.
5038
5181
 
5039
5182
  ${componentRegistry}
5040
- ${sharedSection}
5041
5183
 
5042
5184
  Available shadcn/ui components (can be auto-installed): ${availableShadcn.join(", ")}
5043
5185
 
@@ -5264,6 +5406,20 @@ Return valid JSON only, no markdown code fence. Use this shape:
5264
5406
  { "requests": [ ... array of ModificationRequest ... ], "uxRecommendations": "optional markdown or omit key" }
5265
5407
  Legacy: returning only a JSON array of requests is still accepted.`;
5266
5408
  }
5409
+ function buildLightweightPagePrompt(pageName, route, styleContext, sharedComponentsSummary, pageType) {
5410
+ const designConstraints = pageType ? getDesignQualityForType(pageType) : "";
5411
+ return [
5412
+ `Generate complete pageCode for a page called "${pageName}" at route "${route}".`,
5413
+ `Output valid TSX with a default export React component.`,
5414
+ `Use shadcn/ui components (import from @/components/ui/*). Use Tailwind CSS semantic tokens only.`,
5415
+ pageType ? `PAGE TYPE: ${pageType}` : "",
5416
+ designConstraints,
5417
+ styleContext ? `Follow this style context:
5418
+ ${styleContext}` : "",
5419
+ sharedComponentsSummary ? `Available shared components:
5420
+ ${sharedComponentsSummary}` : ""
5421
+ ].filter(Boolean).join("\n\n");
5422
+ }
5267
5423
  async function checkComponentReuse(requests, componentManager) {
5268
5424
  const enhanced = [];
5269
5425
  for (const request of requests) {
@@ -6251,6 +6407,17 @@ function validatePageQuality(code, validRoutes) {
6251
6407
  severity: "error"
6252
6408
  });
6253
6409
  }
6410
+ const linkWithoutHrefRe = /<(?:Link|a)\b(?![^>]*\bhref\s*=)[^>]*>/g;
6411
+ let linkNoHrefMatch;
6412
+ while ((linkNoHrefMatch = linkWithoutHrefRe.exec(code)) !== null) {
6413
+ const matchLine = code.slice(0, linkNoHrefMatch.index).split("\n").length;
6414
+ issues.push({
6415
+ line: matchLine,
6416
+ type: "LINK_MISSING_HREF",
6417
+ message: "<Link> or <a> without href prop \u2014 causes Next.js runtime error. Add href attribute.",
6418
+ severity: "error"
6419
+ });
6420
+ }
6254
6421
  issues.push(...detectComponentIssues(code));
6255
6422
  return issues;
6256
6423
  }
@@ -6356,11 +6523,36 @@ async function autoFixCode(code) {
6356
6523
  fixes.push("fixed escaped closing quotes in strings");
6357
6524
  }
6358
6525
  const beforeEntityFix = fixed;
6359
- fixed = fixed.replace(/&lt;=/g, "<=");
6360
- fixed = fixed.replace(/&gt;=/g, ">=");
6361
- fixed = fixed.replace(/&amp;&amp;/g, "&&");
6362
- fixed = fixed.replace(/([\w)\]])\s*&lt;\s*([\w(])/g, "$1 < $2");
6363
- fixed = fixed.replace(/([\w)\]])\s*&gt;\s*([\w(])/g, "$1 > $2");
6526
+ const isInsideAttrValue = (line, idx) => {
6527
+ let inQuote = false;
6528
+ let inAttr = false;
6529
+ for (let i = 0; i < idx; i++) {
6530
+ if (line[i] === "=" && line[i + 1] === '"') {
6531
+ inAttr = true;
6532
+ inQuote = true;
6533
+ i++;
6534
+ } else if (inAttr && line[i] === '"') {
6535
+ inAttr = false;
6536
+ inQuote = false;
6537
+ }
6538
+ }
6539
+ return inQuote;
6540
+ };
6541
+ fixed = fixed.split("\n").map((line) => {
6542
+ let l = line;
6543
+ l = l.replace(/&lt;=/g, (m, offset) => isInsideAttrValue(line, offset) ? m : "<=");
6544
+ l = l.replace(/&gt;=/g, (m, offset) => isInsideAttrValue(line, offset) ? m : ">=");
6545
+ l = l.replace(/&amp;&amp;/g, (m, offset) => isInsideAttrValue(line, offset) ? m : "&&");
6546
+ l = l.replace(
6547
+ /([\w)\]])\s*&lt;\s*([\w(])/g,
6548
+ (m, p1, p2, offset) => isInsideAttrValue(line, offset) ? m : `${p1} < ${p2}`
6549
+ );
6550
+ l = l.replace(
6551
+ /([\w)\]])\s*&gt;\s*([\w(])/g,
6552
+ (m, p1, p2, offset) => isInsideAttrValue(line, offset) ? m : `${p1} > ${p2}`
6553
+ );
6554
+ return l;
6555
+ }).join("\n");
6364
6556
  if (fixed !== beforeEntityFix) {
6365
6557
  fixes.push("Fixed syntax issues");
6366
6558
  }
@@ -6707,6 +6899,11 @@ ${selectImport}`
6707
6899
  if (fixed !== beforeAsChildFlex) {
6708
6900
  fixes.push("added inline-flex to Button asChild children (base-ui compat)");
6709
6901
  }
6902
+ const beforeLinkHrefFix = fixed;
6903
+ fixed = fixed.replace(/<(Link|a)\b(?![^>]*\bhref\s*=)([^>]*)>/g, '<$1 href="/"$2>');
6904
+ if (fixed !== beforeLinkHrefFix) {
6905
+ fixes.push('added href="/" to <Link>/<a> missing href');
6906
+ }
6710
6907
  const { code: fixedByRules, fixes: ruleFixes } = applyComponentRules(fixed);
6711
6908
  if (ruleFixes.length > 0) {
6712
6909
  fixed = fixedByRules;
@@ -6830,7 +7027,16 @@ import { DesignSystemManager as DesignSystemManager3, loadManifest as loadManife
6830
7027
  import chalk8 from "chalk";
6831
7028
  var MARKETING_ROUTES = /* @__PURE__ */ new Set(["", "landing", "pricing", "about", "contact", "blog", "features"]);
6832
7029
  var MIN_ANCHOR_PAGE_CODE_CHARS = 120;
6833
- var AUTH_ROUTE_SLUGS = /* @__PURE__ */ new Set(["login", "register", "forgot-password", "reset-password", "sign-up"]);
7030
+ var AUTH_ROUTE_SLUGS = /* @__PURE__ */ new Set([
7031
+ "login",
7032
+ "signin",
7033
+ "sign-in",
7034
+ "register",
7035
+ "sign-up",
7036
+ "signup",
7037
+ "forgot-password",
7038
+ "reset-password"
7039
+ ]);
6834
7040
  function inferRouteUsesAuthSegment(route) {
6835
7041
  const slug = route.replace(/^\//, "").split("/")[0] || "";
6836
7042
  return AUTH_ROUTE_SLUGS.has(slug);
@@ -6852,30 +7058,30 @@ function isMarketingRoute(route) {
6852
7058
  const slug = route.replace(/^\//, "").split("/")[0] || "";
6853
7059
  return MARKETING_ROUTES.has(slug);
6854
7060
  }
6855
- function routeToFsPath(projectRoot, route, isAuth) {
7061
+ function routeToFsPath(projectRoot, route, isAuthOrPlan) {
7062
+ const plan = typeof isAuthOrPlan === "object" ? isAuthOrPlan : void 0;
7063
+ const isAuth = typeof isAuthOrPlan === "boolean" ? isAuthOrPlan : false;
6856
7064
  const slug = route.replace(/^\//, "");
6857
- if (isAuth) {
6858
- return resolve5(projectRoot, "app", "(auth)", slug || "login", "page.tsx");
6859
- }
6860
- if (!slug) {
6861
- return resolve5(projectRoot, "app", "page.tsx");
6862
- }
6863
- if (isMarketingRoute(route)) {
6864
- return resolve5(projectRoot, "app", slug, "page.tsx");
7065
+ if (!slug) return resolve5(projectRoot, "app", "page.tsx");
7066
+ if (plan) {
7067
+ const group = getPageGroup(route, plan);
7068
+ if (group) return resolve5(projectRoot, "app", `(${group.id})`, slug, "page.tsx");
6865
7069
  }
7070
+ if (isAuth) return resolve5(projectRoot, "app", "(auth)", slug || "login", "page.tsx");
7071
+ if (isMarketingRoute(route)) return resolve5(projectRoot, "app", slug, "page.tsx");
6866
7072
  return resolve5(projectRoot, "app", "(app)", slug, "page.tsx");
6867
7073
  }
6868
- function routeToRelPath(route, isAuth) {
7074
+ function routeToRelPath(route, isAuthOrPlan) {
7075
+ const plan = typeof isAuthOrPlan === "object" ? isAuthOrPlan : void 0;
7076
+ const isAuth = typeof isAuthOrPlan === "boolean" ? isAuthOrPlan : false;
6869
7077
  const slug = route.replace(/^\//, "");
6870
- if (isAuth) {
6871
- return `app/(auth)/${slug || "login"}/page.tsx`;
6872
- }
6873
- if (!slug) {
6874
- return "app/page.tsx";
6875
- }
6876
- if (isMarketingRoute(route)) {
6877
- return `app/${slug}/page.tsx`;
7078
+ if (!slug) return "app/page.tsx";
7079
+ if (plan) {
7080
+ const group = getPageGroup(route, plan);
7081
+ if (group) return `app/(${group.id})/${slug}/page.tsx`;
6878
7082
  }
7083
+ if (isAuth) return `app/(auth)/${slug || "login"}/page.tsx`;
7084
+ if (isMarketingRoute(route)) return `app/${slug}/page.tsx`;
6879
7085
  return `app/(app)/${slug}/page.tsx`;
6880
7086
  }
6881
7087
  function deduplicatePages(pages) {
@@ -6900,13 +7106,24 @@ function extractComponentIdsFromCode(code) {
6900
7106
  }
6901
7107
  return ids;
6902
7108
  }
6903
- async function warnInlineDuplicates(projectRoot, pageName, pageCode, manifest) {
7109
+ async function warnInlineDuplicates(projectRoot, pageName, route, pageCode, manifest, plan) {
6904
7110
  const sectionOrWidget = manifest.shared.filter((e) => e.type === "section" || e.type === "widget");
6905
7111
  if (sectionOrWidget.length === 0) return;
7112
+ const plannedForPage = plan ? new Set(plan.sharedComponents.filter((c) => c.usedBy.includes(route)).map((c) => c.name)) : null;
6906
7113
  for (const e of sectionOrWidget) {
7114
+ if (plannedForPage && !plannedForPage.has(e.name)) continue;
6907
7115
  const kebab = e.file.replace(/^components\/shared\//, "").replace(/\.tsx$/, "");
6908
7116
  const hasImport = pageCode.includes(`@/components/shared/${kebab}`);
6909
7117
  if (hasImport) continue;
7118
+ if (plannedForPage) {
7119
+ console.log(
7120
+ chalk8.yellow(
7121
+ `
7122
+ \u26A0 Page "${pageName}" should use shared component ${e.name} (per architecture plan) but it's not imported. Import from @/components/shared/${kebab}`
7123
+ )
7124
+ );
7125
+ continue;
7126
+ }
6910
7127
  const sameNameAsTag = new RegExp(`<\\/?${e.name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}[\\s>]`).test(pageCode);
6911
7128
  if (sameNameAsTag) {
6912
7129
  console.log(
@@ -7397,7 +7614,10 @@ function applyDefaults(request) {
7397
7614
 
7398
7615
  // src/commands/chat/split-generator.ts
7399
7616
  import { z } from "zod";
7400
- import { loadManifest as loadManifest5, generateSharedComponent as generateSharedComponent2 } from "@getcoherent/core";
7617
+ import {
7618
+ loadManifest as loadManifest5,
7619
+ generateSharedComponent as generateSharedComponent2
7620
+ } from "@getcoherent/core";
7401
7621
 
7402
7622
  // src/utils/page-analyzer.ts
7403
7623
  var FORM_COMPONENTS = /* @__PURE__ */ new Set(["Input", "Textarea", "Label", "Select", "Checkbox", "Switch"]);
@@ -7515,6 +7735,7 @@ async function pMap(items, fn, concurrency = 3) {
7515
7735
  }
7516
7736
 
7517
7737
  // src/commands/chat/split-generator.ts
7738
+ import chalk9 from "chalk";
7518
7739
  function buildExistingPagesContext(config2) {
7519
7740
  const pages = config2.pages || [];
7520
7741
  const analyzed = pages.filter((p) => p.pageAnalysis);
@@ -7604,6 +7825,28 @@ function buildSharedComponentsSummary(manifest) {
7604
7825
  Import: @/components/shared/${importPath}${propsLine}`;
7605
7826
  }).join("\n");
7606
7827
  }
7828
+ function buildSharedComponentsNote(sharedComponentsSummary) {
7829
+ if (!sharedComponentsSummary) return void 0;
7830
+ return `SHARED COMPONENTS \u2014 MANDATORY REUSE:
7831
+ Before implementing any section, check this list. Import and use matching components from @/components/shared/. Do NOT re-implement these patterns inline.
7832
+
7833
+ ${sharedComponentsSummary}`;
7834
+ }
7835
+ function formatPlanSummary(plan) {
7836
+ if (plan.groups.length === 0) return "";
7837
+ const groupLines = plan.groups.map((g) => ` Group "${g.id}" (layout: ${g.layout}): ${g.pages.join(", ")}`);
7838
+ const compLines = plan.sharedComponents.map(
7839
+ (c) => ` ${c.name} (${c.type}) \u2014 ${c.description}; usedBy: ${c.usedBy.join(", ")}`
7840
+ );
7841
+ const parts = [`ARCHITECTURE PLAN:
7842
+ Groups:
7843
+ ${groupLines.join("\n")}`];
7844
+ if (compLines.length > 0) {
7845
+ parts.push(`Shared Components:
7846
+ ${compLines.join("\n")}`);
7847
+ }
7848
+ return parts.join("\n");
7849
+ }
7607
7850
  async function splitGeneratePages(spinner, message, modCtx, provider, parseOpts) {
7608
7851
  let pageNames = [];
7609
7852
  spinner.start("Phase 1/5 \u2014 Planning pages...");
@@ -7637,7 +7880,7 @@ async function splitGeneratePages(spinner, message, modCtx, provider, parseOpts)
7637
7880
  }
7638
7881
  if (pageNames.length === 0) {
7639
7882
  spinner.fail("Could not determine pages to create");
7640
- return [];
7883
+ return { requests: [], plan: null };
7641
7884
  }
7642
7885
  pageNames = deduplicatePages(pageNames);
7643
7886
  const hasHomePage = pageNames.some((p) => p.route === "/");
@@ -7659,7 +7902,41 @@ async function splitGeneratePages(spinner, message, modCtx, provider, parseOpts)
7659
7902
  const allRoutes = pageNames.map((p) => p.route).join(", ");
7660
7903
  const allPagesList = pageNames.map((p) => `${p.name} (${p.route})`).join(", ");
7661
7904
  const inferredNote = inferred.length > 0 ? ` (${inferred.length} auto-inferred)` : "";
7662
- spinner.succeed(`Phase 1/5 \u2014 Found ${pageNames.length} pages${inferredNote}: ${allPagesList}`);
7905
+ spinner.succeed(`Phase 1/6 \u2014 Found ${pageNames.length} pages${inferredNote}: ${allPagesList}`);
7906
+ let plan = null;
7907
+ if (parseOpts.projectRoot) {
7908
+ spinner.start("Phase 2/6 \u2014 Generating architecture plan...");
7909
+ try {
7910
+ const ai = await createAIProvider(provider ?? "auto");
7911
+ const layoutHint = modCtx.config.navigation?.type || null;
7912
+ plan = await generateArchitecturePlan(pageNames, message, ai, layoutHint);
7913
+ if (plan) {
7914
+ const groupsSummary = plan.groups.map((g) => `${g.id} (${g.layout}, ${g.pages.length} pages)`).join(", ");
7915
+ const sharedSummary = plan.sharedComponents.length > 0 ? plan.sharedComponents.map((c) => `${c.name} \u2192 ${c.usedBy.join(", ")}`).join(" | ") : "";
7916
+ const totalPages = plan.groups.reduce((sum, g) => sum + g.pages.length, 0);
7917
+ spinner.succeed(`Phase 2/6 \u2014 Architecture plan created`);
7918
+ console.log(chalk9.dim(` Groups: ${groupsSummary}`));
7919
+ if (sharedSummary) console.log(chalk9.dim(` Shared: ${sharedSummary}`));
7920
+ console.log(chalk9.dim(` Total: ${totalPages} pages, ${plan.sharedComponents.length} shared components`));
7921
+ if (plan.sharedComponents.length > 0 && parseOpts.projectRoot) {
7922
+ const allDeps = new Set(plan.sharedComponents.flatMap((c) => c.shadcnDeps));
7923
+ if (allDeps.size > 0) {
7924
+ const componentProvider = getComponentProvider();
7925
+ for (const dep of allDeps) {
7926
+ try {
7927
+ await componentProvider.installComponent(dep, parseOpts.projectRoot);
7928
+ } catch {
7929
+ }
7930
+ }
7931
+ }
7932
+ }
7933
+ } else {
7934
+ spinner.warn("Phase 2/6 \u2014 Plan generation failed (continuing without plan)");
7935
+ }
7936
+ } catch {
7937
+ spinner.warn("Phase 2/6 \u2014 Plan generation failed (continuing without plan)");
7938
+ }
7939
+ }
7663
7940
  const homeIdx = pageNames.findIndex((p) => p.route === "/");
7664
7941
  const homePage = homeIdx !== -1 ? pageNames[homeIdx] : pageNames[0];
7665
7942
  const remainingPages = pageNames.filter((_, i) => i !== (homeIdx !== -1 ? homeIdx : 0));
@@ -7667,17 +7944,18 @@ async function splitGeneratePages(spinner, message, modCtx, provider, parseOpts)
7667
7944
  let homeRequest = null;
7668
7945
  let homePageCode = "";
7669
7946
  let reusedExistingAnchor = false;
7670
- if (projectRoot && remainingPages.length > 0) {
7947
+ const isPlaceholder = modCtx.config?.settings?.homePagePlaceholder === true;
7948
+ if (projectRoot && remainingPages.length > 0 && !isPlaceholder) {
7671
7949
  const existingCode = readAnchorPageCodeFromDisk(projectRoot, homePage.route);
7672
7950
  if (existingCode) {
7673
7951
  reusedExistingAnchor = true;
7674
7952
  homePageCode = existingCode;
7675
- spinner.start(`Phase 2/5 \u2014 Loading ${homePage.name} from disk (style anchor)...`);
7676
- spinner.succeed(`Phase 2/5 \u2014 Reused existing ${homePage.name} page (skipped AI regeneration)`);
7953
+ spinner.start(`Phase 3/6 \u2014 Loading ${homePage.name} from disk (style anchor)...`);
7954
+ spinner.succeed(`Phase 3/6 \u2014 Reused existing ${homePage.name} page (skipped AI regeneration)`);
7677
7955
  }
7678
7956
  }
7679
7957
  if (!reusedExistingAnchor) {
7680
- spinner.start(`Phase 2/5 \u2014 Generating ${homePage.name} page (sets design direction)...`);
7958
+ spinner.start(`Phase 3/6 \u2014 Generating ${homePage.name} page (sets design direction)...`);
7681
7959
  try {
7682
7960
  const homeResult = await parseModification(
7683
7961
  `Create ONE page called "${homePage.name}" at route "${homePage.route}". Context: ${message}. This REPLACES the default placeholder page \u2014 generate a complete, content-rich landing page for the project described above. Generate complete pageCode. Include a branded site-wide <header> with navigation links to ALL these pages: ${allPagesList}. Use these EXACT routes in navigation: ${allRoutes}. Include a <footer> at the bottom. Make it visually polished \u2014 this page sets the design direction for the entire site. Do not generate other pages.`,
@@ -7699,68 +7977,102 @@ async function splitGeneratePages(spinner, message, modCtx, provider, parseOpts)
7699
7977
  changes: { id: homePage.id, name: homePage.name, route: homePage.route }
7700
7978
  };
7701
7979
  }
7702
- spinner.succeed(`Phase 2/5 \u2014 ${homePage.name} page generated`);
7980
+ spinner.succeed(`Phase 3/6 \u2014 ${homePage.name} page generated`);
7703
7981
  }
7704
- spinner.start("Phase 3/5 \u2014 Extracting design patterns...");
7982
+ spinner.start("Phase 4/6 \u2014 Extracting design patterns...");
7705
7983
  const styleContext = homePageCode ? extractStyleContext(homePageCode) : "";
7706
7984
  if (styleContext) {
7707
7985
  const lineCount = styleContext.split("\n").length - 1;
7708
7986
  const source = reusedExistingAnchor ? `${homePage.name} (existing file)` : homePage.name;
7709
- spinner.succeed(`Phase 3/5 \u2014 Extracted ${lineCount} style patterns from ${source}`);
7987
+ spinner.succeed(`Phase 4/6 \u2014 Extracted ${lineCount} style patterns from ${source}`);
7710
7988
  } else {
7711
- spinner.succeed("Phase 3/5 \u2014 No style patterns extracted (anchor page had no code)");
7989
+ spinner.succeed("Phase 4/6 \u2014 No style patterns extracted (anchor page had no code)");
7712
7990
  }
7713
- if (remainingPages.length >= 2 && homePageCode && projectRoot) {
7714
- const manifest = await loadManifest5(projectRoot);
7715
- const shouldSkip = reusedExistingAnchor && manifest.shared.some((e) => e.type !== "layout");
7716
- if (!shouldSkip) {
7717
- spinner.start("Phase 3.5/5 \u2014 Extracting shared components...");
7991
+ if (remainingPages.length >= 2 && projectRoot) {
7992
+ if (plan && plan.sharedComponents.length > 0) {
7993
+ spinner.start(`Phase 4.5/6 \u2014 Generating ${plan.sharedComponents.length} shared components from plan...`);
7718
7994
  try {
7719
- const extraction = await extractSharedComponents(homePageCode, projectRoot, provider ?? "auto");
7720
- parseOpts.sharedComponentsSummary = extraction.summary;
7721
- if (extraction.components.length > 0) {
7722
- const names = extraction.components.map((c) => c.name).join(", ");
7723
- spinner.succeed(`Phase 3.5/5 \u2014 Extracted ${extraction.components.length} shared components (${names})`);
7995
+ const { generateSharedComponentsFromPlan } = await import("./plan-generator-XKMZTEGK.js");
7996
+ const generated = await generateSharedComponentsFromPlan(
7997
+ plan,
7998
+ styleContext,
7999
+ projectRoot,
8000
+ await createAIProvider(provider ?? "auto")
8001
+ );
8002
+ if (generated.length > 0) {
8003
+ const updatedManifest = await loadManifest5(projectRoot);
8004
+ parseOpts.sharedComponentsSummary = buildSharedComponentsSummary(updatedManifest);
8005
+ const names = generated.map((c) => c.name).join(", ");
8006
+ spinner.succeed(`Phase 4.5/6 \u2014 Generated ${generated.length} shared components (${names})`);
7724
8007
  } else {
7725
- spinner.succeed("Phase 3.5/5 \u2014 No shared components extracted");
8008
+ spinner.succeed("Phase 4.5/6 \u2014 No shared components generated");
7726
8009
  }
7727
8010
  } catch {
7728
- spinner.warn("Phase 3.5/5 \u2014 Could not extract shared components (continuing without)");
8011
+ spinner.warn("Phase 4.5/6 \u2014 Could not generate shared components (continuing without)");
8012
+ }
8013
+ } else if (homePageCode) {
8014
+ const manifest = await loadManifest5(projectRoot);
8015
+ const shouldSkip = reusedExistingAnchor && manifest.shared.some((e) => e.type !== "layout");
8016
+ if (!shouldSkip) {
8017
+ spinner.start("Phase 4.5/6 \u2014 Extracting shared components (legacy)...");
8018
+ try {
8019
+ const extraction = await extractSharedComponents(homePageCode, projectRoot, provider ?? "auto");
8020
+ parseOpts.sharedComponentsSummary = extraction.summary;
8021
+ if (extraction.components.length > 0) {
8022
+ const names = extraction.components.map((c) => c.name).join(", ");
8023
+ spinner.succeed(`Phase 4.5/6 \u2014 Extracted ${extraction.components.length} shared components (${names})`);
8024
+ } else {
8025
+ spinner.succeed("Phase 4.5/6 \u2014 No shared components extracted");
8026
+ }
8027
+ } catch {
8028
+ spinner.warn("Phase 4.5/6 \u2014 Could not extract shared components (continuing without)");
8029
+ }
7729
8030
  }
7730
8031
  }
7731
8032
  }
7732
8033
  if (remainingPages.length === 0) {
7733
- return homeRequest ? [homeRequest] : [];
8034
+ return { requests: homeRequest ? [homeRequest] : [], plan };
7734
8035
  }
7735
- 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.";
8036
+ spinner.start(`Phase 5/6 \u2014 Generating ${remainingPages.length} pages in parallel...`);
8037
+ 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.";
8038
+ const sharedComponentsNote = buildSharedComponentsNote(parseOpts.sharedComponentsSummary);
7737
8039
  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
8040
  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.';
8041
+ const planSummaryNote = plan ? formatPlanSummary(plan) : "";
7739
8042
  const existingPagesContext = buildExistingPagesContext(modCtx.config);
7740
8043
  const AI_CONCURRENCY = 3;
7741
- let phase4Done = 0;
8044
+ let phase5Done = 0;
7742
8045
  const remainingRequests = await pMap(
7743
8046
  remainingPages,
7744
8047
  async ({ name, id, route }) => {
8048
+ const isAuth = isAuthRoute(route) || isAuthRoute(name);
8049
+ const pageType = plan ? getPageType(route, plan) : inferPageTypeFromRoute(route);
8050
+ const designConstraints = getDesignQualityForType(pageType);
8051
+ 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
8052
  const prompt = [
7746
8053
  `Create ONE page called "${name}" at route "${route}".`,
7747
8054
  `Context: ${message}.`,
7748
8055
  `Generate complete pageCode for this single page only. Do not generate other pages.`,
7749
- sharedNote,
8056
+ `PAGE TYPE: ${pageType}`,
8057
+ designConstraints,
8058
+ sharedLayoutNote,
8059
+ sharedComponentsNote,
7750
8060
  routeNote,
7751
8061
  alignmentNote,
8062
+ authNote,
8063
+ planSummaryNote,
7752
8064
  existingPagesContext,
7753
8065
  styleContext
7754
8066
  ].filter(Boolean).join("\n\n");
7755
8067
  try {
7756
8068
  const result = await parseModification(prompt, modCtx, provider, parseOpts);
7757
- phase4Done++;
7758
- spinner.text = `Phase 4/5 \u2014 ${phase4Done}/${remainingPages.length} pages generated...`;
8069
+ phase5Done++;
8070
+ spinner.text = `Phase 5/6 \u2014 ${phase5Done}/${remainingPages.length} pages generated...`;
7759
8071
  const codePage = result.requests.find((r) => r.type === "add-page");
7760
8072
  return codePage || { type: "add-page", target: "new", changes: { id, name, route } };
7761
8073
  } catch {
7762
- phase4Done++;
7763
- spinner.text = `Phase 4/5 \u2014 ${phase4Done}/${remainingPages.length} pages generated...`;
8074
+ phase5Done++;
8075
+ spinner.text = `Phase 5/6 \u2014 ${phase5Done}/${remainingPages.length} pages generated...`;
7764
8076
  return { type: "add-page", target: "new", changes: { id, name, route } };
7765
8077
  }
7766
8078
  },
@@ -7768,19 +8080,25 @@ async function splitGeneratePages(spinner, message, modCtx, provider, parseOpts)
7768
8080
  );
7769
8081
  const allRequests = reusedExistingAnchor ? [...remainingRequests] : homeRequest ? [homeRequest, ...remainingRequests] : [...remainingRequests];
7770
8082
  const emptyPages = allRequests.filter((r) => r.type === "add-page" && !r.changes?.pageCode);
7771
- if (emptyPages.length > 0 && emptyPages.length <= 5) {
8083
+ if (emptyPages.length > 0) {
7772
8084
  spinner.text = `Retrying ${emptyPages.length} page(s) without code...`;
7773
8085
  for (const req of emptyPages) {
7774
8086
  const page = req.changes;
7775
8087
  const pageName = page.name || page.id || "page";
7776
8088
  const pageRoute = page.route || `/${pageName.toLowerCase()}`;
7777
8089
  try {
7778
- const retryResult = await parseModification(
7779
- `Create ONE page called "${pageName}" at route "${pageRoute}". Context: ${message}. Generate complete pageCode for this single page only.`,
7780
- modCtx,
7781
- provider,
7782
- parseOpts
8090
+ const retryPageType = plan ? getPageType(pageRoute, plan) : inferPageTypeFromRoute(pageRoute);
8091
+ const lightweightPrompt = buildLightweightPagePrompt(
8092
+ pageName,
8093
+ pageRoute,
8094
+ styleContext || "",
8095
+ parseOpts.sharedComponentsSummary,
8096
+ retryPageType
7783
8097
  );
8098
+ const retryResult = await parseModification(lightweightPrompt, modCtx, provider, {
8099
+ ...parseOpts,
8100
+ lightweight: true
8101
+ });
7784
8102
  const codePage = retryResult.requests.find((r) => r.type === "add-page");
7785
8103
  if (codePage && codePage.changes?.pageCode) {
7786
8104
  const idx = allRequests.indexOf(req);
@@ -7791,8 +8109,8 @@ async function splitGeneratePages(spinner, message, modCtx, provider, parseOpts)
7791
8109
  }
7792
8110
  }
7793
8111
  const withCode = allRequests.filter((r) => r.changes?.pageCode).length;
7794
- spinner.succeed(`Phase 4/5 \u2014 Generated ${allRequests.length} pages (${withCode} with full code)`);
7795
- return allRequests;
8112
+ spinner.succeed(`Phase 5/6 \u2014 Generated ${allRequests.length} pages (${withCode} with full code)`);
8113
+ return { requests: allRequests, plan };
7796
8114
  }
7797
8115
  var SharedExtractionItemSchema = z.object({
7798
8116
  name: z.string().min(2).max(50),
@@ -7825,7 +8143,9 @@ async function extractSharedComponents(homePageCode, projectRoot, aiProvider) {
7825
8143
  } catch {
7826
8144
  return { components: [], summary: buildSharedComponentsSummary(manifest) };
7827
8145
  }
7828
- const reservedSet = new Set(getComponentProvider().listNames().map((n) => n.toLowerCase()));
8146
+ const reservedSet = new Set(
8147
+ getComponentProvider().listNames().map((n) => n.toLowerCase())
8148
+ );
7829
8149
  const existingSet = new Set(manifest.shared.map((e) => e.name.toLowerCase()));
7830
8150
  const seenNames = /* @__PURE__ */ new Set();
7831
8151
  const filtered = rawItems.filter((item) => {
@@ -7904,7 +8224,7 @@ function extractAppNameFromPrompt(prompt) {
7904
8224
  import { resolve as resolve7 } from "path";
7905
8225
  import { mkdir as mkdir4 } from "fs/promises";
7906
8226
  import { dirname as dirname6 } from "path";
7907
- import chalk11 from "chalk";
8227
+ import chalk12 from "chalk";
7908
8228
  import {
7909
8229
  getTemplateForPageType,
7910
8230
  loadManifest as loadManifest6,
@@ -7916,7 +8236,7 @@ import {
7916
8236
 
7917
8237
  // src/commands/chat/code-generator.ts
7918
8238
  import { resolve as resolve6 } from "path";
7919
- import { existsSync as existsSync14 } from "fs";
8239
+ import { existsSync as existsSync14, readdirSync as readdirSync2, readFileSync as readFileSync9 } from "fs";
7920
8240
  import { mkdir as mkdir3 } from "fs/promises";
7921
8241
  import { dirname as dirname5 } from "path";
7922
8242
  import {
@@ -7925,7 +8245,7 @@ import {
7925
8245
  TailwindConfigGenerator
7926
8246
  } from "@getcoherent/core";
7927
8247
  import { integrateSharedLayoutIntoRootLayout as integrateSharedLayoutIntoRootLayout2, generateSharedComponent as generateSharedComponent3 } from "@getcoherent/core";
7928
- import chalk9 from "chalk";
8248
+ import chalk10 from "chalk";
7929
8249
 
7930
8250
  // src/utils/file-hashes.ts
7931
8251
  import { createHash } from "crypto";
@@ -8029,7 +8349,7 @@ async function canOverwriteShared(projectRoot, componentFile, storedHashes) {
8029
8349
  if (!storedHash) return true;
8030
8350
  const edited = await isManuallyEdited(filePath, storedHash);
8031
8351
  if (edited) {
8032
- console.log(chalk9.yellow(` \u26A0 Skipping ${componentFile} \u2014 manually edited since last generation`));
8352
+ console.log(chalk10.yellow(` \u26A0 Skipping ${componentFile} \u2014 manually edited since last generation`));
8033
8353
  }
8034
8354
  return !edited;
8035
8355
  }
@@ -8092,9 +8412,31 @@ async function regenerateLayout(config2, projectRoot, options = { navChanged: fa
8092
8412
  await ensureAppRouteGroupLayout(projectRoot, config2.navigation?.type, options.navChanged);
8093
8413
  } catch (err) {
8094
8414
  if (process.env.COHERENT_DEBUG === "1") {
8095
- console.log(chalk9.dim("Layout integration warning:", err));
8415
+ console.log(chalk10.dim("Layout integration warning:", err));
8416
+ }
8417
+ }
8418
+ }
8419
+ async function scanAndInstallSharedDeps(projectRoot) {
8420
+ const sharedDir = resolve6(projectRoot, "components", "shared");
8421
+ if (!existsSync14(sharedDir)) return [];
8422
+ const files = readdirSync2(sharedDir).filter((f) => f.endsWith(".tsx") || f.endsWith(".ts"));
8423
+ const installed = [];
8424
+ const provider = getComponentProvider();
8425
+ for (const file of files) {
8426
+ const code = readFileSync9(resolve6(sharedDir, file), "utf-8");
8427
+ const importMatches = [...code.matchAll(/@\/components\/ui\/([a-z0-9-]+)/g)];
8428
+ for (const [, componentId] of importMatches) {
8429
+ const uiPath = resolve6(projectRoot, "components", "ui", `${componentId}.tsx`);
8430
+ if (!existsSync14(uiPath) && provider.has(componentId)) {
8431
+ try {
8432
+ await provider.installComponent(componentId, projectRoot);
8433
+ installed.push(componentId);
8434
+ } catch {
8435
+ }
8436
+ }
8096
8437
  }
8097
8438
  }
8439
+ return [...new Set(installed)];
8098
8440
  }
8099
8441
  async function ensureAppRouteGroupLayout(projectRoot, navType, forceUpdate = false) {
8100
8442
  const layoutPath = resolve6(projectRoot, "app", "(app)", "layout.tsx");
@@ -8138,6 +8480,59 @@ export default function AppLayout({
8138
8480
  }
8139
8481
  `;
8140
8482
  }
8483
+ function buildGroupLayoutCode(layout, _pages) {
8484
+ if (layout === "sidebar" || layout === "both") {
8485
+ return `import { Sidebar } from '@/components/shared/sidebar'
8486
+
8487
+ export default function GroupLayout({
8488
+ children,
8489
+ }: {
8490
+ children: React.ReactNode
8491
+ }) {
8492
+ return (
8493
+ <div className="flex min-h-[calc(100vh-3.5rem)]">
8494
+ <Sidebar />
8495
+ <main className="flex-1 px-4 sm:px-6 lg:px-8 py-6">
8496
+ {children}
8497
+ </main>
8498
+ </div>
8499
+ )
8500
+ }
8501
+ `;
8502
+ }
8503
+ if (layout === "none") {
8504
+ return `export default function GroupLayout({
8505
+ children,
8506
+ }: {
8507
+ children: React.ReactNode
8508
+ }) {
8509
+ return <>{children}</>
8510
+ }
8511
+ `;
8512
+ }
8513
+ return `export default function GroupLayout({
8514
+ children,
8515
+ }: {
8516
+ children: React.ReactNode
8517
+ }) {
8518
+ return (
8519
+ <main className="mx-auto w-full max-w-7xl px-4 sm:px-6 lg:px-8 py-6">
8520
+ {children}
8521
+ </main>
8522
+ )
8523
+ }
8524
+ `;
8525
+ }
8526
+ async function ensurePlanGroupLayouts(projectRoot, plan) {
8527
+ const { mkdir: mkdirAsync } = await import("fs/promises");
8528
+ for (const group of plan.groups) {
8529
+ const groupDir = resolve6(projectRoot, "app", `(${group.id})`);
8530
+ await mkdirAsync(groupDir, { recursive: true });
8531
+ const layoutPath = resolve6(groupDir, "layout.tsx");
8532
+ const code = buildGroupLayoutCode(group.layout, group.pages);
8533
+ await writeFile(layoutPath, code);
8534
+ }
8535
+ }
8141
8536
  async function regenerateFiles(modified, config2, projectRoot, options = { navChanged: false }) {
8142
8537
  const componentIds = /* @__PURE__ */ new Set();
8143
8538
  const pageIds = /* @__PURE__ */ new Set();
@@ -8153,6 +8548,10 @@ async function regenerateFiles(modified, config2, projectRoot, options = { navCh
8153
8548
  navChanged: options.navChanged,
8154
8549
  storedHashes: options.storedHashes
8155
8550
  });
8551
+ const sharedInstalled = await scanAndInstallSharedDeps(projectRoot);
8552
+ if (sharedInstalled.length > 0 && process.env.COHERENT_DEBUG === "1") {
8553
+ console.log(chalk10.dim(` Auto-installed shared deps: ${sharedInstalled.join(", ")}`));
8554
+ }
8156
8555
  }
8157
8556
  if (componentIds.size > 0) {
8158
8557
  const twGen = new TailwindConfigGenerator(config2);
@@ -8208,7 +8607,7 @@ function extractBalancedTag(source, tagName) {
8208
8607
  }
8209
8608
 
8210
8609
  // src/commands/chat/reporting.ts
8211
- import chalk10 from "chalk";
8610
+ import chalk11 from "chalk";
8212
8611
  function extractImportsFrom(code, fromPath) {
8213
8612
  const escaped = fromPath.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
8214
8613
  const regex = new RegExp(`import\\s*\\{([^}]+)\\}\\s*from\\s*['"\`]${escaped}[^'"\`]*['"\`]`, "g");
@@ -8230,27 +8629,27 @@ function printPostGenerationReport(opts) {
8230
8629
  const iconCount = extractImportsFrom(code, "lucide-react").length;
8231
8630
  const hasInstalled = postFixes.some((f) => f.startsWith("Installed:"));
8232
8631
  const syntaxStatus = postFixes.length > 0 ? postFixes.some((f) => f.includes("metadata")) ? "fixed (escaped metadata quotes) \u2714" : "fixed \u2714" : "valid \u2714";
8233
- console.log(chalk10.green(`
8632
+ console.log(chalk11.green(`
8234
8633
  \u2705 Page "${pageTitle}" ${action} at ${filePath}
8235
8634
  `));
8236
8635
  if (uiComponents.length > 0) {
8237
- console.log(chalk10.dim(` Components: ${uiComponents.join(", ")} (from @/components/ui)`));
8636
+ console.log(chalk11.dim(` Components: ${uiComponents.join(", ")} (from @/components/ui)`));
8238
8637
  }
8239
8638
  if (inCodeShared.length > 0) {
8240
- console.log(chalk10.dim(` Shared: ${inCodeShared.map((s) => `${s.id} (${s.name})`).join(", ")}`));
8639
+ console.log(chalk11.dim(` Shared: ${inCodeShared.map((s) => `${s.id} (${s.name})`).join(", ")}`));
8241
8640
  }
8242
8641
  if (layoutShared.length > 0) {
8243
- console.log(chalk10.dim(` Layout: ${layoutShared.map((l) => `${l.id} (${l.name})`).join(", ")} via layout.tsx`));
8642
+ console.log(chalk11.dim(` Layout: ${layoutShared.map((l) => `${l.id} (${l.name})`).join(", ")} via layout.tsx`));
8244
8643
  }
8245
8644
  if (iconCount > 0) {
8246
- console.log(chalk10.dim(` Icons: ${iconCount} from lucide-react`));
8645
+ console.log(chalk11.dim(` Icons: ${iconCount} from lucide-react`));
8247
8646
  }
8248
8647
  if (hasInstalled) {
8249
- console.log(chalk10.dim(" Dependencies: installed \u2714"));
8648
+ console.log(chalk11.dim(" Dependencies: installed \u2714"));
8250
8649
  }
8251
- console.log(chalk10.dim(` Syntax: ${syntaxStatus}`));
8650
+ console.log(chalk11.dim(` Syntax: ${syntaxStatus}`));
8252
8651
  if (route) {
8253
- console.log(chalk10.cyan(`
8652
+ console.log(chalk11.cyan(`
8254
8653
  Preview: http://localhost:3000${route}`));
8255
8654
  }
8256
8655
  console.log("");
@@ -8258,35 +8657,35 @@ function printPostGenerationReport(opts) {
8258
8657
  function printSharedComponentReport(opts) {
8259
8658
  const { id, name, file, instruction, postFixes = [] } = opts;
8260
8659
  const syntaxStatus = postFixes.length > 0 ? "fixed \u2714" : "valid \u2714";
8261
- console.log(chalk10.green(`
8660
+ console.log(chalk11.green(`
8262
8661
  \u2705 Updated ${id} (${name}) at ${file}
8263
8662
  `));
8264
8663
  if (instruction) {
8265
8664
  const snippet = instruction.length > 60 ? instruction.slice(0, 57) + "..." : instruction;
8266
- console.log(chalk10.dim(` Changed: ${snippet}`));
8665
+ console.log(chalk11.dim(` Changed: ${snippet}`));
8267
8666
  }
8268
- console.log(chalk10.dim(" Affects: all pages via layout.tsx"));
8269
- console.log(chalk10.dim(` Syntax: ${syntaxStatus}`));
8667
+ console.log(chalk11.dim(" Affects: all pages via layout.tsx"));
8668
+ console.log(chalk11.dim(` Syntax: ${syntaxStatus}`));
8270
8669
  console.log("");
8271
8670
  }
8272
8671
  function printLinkSharedReport(opts) {
8273
8672
  const { sharedId, sharedName, pageTarget, route, postFixes = [] } = opts;
8274
8673
  const syntaxStatus = postFixes.length > 0 ? "fixed \u2714" : "valid \u2714";
8275
- console.log(chalk10.green(`
8674
+ console.log(chalk11.green(`
8276
8675
  \u2705 Linked ${sharedId} (${sharedName}) to page "${pageTarget}"
8277
8676
  `));
8278
- console.log(chalk10.dim(` Syntax: ${syntaxStatus}`));
8279
- console.log(chalk10.cyan(` Preview: http://localhost:3000${route}`));
8677
+ console.log(chalk11.dim(` Syntax: ${syntaxStatus}`));
8678
+ console.log(chalk11.cyan(` Preview: http://localhost:3000${route}`));
8280
8679
  console.log("");
8281
8680
  }
8282
8681
  function printPromoteAndLinkReport(opts) {
8283
8682
  const { id, name, file, usedInFiles, postFixes = [] } = opts;
8284
8683
  const syntaxStatus = postFixes.length > 0 ? "fixed \u2714" : "valid \u2714";
8285
- console.log(chalk10.green(`
8684
+ console.log(chalk11.green(`
8286
8685
  \u2705 Created ${id} (${name}) at ${file}
8287
8686
  `));
8288
- console.log(chalk10.dim(` Linked to: ${usedInFiles.length} page(s)`));
8289
- console.log(chalk10.dim(` Syntax: ${syntaxStatus}`));
8687
+ console.log(chalk11.dim(` Linked to: ${usedInFiles.length} page(s)`));
8688
+ console.log(chalk11.dim(` Syntax: ${syntaxStatus}`));
8290
8689
  console.log("");
8291
8690
  }
8292
8691
  function showPreview(requests, results, config2, preflightInstalledNames) {
@@ -8304,23 +8703,23 @@ function showPreview(requests, results, config2, preflightInstalledNames) {
8304
8703
  const modifiedSharedComponents = successfulPairs.filter(({ request }) => request.type === "modify-layout-block");
8305
8704
  const modifiedPages = successfulPairs.filter(({ request }) => request.type === "update-page");
8306
8705
  const tokenChanges = successfulPairs.filter(({ request }) => request.type === "update-token");
8307
- console.log(chalk10.bold.cyan("\n\u{1F4CB} Changes Applied:\n"));
8706
+ console.log(chalk11.bold.cyan("\n\u{1F4CB} Changes Applied:\n"));
8308
8707
  if (preflightInstalledNames && preflightInstalledNames.length > 0) {
8309
- console.log(chalk10.cyan("\u{1F50D} Pre-flight check: Installed missing components:"));
8708
+ console.log(chalk11.cyan("\u{1F50D} Pre-flight check: Installed missing components:"));
8310
8709
  preflightInstalledNames.forEach((name) => {
8311
- console.log(chalk10.green(` \u2728 Auto-installed ${name}`));
8710
+ console.log(chalk11.green(` \u2728 Auto-installed ${name}`));
8312
8711
  });
8313
8712
  console.log("");
8314
8713
  }
8315
8714
  if (addedComponents.length > 0) {
8316
8715
  const names = addedComponents.map(({ request }) => request.changes.name).filter(Boolean);
8317
- console.log(chalk10.green("\u{1F4E6} Components:"));
8318
- console.log(chalk10.white(` \u2728 Auto-installed: ${names.join(", ")}`));
8716
+ console.log(chalk11.green("\u{1F4E6} Components:"));
8717
+ console.log(chalk11.white(` \u2728 Auto-installed: ${names.join(", ")}`));
8319
8718
  }
8320
8719
  if (customComponents.length > 0) {
8321
8720
  const names = customComponents.map(({ request }) => request.changes.name).filter(Boolean);
8322
- if (addedComponents.length === 0) console.log(chalk10.green("\u{1F4E6} Components:"));
8323
- console.log(chalk10.white(` \u2728 Created: ${names.join(", ")}`));
8721
+ if (addedComponents.length === 0) console.log(chalk11.green("\u{1F4E6} Components:"));
8722
+ console.log(chalk11.white(` \u2728 Created: ${names.join(", ")}`));
8324
8723
  }
8325
8724
  const usedComponentIds = /* @__PURE__ */ new Set();
8326
8725
  addedPages.forEach(({ request }) => {
@@ -8335,71 +8734,71 @@ function showPreview(requests, results, config2, preflightInstalledNames) {
8335
8734
  ]);
8336
8735
  const reusedIds = [...usedComponentIds].filter((id) => !newComponentIds.has(id));
8337
8736
  if (reusedIds.length > 0) {
8338
- if (addedComponents.length === 0 && customComponents.length === 0) console.log(chalk10.green("\u{1F4E6} Components:"));
8339
- console.log(chalk10.white(` \u{1F504} Reused: ${reusedIds.join(", ")}`));
8737
+ if (addedComponents.length === 0 && customComponents.length === 0) console.log(chalk11.green("\u{1F4E6} Components:"));
8738
+ console.log(chalk11.white(` \u{1F504} Reused: ${reusedIds.join(", ")}`));
8340
8739
  }
8341
8740
  if (addedComponents.length > 0 || customComponents.length > 0 || reusedIds.length > 0) {
8342
8741
  console.log("");
8343
8742
  }
8344
8743
  if (addedPages.length > 0) {
8345
- console.log(chalk10.green("\u{1F4C4} Pages Created:"));
8744
+ console.log(chalk11.green("\u{1F4C4} Pages Created:"));
8346
8745
  addedPages.forEach(({ request }) => {
8347
8746
  const page = request.changes;
8348
8747
  const route = page.route || "/";
8349
- console.log(chalk10.white(` \u2728 ${page.name || "Page"}`));
8350
- console.log(chalk10.gray(` Route: ${route}`));
8351
- console.log(chalk10.gray(` Sections: ${page.sections?.length ?? 0}`));
8748
+ console.log(chalk11.white(` \u2728 ${page.name || "Page"}`));
8749
+ console.log(chalk11.gray(` Route: ${route}`));
8750
+ console.log(chalk11.gray(` Sections: ${page.sections?.length ?? 0}`));
8352
8751
  });
8353
8752
  console.log("");
8354
8753
  }
8355
8754
  if (modifiedComponents.length > 0 || modifiedSharedComponents.length > 0 || modifiedPages.length > 0 || tokenChanges.length > 0) {
8356
- console.log(chalk10.yellow("\u{1F527} Modified:"));
8755
+ console.log(chalk11.yellow("\u{1F527} Modified:"));
8357
8756
  modifiedComponents.forEach(({ result }) => {
8358
- console.log(chalk10.white(` \u2022 ${result.message}`));
8757
+ console.log(chalk11.white(` \u2022 ${result.message}`));
8359
8758
  });
8360
8759
  modifiedSharedComponents.forEach(({ result }) => {
8361
- console.log(chalk10.white(` \u2022 ${result.message}`));
8760
+ console.log(chalk11.white(` \u2022 ${result.message}`));
8362
8761
  });
8363
8762
  modifiedPages.forEach(({ result }) => {
8364
- console.log(chalk10.white(` \u2022 ${result.message}`));
8763
+ console.log(chalk11.white(` \u2022 ${result.message}`));
8365
8764
  });
8366
8765
  tokenChanges.forEach(({ result }) => {
8367
- console.log(chalk10.white(` \u2022 ${result.message}`));
8766
+ console.log(chalk11.white(` \u2022 ${result.message}`));
8368
8767
  });
8369
8768
  console.log("");
8370
8769
  }
8371
8770
  if (failedPairs.length > 0) {
8372
- console.log(chalk10.red("\u274C Failed modifications:"));
8771
+ console.log(chalk11.red("\u274C Failed modifications:"));
8373
8772
  failedPairs.forEach(({ result }) => {
8374
- console.log(chalk10.gray(` \u2716 ${result.message}`));
8773
+ console.log(chalk11.gray(` \u2716 ${result.message}`));
8375
8774
  });
8376
8775
  console.log("");
8377
8776
  }
8378
8777
  const successCount = successfulPairs.length;
8379
8778
  const totalCount = results.length;
8380
8779
  if (successCount === totalCount) {
8381
- console.log(chalk10.green.bold(`\u2705 Success! ${successCount} modification(s) applied
8780
+ console.log(chalk11.green.bold(`\u2705 Success! ${successCount} modification(s) applied
8382
8781
  `));
8383
8782
  } else {
8384
- console.log(chalk10.yellow.bold(`\u26A0\uFE0F Partial success: ${successCount}/${totalCount} modification(s) applied
8783
+ console.log(chalk11.yellow.bold(`\u26A0\uFE0F Partial success: ${successCount}/${totalCount} modification(s) applied
8385
8784
  `));
8386
8785
  }
8387
8786
  if (addedPages.length > 0) {
8388
8787
  const firstPage = addedPages[0].request.changes;
8389
8788
  const route = firstPage?.route || "/";
8390
- console.log(chalk10.cyan("\u{1F680} What's next:\n"));
8391
- console.log(chalk10.white(" \u{1F4FA} View in browser:"));
8392
- console.log(chalk10.cyan(" coherent preview"));
8393
- console.log(chalk10.gray(` \u2192 Opens http://localhost:3000${route}
8789
+ console.log(chalk11.cyan("\u{1F680} What's next:\n"));
8790
+ console.log(chalk11.white(" \u{1F4FA} View in browser:"));
8791
+ console.log(chalk11.cyan(" coherent preview"));
8792
+ console.log(chalk11.gray(` \u2192 Opens http://localhost:3000${route}
8394
8793
  `));
8395
- console.log(chalk10.white(" \u{1F3A8} Customize:"));
8396
- console.log(chalk10.cyan(' coherent chat "make buttons rounded"'));
8397
- console.log(chalk10.cyan(` coherent chat "add hero section to ${firstPage?.name ?? "page"}"`));
8794
+ console.log(chalk11.white(" \u{1F3A8} Customize:"));
8795
+ console.log(chalk11.cyan(' coherent chat "make buttons rounded"'));
8796
+ console.log(chalk11.cyan(` coherent chat "add hero section to ${firstPage?.name ?? "page"}"`));
8398
8797
  console.log("");
8399
8798
  } else if (successCount > 0) {
8400
- console.log(chalk10.cyan("\u{1F680} What's next:\n"));
8401
- console.log(chalk10.white(" \u{1F4FA} Preview changes:"));
8402
- console.log(chalk10.cyan(" coherent preview\n"));
8799
+ console.log(chalk11.cyan("\u{1F680} What's next:\n"));
8800
+ console.log(chalk11.white(" \u{1F4FA} Preview changes:"));
8801
+ console.log(chalk11.cyan(" coherent preview\n"));
8403
8802
  }
8404
8803
  }
8405
8804
  function getChangeDescription(request, config2) {
@@ -8548,8 +8947,8 @@ async function applyModification(request, dsm, cm, pm, projectRoot, aiProvider,
8548
8947
  const newCode = await ai.editSharedComponentCode(currentCode, instruction, resolved.name);
8549
8948
  const { fixedCode, fixes } = await validateAndFixGeneratedCode(projectRoot, newCode, { isPage: false });
8550
8949
  if (fixes.length > 0) {
8551
- console.log(chalk11.dim(" \u{1F527} Post-generation fixes:"));
8552
- fixes.forEach((f) => console.log(chalk11.dim(` ${f}`)));
8950
+ console.log(chalk12.dim(" \u{1F527} Post-generation fixes:"));
8951
+ fixes.forEach((f) => console.log(chalk12.dim(` ${f}`)));
8553
8952
  }
8554
8953
  await writeFile(fullPath, fixedCode);
8555
8954
  printSharedComponentReport({
@@ -8622,8 +9021,8 @@ async function applyModification(request, dsm, cm, pm, projectRoot, aiProvider,
8622
9021
  const newPageCode = await ai.replaceInlineWithShared(pageCode, sharedCode, resolved.name, changes?.blockHint);
8623
9022
  const { fixedCode, fixes } = await validateAndFixGeneratedCode(projectRoot, newPageCode, { isPage: true });
8624
9023
  if (fixes.length > 0) {
8625
- console.log(chalk11.dim(" \u{1F527} Post-generation fixes:"));
8626
- fixes.forEach((f) => console.log(chalk11.dim(` ${f}`)));
9024
+ console.log(chalk12.dim(" \u{1F527} Post-generation fixes:"));
9025
+ fixes.forEach((f) => console.log(chalk12.dim(` ${f}`)));
8627
9026
  }
8628
9027
  await writeFile(pageFilePath, fixedCode);
8629
9028
  const manifest = await loadManifest6(projectRoot);
@@ -8725,8 +9124,8 @@ async function applyModification(request, dsm, cm, pm, projectRoot, aiProvider,
8725
9124
  const newCode = await ai.replaceInlineWithShared(linkPageCode, sharedCode, created.name, blockHint);
8726
9125
  const { fixedCode, fixes } = await validateAndFixGeneratedCode(projectRoot, newCode, { isPage: true });
8727
9126
  if (fixes.length > 0) {
8728
- console.log(chalk11.dim(" \u{1F527} Post-generation fixes:"));
8729
- fixes.forEach((f) => console.log(chalk11.dim(` ${f}`)));
9127
+ console.log(chalk12.dim(" \u{1F527} Post-generation fixes:"));
9128
+ fixes.forEach((f) => console.log(chalk12.dim(` ${f}`)));
8730
9129
  }
8731
9130
  await writeFile(fullPath, fixedCode);
8732
9131
  usedInFiles.push(relPath);
@@ -8817,7 +9216,7 @@ async function applyModification(request, dsm, cm, pm, projectRoot, aiProvider,
8817
9216
  const aiPageCode = typeof page.pageCode === "string" && page.pageCode.trim() !== "" ? page.pageCode : void 0;
8818
9217
  if (aiPageCode) {
8819
9218
  finalPageCode = aiPageCode;
8820
- if (DEBUG2) console.log(chalk11.dim(` [pageCode] Using AI-generated pageCode (user content priority)`));
9219
+ if (DEBUG2) console.log(chalk12.dim(` [pageCode] Using AI-generated pageCode (user content priority)`));
8821
9220
  } else {
8822
9221
  const inferredType = page.pageType || inferPageType(page.route || "", page.name || "");
8823
9222
  if (inferredType) {
@@ -8832,19 +9231,19 @@ async function applyModification(request, dsm, cm, pm, projectRoot, aiProvider,
8832
9231
  const content = page.structuredContent || getDefaultContent(inferredType, page.name || pageName);
8833
9232
  finalPageCode = templateFn(content, opts);
8834
9233
  if (DEBUG2)
8835
- console.log(chalk11.dim(` [template] Used "${inferredType}" template (inferred from route/name)`));
9234
+ console.log(chalk12.dim(` [template] Used "${inferredType}" template (inferred from route/name)`));
8836
9235
  } catch {
8837
- if (DEBUG2) console.log(chalk11.dim(` [template] Failed for "${inferredType}"`));
9236
+ if (DEBUG2) console.log(chalk12.dim(` [template] Failed for "${inferredType}"`));
8838
9237
  }
8839
9238
  }
8840
9239
  }
8841
9240
  }
8842
9241
  if (!finalPageCode) {
8843
- console.log(chalk11.yellow(`
9242
+ console.log(chalk12.yellow(`
8844
9243
  \u26A0\uFE0F Page "${page.name || page.id}" has no generated code \u2014 it will appear empty.`));
8845
- console.log(chalk11.dim(" This usually means the AI did not produce pageCode for this page."));
9244
+ console.log(chalk12.dim(" This usually means the AI did not produce pageCode for this page."));
8846
9245
  console.log(
8847
- chalk11.dim(
9246
+ chalk12.dim(
8848
9247
  ' Try running: coherent chat "regenerate the ' + (page.name || page.id) + ' page with full content"'
8849
9248
  )
8850
9249
  );
@@ -8898,7 +9297,9 @@ async function applyModification(request, dsm, cm, pm, projectRoot, aiProvider,
8898
9297
  }
8899
9298
  const { code: layoutStripped, stripped } = stripInlineLayoutElements(codeToWrite);
8900
9299
  codeToWrite = layoutStripped;
8901
- if (!isMarketingRoute(route)) {
9300
+ const currentPlan = projectRoot ? loadPlan(projectRoot) : null;
9301
+ const pageType = currentPlan ? getPageType(route, currentPlan) : isMarketingRoute(route) ? "marketing" : isAuth ? "auth" : "app";
9302
+ if (pageType === "app") {
8902
9303
  const { code: normalized, fixed: wrapperFixed } = normalizePageWrapper(codeToWrite);
8903
9304
  if (wrapperFixed) {
8904
9305
  codeToWrite = normalized;
@@ -8908,8 +9309,8 @@ async function applyModification(request, dsm, cm, pm, projectRoot, aiProvider,
8908
9309
  const allFixes = [...postFixes, ...autoFixes];
8909
9310
  if (stripped.length > 0) allFixes.push(`stripped inline ${stripped.join(", ")} (layout owns these)`);
8910
9311
  if (allFixes.length > 0) {
8911
- console.log(chalk11.dim(" \u{1F527} Post-generation fixes:"));
8912
- allFixes.forEach((f) => console.log(chalk11.dim(` ${f}`)));
9312
+ console.log(chalk12.dim(" \u{1F527} Post-generation fixes:"));
9313
+ allFixes.forEach((f) => console.log(chalk12.dim(` ${f}`)));
8913
9314
  }
8914
9315
  await writeFile(filePath, codeToWrite);
8915
9316
  const pageIdx = dsm.getConfig().pages.findIndex((p) => p.id === page.id);
@@ -8921,7 +9322,15 @@ async function applyModification(request, dsm, cm, pm, projectRoot, aiProvider,
8921
9322
  pm.updateConfig(cfg);
8922
9323
  }
8923
9324
  const manifestForAudit = await loadManifest6(projectRoot);
8924
- await warnInlineDuplicates(projectRoot, page.name || page.id || route.slice(1), codeToWrite, manifestForAudit);
9325
+ const planForAudit = loadPlan(projectRoot);
9326
+ await warnInlineDuplicates(
9327
+ projectRoot,
9328
+ page.name || page.id || route.slice(1),
9329
+ route,
9330
+ codeToWrite,
9331
+ manifestForAudit,
9332
+ planForAudit ?? void 0
9333
+ );
8925
9334
  const relFilePath = routeToRelPath(route, isAuth);
8926
9335
  printPostGenerationReport({
8927
9336
  action: "created",
@@ -8938,7 +9347,7 @@ async function applyModification(request, dsm, cm, pm, projectRoot, aiProvider,
8938
9347
  const errors = issues.filter((i) => i.severity === "error");
8939
9348
  if (errors.length >= 2 && aiProvider) {
8940
9349
  console.log(
8941
- chalk11.yellow(`
9350
+ chalk12.yellow(`
8942
9351
  \u{1F504} ${errors.length} quality errors \u2014 attempting AI fix for ${page.name || page.id}...`)
8943
9352
  );
8944
9353
  try {
@@ -8967,7 +9376,7 @@ Rules:
8967
9376
  await writeFile(filePath, codeToWrite);
8968
9377
  issues = validatePageQuality(codeToWrite);
8969
9378
  const finalErrors = issues.filter((i) => i.severity === "error").length;
8970
- console.log(chalk11.green(` \u2714 Quality fix: ${errors.length} \u2192 ${finalErrors} errors`));
9379
+ console.log(chalk12.green(` \u2714 Quality fix: ${errors.length} \u2192 ${finalErrors} errors`));
8971
9380
  }
8972
9381
  }
8973
9382
  }
@@ -8976,15 +9385,15 @@ Rules:
8976
9385
  }
8977
9386
  const report = formatIssues(issues);
8978
9387
  if (report) {
8979
- console.log(chalk11.yellow(`
9388
+ console.log(chalk12.yellow(`
8980
9389
  \u{1F50D} Quality check for ${page.name || page.id}:`));
8981
- console.log(chalk11.dim(report));
9390
+ console.log(chalk12.dim(report));
8982
9391
  }
8983
9392
  const consistency = checkDesignConsistency(codeToWrite);
8984
9393
  if (consistency.length > 0) {
8985
- console.log(chalk11.yellow(`
9394
+ console.log(chalk12.yellow(`
8986
9395
  \u{1F3A8} Design consistency for ${page.name || page.id}:`));
8987
- consistency.forEach((w) => console.log(chalk11.dim(` \u26A0 [${w.type}] ${w.message}`)));
9396
+ consistency.forEach((w) => console.log(chalk12.dim(` \u26A0 [${w.type}] ${w.message}`)));
8988
9397
  }
8989
9398
  }
8990
9399
  }
@@ -8999,9 +9408,9 @@ Rules:
8999
9408
  const changes = request.changes;
9000
9409
  const instruction = originalMessage || (typeof changes?.instruction === "string" ? changes.instruction : void 0);
9001
9410
  let resolvedPageCode = typeof changes?.pageCode === "string" && changes.pageCode.trim() !== "" ? changes.pageCode : void 0;
9002
- if (DEBUG2 && instruction) console.log(chalk11.dim(` [update-page] instruction: ${instruction.slice(0, 120)}...`));
9411
+ if (DEBUG2 && instruction) console.log(chalk12.dim(` [update-page] instruction: ${instruction.slice(0, 120)}...`));
9003
9412
  if (DEBUG2 && resolvedPageCode)
9004
- console.log(chalk11.dim(` [update-page] has pageCode (${resolvedPageCode.length} chars)`));
9413
+ console.log(chalk12.dim(` [update-page] has pageCode (${resolvedPageCode.length} chars)`));
9005
9414
  const configChanges = { ...changes };
9006
9415
  delete configChanges.pageCode;
9007
9416
  delete configChanges.pageType;
@@ -9025,12 +9434,12 @@ Rules:
9025
9434
  try {
9026
9435
  currentCode = await readFile(absPath);
9027
9436
  } catch {
9028
- if (DEBUG2) console.log(chalk11.dim(` [update-page] Could not read current file at ${absPath}`));
9437
+ if (DEBUG2) console.log(chalk12.dim(` [update-page] Could not read current file at ${absPath}`));
9029
9438
  }
9030
9439
  if (currentCode) {
9031
9440
  const ai = await createAIProvider(aiProvider ?? "auto");
9032
9441
  if (ai.editPageCode) {
9033
- console.log(chalk11.dim(" \u270F\uFE0F Applying changes to existing page..."));
9442
+ console.log(chalk12.dim(" \u270F\uFE0F Applying changes to existing page..."));
9034
9443
  const coreRules = CORE_CONSTRAINTS;
9035
9444
  const qualityRules = DESIGN_QUALITY;
9036
9445
  const contextualRules = selectContextualRules(instruction);
@@ -9050,15 +9459,15 @@ ${contextualRules}
9050
9459
  ${routeRules}
9051
9460
  ${pagesCtx}`
9052
9461
  );
9053
- if (DEBUG2) console.log(chalk11.dim(` [update-page] AI returned ${resolvedPageCode.length} chars`));
9462
+ if (DEBUG2) console.log(chalk12.dim(` [update-page] AI returned ${resolvedPageCode.length} chars`));
9054
9463
  const editIssues = verifyIncrementalEdit(currentCode, resolvedPageCode);
9055
9464
  if (editIssues.length > 0) {
9056
- console.log(chalk11.yellow(`
9465
+ console.log(chalk12.yellow(`
9057
9466
  \u26A0 Incremental edit issues for ${pageDef.name || pageDef.id}:`));
9058
- editIssues.forEach((issue) => console.log(chalk11.dim(` [${issue.type}] ${issue.message}`)));
9467
+ editIssues.forEach((issue) => console.log(chalk12.dim(` [${issue.type}] ${issue.message}`)));
9059
9468
  }
9060
9469
  } else {
9061
- console.log(chalk11.yellow(" \u26A0 AI provider does not support editPageCode"));
9470
+ console.log(chalk12.yellow(" \u26A0 AI provider does not support editPageCode"));
9062
9471
  }
9063
9472
  }
9064
9473
  }
@@ -9098,7 +9507,9 @@ ${pagesCtx}`
9098
9507
  }
9099
9508
  const { code: layoutStripped, stripped } = stripInlineLayoutElements(codeToWrite);
9100
9509
  codeToWrite = layoutStripped;
9101
- if (!isMarketingRoute(route)) {
9510
+ const currentPlan2 = projectRoot ? loadPlan(projectRoot) : null;
9511
+ const pageType2 = currentPlan2 ? getPageType(route, currentPlan2) : isMarketingRoute(route) ? "marketing" : isAuth ? "auth" : "app";
9512
+ if (pageType2 === "app") {
9102
9513
  const { code: normalized, fixed: wrapperFixed } = normalizePageWrapper(codeToWrite);
9103
9514
  if (wrapperFixed) {
9104
9515
  codeToWrite = normalized;
@@ -9108,8 +9519,8 @@ ${pagesCtx}`
9108
9519
  const allFixes = [...postFixes, ...autoFixes];
9109
9520
  if (stripped.length > 0) allFixes.push(`stripped inline ${stripped.join(", ")} (layout owns these)`);
9110
9521
  if (allFixes.length > 0) {
9111
- console.log(chalk11.dim(" \u{1F527} Post-generation fixes:"));
9112
- allFixes.forEach((f) => console.log(chalk11.dim(` ${f}`)));
9522
+ console.log(chalk12.dim(" \u{1F527} Post-generation fixes:"));
9523
+ allFixes.forEach((f) => console.log(chalk12.dim(` ${f}`)));
9113
9524
  }
9114
9525
  await writeFile(absPath, codeToWrite);
9115
9526
  const updatePageIdx = dsm.getConfig().pages.findIndex((p) => p.id === pageDef.id);
@@ -9121,11 +9532,14 @@ ${pagesCtx}`
9121
9532
  pm.updateConfig(cfg);
9122
9533
  }
9123
9534
  const manifestForAudit = await loadManifest6(projectRoot);
9535
+ const planForAudit2 = loadPlan(projectRoot);
9124
9536
  await warnInlineDuplicates(
9125
9537
  projectRoot,
9126
9538
  pageDef.name || pageDef.id || route.slice(1),
9539
+ route,
9127
9540
  codeToWrite,
9128
- manifestForAudit
9541
+ manifestForAudit,
9542
+ planForAudit2 ?? void 0
9129
9543
  );
9130
9544
  const relFilePath = routeToRelPath(route, isAuth);
9131
9545
  printPostGenerationReport({
@@ -9142,15 +9556,15 @@ ${pagesCtx}`
9142
9556
  const issues = validatePageQuality(codeToWrite);
9143
9557
  const report = formatIssues(issues);
9144
9558
  if (report) {
9145
- console.log(chalk11.yellow(`
9559
+ console.log(chalk12.yellow(`
9146
9560
  \u{1F50D} Quality check for ${pageDef.name || pageDef.id}:`));
9147
- console.log(chalk11.dim(report));
9561
+ console.log(chalk12.dim(report));
9148
9562
  }
9149
9563
  const consistency = checkDesignConsistency(codeToWrite);
9150
9564
  if (consistency.length > 0) {
9151
- console.log(chalk11.yellow(`
9565
+ console.log(chalk12.yellow(`
9152
9566
  \u{1F3A8} Design consistency for ${pageDef.name || pageDef.id}:`));
9153
- consistency.forEach((w) => console.log(chalk11.dim(` \u26A0 [${w.type}] ${w.message}`)));
9567
+ consistency.forEach((w) => console.log(chalk12.dim(` \u26A0 [${w.type}] ${w.message}`)));
9154
9568
  }
9155
9569
  } else {
9156
9570
  try {
@@ -9159,8 +9573,8 @@ ${pagesCtx}`
9159
9573
  if (fixes.length > 0) {
9160
9574
  code = fixed;
9161
9575
  await writeFile(absPath, code);
9162
- console.log(chalk11.dim(" \u{1F527} Auto-fixes applied:"));
9163
- fixes.forEach((f) => console.log(chalk11.dim(` ${f}`)));
9576
+ console.log(chalk12.dim(" \u{1F527} Auto-fixes applied:"));
9577
+ fixes.forEach((f) => console.log(chalk12.dim(` ${f}`)));
9164
9578
  }
9165
9579
  const relFilePath = routeToRelPath(route, isAuth);
9166
9580
  const manifest = await loadManifest6(projectRoot);
@@ -9177,9 +9591,9 @@ ${pagesCtx}`
9177
9591
  const issues = validatePageQuality(code);
9178
9592
  const report = formatIssues(issues);
9179
9593
  if (report) {
9180
- console.log(chalk11.yellow(`
9594
+ console.log(chalk12.yellow(`
9181
9595
  \u{1F50D} Quality check for ${pageDef.name || pageDef.id}:`));
9182
- console.log(chalk11.dim(report));
9596
+ console.log(chalk12.dim(report));
9183
9597
  }
9184
9598
  } catch {
9185
9599
  }
@@ -9219,6 +9633,11 @@ function inferPageType(route, name) {
9219
9633
  if (/\bchangelog\b/.test(key)) return "changelog";
9220
9634
  if (/\babout\b/.test(key)) return "about";
9221
9635
  if (/\bsettings?\b/.test(key)) return "settings";
9636
+ if (/\bteam\b|\bmember\b/.test(key)) return "team";
9637
+ if (/\btasks?\b/.test(key) && /\[id\]|\bdetail\b/.test(key)) return "task-detail";
9638
+ if (/\btasks?\b/.test(key)) return "tasks";
9639
+ if (/\breset.?password\b/.test(key)) return "reset-password";
9640
+ if (/\bprofile\b|\baccount\b/.test(key)) return "profile";
9222
9641
  return null;
9223
9642
  }
9224
9643
  function getDefaultContent(pageType, pageName) {
@@ -9262,6 +9681,26 @@ function getDefaultContent(pageType, pageName) {
9262
9681
  settings: {
9263
9682
  title: "Settings",
9264
9683
  description: "Manage your account and preferences"
9684
+ },
9685
+ team: {
9686
+ title: "Our Team",
9687
+ description: "Meet the people behind the product"
9688
+ },
9689
+ tasks: {
9690
+ title: "Tasks",
9691
+ description: "Manage and track your tasks"
9692
+ },
9693
+ "task-detail": {
9694
+ title: "Task Detail",
9695
+ description: "View task details and activity"
9696
+ },
9697
+ "reset-password": {
9698
+ title: "Reset Password",
9699
+ description: "Enter your new password"
9700
+ },
9701
+ profile: {
9702
+ title: "Profile",
9703
+ description: "View and edit your profile"
9265
9704
  }
9266
9705
  };
9267
9706
  return defaults[pageType] || { title: pageName, description: "" };
@@ -9277,9 +9716,9 @@ function hasNavChanged(before, after) {
9277
9716
  }
9278
9717
 
9279
9718
  // src/commands/chat/interactive.ts
9280
- import chalk12 from "chalk";
9719
+ import chalk13 from "chalk";
9281
9720
  import { resolve as resolve8 } from "path";
9282
- import { existsSync as existsSync15, readFileSync as readFileSync9, writeFileSync as writeFileSync8, mkdirSync as mkdirSync5 } from "fs";
9721
+ import { existsSync as existsSync15, readFileSync as readFileSync10, writeFileSync as writeFileSync8, mkdirSync as mkdirSync5 } from "fs";
9283
9722
  import { DesignSystemManager as DesignSystemManager6, ComponentManager as ComponentManager4, loadManifest as loadManifest7 } from "@getcoherent/core";
9284
9723
  var DEBUG3 = process.env.COHERENT_DEBUG === "1";
9285
9724
  async function interactiveChat(options, chatCommandFn) {
@@ -9295,7 +9734,7 @@ async function interactiveChat(options, chatCommandFn) {
9295
9734
  const validProviders = ["claude", "openai", "auto"];
9296
9735
  const provider = (options.provider || "auto").toLowerCase();
9297
9736
  if (!validProviders.includes(provider)) {
9298
- console.error(chalk12.red(`
9737
+ console.error(chalk13.red(`
9299
9738
  \u274C Invalid provider: ${options.provider}`));
9300
9739
  process.exit(1);
9301
9740
  }
@@ -9305,18 +9744,18 @@ async function interactiveChat(options, chatCommandFn) {
9305
9744
  try {
9306
9745
  mkdirSync5(historyDir, { recursive: true });
9307
9746
  if (existsSync15(historyFile)) {
9308
- history = readFileSync9(historyFile, "utf-8").split("\n").filter(Boolean).slice(-200);
9747
+ history = readFileSync10(historyFile, "utf-8").split("\n").filter(Boolean).slice(-200);
9309
9748
  }
9310
9749
  } catch (e) {
9311
9750
  if (DEBUG3) console.error("Failed to load REPL history:", e);
9312
9751
  }
9313
- console.log(chalk12.cyan("\n\u{1F3A8} Coherent Interactive Mode"));
9314
- console.log(chalk12.dim(" Type your requests, or use built-in commands."));
9315
- console.log(chalk12.dim(' Type "help" for available commands, "exit" to quit.\n'));
9752
+ console.log(chalk13.cyan("\n\u{1F3A8} Coherent Interactive Mode"));
9753
+ console.log(chalk13.dim(" Type your requests, or use built-in commands."));
9754
+ console.log(chalk13.dim(' Type "help" for available commands, "exit" to quit.\n'));
9316
9755
  const rl = createInterface({
9317
9756
  input: process.stdin,
9318
9757
  output: process.stdout,
9319
- prompt: chalk12.cyan("Coherent> "),
9758
+ prompt: chalk13.cyan("Coherent> "),
9320
9759
  history,
9321
9760
  historySize: 200
9322
9761
  });
@@ -9330,37 +9769,37 @@ async function interactiveChat(options, chatCommandFn) {
9330
9769
  const lower = input.toLowerCase();
9331
9770
  if (lower === "exit" || lower === "quit" || lower === "q") {
9332
9771
  saveHistory();
9333
- console.log(chalk12.dim("\nBye!\n"));
9772
+ console.log(chalk13.dim("\nBye!\n"));
9334
9773
  rl.close();
9335
9774
  process.exit(0);
9336
9775
  }
9337
9776
  if (lower === "help") {
9338
- console.log(chalk12.bold("\n Built-in commands:"));
9339
- console.log(chalk12.white(" components") + chalk12.dim(" \u2014 list shared and UI components"));
9340
- console.log(chalk12.white(" pages") + chalk12.dim(" \u2014 list all pages"));
9341
- console.log(chalk12.white(" tokens") + chalk12.dim(" \u2014 show design tokens"));
9342
- console.log(chalk12.white(" status") + chalk12.dim(" \u2014 project summary"));
9343
- console.log(chalk12.white(" help") + chalk12.dim(" \u2014 this help"));
9344
- console.log(chalk12.white(" exit") + chalk12.dim(" \u2014 quit interactive mode"));
9345
- console.log(chalk12.bold("\n Target shortcuts:"));
9346
- console.log(chalk12.white(" @ComponentName <msg>") + chalk12.dim(" \u2014 target a shared component"));
9347
- console.log(chalk12.white(" @/route <msg>") + chalk12.dim(" \u2014 target a page by route"));
9348
- console.log(chalk12.dim("\n Anything else is sent to AI as a modification request.\n"));
9777
+ console.log(chalk13.bold("\n Built-in commands:"));
9778
+ console.log(chalk13.white(" components") + chalk13.dim(" \u2014 list shared and UI components"));
9779
+ console.log(chalk13.white(" pages") + chalk13.dim(" \u2014 list all pages"));
9780
+ console.log(chalk13.white(" tokens") + chalk13.dim(" \u2014 show design tokens"));
9781
+ console.log(chalk13.white(" status") + chalk13.dim(" \u2014 project summary"));
9782
+ console.log(chalk13.white(" help") + chalk13.dim(" \u2014 this help"));
9783
+ console.log(chalk13.white(" exit") + chalk13.dim(" \u2014 quit interactive mode"));
9784
+ console.log(chalk13.bold("\n Target shortcuts:"));
9785
+ console.log(chalk13.white(" @ComponentName <msg>") + chalk13.dim(" \u2014 target a shared component"));
9786
+ console.log(chalk13.white(" @/route <msg>") + chalk13.dim(" \u2014 target a page by route"));
9787
+ console.log(chalk13.dim("\n Anything else is sent to AI as a modification request.\n"));
9349
9788
  rl.prompt();
9350
9789
  return;
9351
9790
  }
9352
9791
  if (lower === "components" || lower === "list components" || lower.includes("what components")) {
9353
9792
  const manifest = await loadManifest7(projectRoot);
9354
9793
  if (manifest.shared.length === 0) {
9355
- console.log(chalk12.gray("\n No shared components yet.\n"));
9794
+ console.log(chalk13.gray("\n No shared components yet.\n"));
9356
9795
  } else {
9357
9796
  console.log("");
9358
9797
  const order = { layout: 0, section: 1, widget: 2 };
9359
9798
  const sorted = [...manifest.shared].sort((a, b) => (order[a.type] ?? 9) - (order[b.type] ?? 9));
9360
9799
  sorted.forEach((entry) => {
9361
- const usage = entry.usedIn.includes("app/layout.tsx") ? chalk12.green("all pages") : entry.usedIn.length > 0 ? chalk12.gray(entry.usedIn.join(", ")) : chalk12.gray("unused");
9800
+ const usage = entry.usedIn.includes("app/layout.tsx") ? chalk13.green("all pages") : entry.usedIn.length > 0 ? chalk13.gray(entry.usedIn.join(", ")) : chalk13.gray("unused");
9362
9801
  console.log(
9363
- ` ${chalk12.cyan(entry.id.padEnd(8))} ${chalk12.white(entry.name.padEnd(18))} ${chalk12.gray(entry.type.padEnd(9))} ${usage}`
9802
+ ` ${chalk13.cyan(entry.id.padEnd(8))} ${chalk13.white(entry.name.padEnd(18))} ${chalk13.gray(entry.type.padEnd(9))} ${usage}`
9364
9803
  );
9365
9804
  });
9366
9805
  console.log("");
@@ -9371,11 +9810,11 @@ async function interactiveChat(options, chatCommandFn) {
9371
9810
  if (lower === "pages" || lower === "list pages" || lower.includes("what pages")) {
9372
9811
  const currentConfig = dsm.getConfig();
9373
9812
  if (currentConfig.pages.length === 0) {
9374
- console.log(chalk12.gray("\n No pages yet.\n"));
9813
+ console.log(chalk13.gray("\n No pages yet.\n"));
9375
9814
  } else {
9376
9815
  console.log("");
9377
9816
  currentConfig.pages.forEach((p) => {
9378
- console.log(` ${chalk12.white(p.name.padEnd(22))} ${chalk12.gray(p.route)}`);
9817
+ console.log(` ${chalk13.white(p.name.padEnd(22))} ${chalk13.gray(p.route)}`);
9379
9818
  });
9380
9819
  console.log("");
9381
9820
  }
@@ -9385,10 +9824,10 @@ async function interactiveChat(options, chatCommandFn) {
9385
9824
  if (lower === "status") {
9386
9825
  const currentConfig = dsm.getConfig();
9387
9826
  const manifest = await loadManifest7(projectRoot);
9388
- console.log(chalk12.bold(`
9827
+ console.log(chalk13.bold(`
9389
9828
  ${currentConfig.name || "Coherent Project"}`));
9390
9829
  console.log(
9391
- chalk12.dim(
9830
+ chalk13.dim(
9392
9831
  ` Pages: ${currentConfig.pages.length} | Shared components: ${manifest.shared.length} | UI components: ${cm.getAllComponents().length}
9393
9832
  `
9394
9833
  )
@@ -9399,21 +9838,21 @@ async function interactiveChat(options, chatCommandFn) {
9399
9838
  if (lower === "tokens" || lower === "show tokens" || lower === "design tokens") {
9400
9839
  const currentConfig = dsm.getConfig();
9401
9840
  const t = currentConfig.tokens;
9402
- console.log(chalk12.bold("\n Design Tokens\n"));
9403
- console.log(chalk12.cyan(" Colors (light)"));
9841
+ console.log(chalk13.bold("\n Design Tokens\n"));
9842
+ console.log(chalk13.cyan(" Colors (light)"));
9404
9843
  for (const [k, v] of Object.entries(t.colors.light)) {
9405
- console.log(` ${chalk12.white(k.padEnd(14))} ${chalk12.gray(v)}`);
9844
+ console.log(` ${chalk13.white(k.padEnd(14))} ${chalk13.gray(v)}`);
9406
9845
  }
9407
- console.log(chalk12.cyan("\n Typography"));
9408
- console.log(` ${chalk12.white("sans".padEnd(14))} ${chalk12.gray(t.typography.fontFamily.sans)}`);
9409
- console.log(` ${chalk12.white("mono".padEnd(14))} ${chalk12.gray(t.typography.fontFamily.mono)}`);
9410
- console.log(chalk12.cyan("\n Spacing"));
9846
+ console.log(chalk13.cyan("\n Typography"));
9847
+ console.log(` ${chalk13.white("sans".padEnd(14))} ${chalk13.gray(t.typography.fontFamily.sans)}`);
9848
+ console.log(` ${chalk13.white("mono".padEnd(14))} ${chalk13.gray(t.typography.fontFamily.mono)}`);
9849
+ console.log(chalk13.cyan("\n Spacing"));
9411
9850
  for (const [k, v] of Object.entries(t.spacing)) {
9412
- console.log(` ${chalk12.white(k.padEnd(14))} ${chalk12.gray(v)}`);
9851
+ console.log(` ${chalk13.white(k.padEnd(14))} ${chalk13.gray(v)}`);
9413
9852
  }
9414
- console.log(chalk12.cyan("\n Radius"));
9853
+ console.log(chalk13.cyan("\n Radius"));
9415
9854
  for (const [k, v] of Object.entries(t.radius)) {
9416
- console.log(` ${chalk12.white(k.padEnd(14))} ${chalk12.gray(v)}`);
9855
+ console.log(` ${chalk13.white(k.padEnd(14))} ${chalk13.gray(v)}`);
9417
9856
  }
9418
9857
  console.log("");
9419
9858
  rl.prompt();
@@ -9435,7 +9874,7 @@ async function interactiveChat(options, chatCommandFn) {
9435
9874
  await dsm.load();
9436
9875
  } catch (err) {
9437
9876
  if (!err._printed) {
9438
- console.error(chalk12.red(`
9877
+ console.error(chalk13.red(`
9439
9878
  Error: ${err.message}
9440
9879
  `));
9441
9880
  }
@@ -9467,8 +9906,8 @@ async function chatCommand(message, options) {
9467
9906
  process.exit(1);
9468
9907
  };
9469
9908
  if (!message) {
9470
- console.error(chalk13.red('\n\u274C No message provided. Use: coherent chat "your request"\n'));
9471
- console.log(chalk13.dim(" Or use interactive mode: coherent chat -i\n"));
9909
+ console.error(chalk14.red('\n\u274C No message provided. Use: coherent chat "your request"\n'));
9910
+ console.log(chalk14.dim(" Or use interactive mode: coherent chat -i\n"));
9472
9911
  bail("No message provided");
9473
9912
  }
9474
9913
  const spinner = ora2("Processing your request...").start();
@@ -9478,7 +9917,7 @@ async function chatCommand(message, options) {
9478
9917
  const migrationGuard = join11(projectRoot, ".coherent", "migration-in-progress");
9479
9918
  if (existsSync16(migrationGuard)) {
9480
9919
  spinner.fail("Migration in progress");
9481
- console.error(chalk13.red("\n\u274C A migration is in progress. Run `coherent migrate --rollback` to undo first."));
9920
+ console.error(chalk14.red("\n\u274C A migration is in progress. Run `coherent migrate --rollback` to undo first."));
9482
9921
  bail("Migration in progress");
9483
9922
  }
9484
9923
  const validProviders = ["claude", "openai", "auto"];
@@ -9488,20 +9927,20 @@ async function chatCommand(message, options) {
9488
9927
  releaseLock = await acquireProjectLock(projectRoot);
9489
9928
  if (!validProviders.includes(provider)) {
9490
9929
  spinner.fail("Invalid provider");
9491
- console.error(chalk13.red(`
9930
+ console.error(chalk14.red(`
9492
9931
  \u274C Invalid provider: ${options.provider}`));
9493
- console.log(chalk13.dim(`Valid options: ${validProviders.join(", ")}`));
9932
+ console.log(chalk14.dim(`Valid options: ${validProviders.join(", ")}`));
9494
9933
  bail(`Invalid provider: ${options.provider}`);
9495
9934
  }
9496
9935
  spinner.text = "Loading design system configuration...";
9497
9936
  const config2 = await loadConfig(configPath);
9498
9937
  if (config2.coherentVersion && config2.coherentVersion !== CLI_VERSION2) {
9499
9938
  spinner.stop();
9500
- console.log(chalk13.yellow("\n\u26A0\uFE0F Version mismatch detected\n"));
9501
- console.log(chalk13.gray(" Project created with: ") + chalk13.white(`v${config2.coherentVersion}`));
9502
- console.log(chalk13.gray(" Current CLI version: ") + chalk13.white(`v${CLI_VERSION2}`));
9503
- console.log(chalk13.cyan("\n \u{1F4A1} Run `coherent update` to apply latest changes to your project.\n"));
9504
- console.log(chalk13.dim(" Continuing anyway...\n"));
9939
+ console.log(chalk14.yellow("\n\u26A0\uFE0F Version mismatch detected\n"));
9940
+ console.log(chalk14.gray(" Project created with: ") + chalk14.white(`v${config2.coherentVersion}`));
9941
+ console.log(chalk14.gray(" Current CLI version: ") + chalk14.white(`v${CLI_VERSION2}`));
9942
+ console.log(chalk14.cyan("\n \u{1F4A1} Run `coherent update` to apply latest changes to your project.\n"));
9943
+ console.log(chalk14.dim(" Continuing anyway...\n"));
9505
9944
  spinner.start("Loading design system configuration...");
9506
9945
  }
9507
9946
  if (needsGlobalsFix(projectRoot)) {
@@ -9528,9 +9967,9 @@ async function chatCommand(message, options) {
9528
9967
  const done = await setDefaultDarkTheme(projectRoot);
9529
9968
  spinner.stop();
9530
9969
  if (done) {
9531
- console.log(chalk13.green("\n\u2705 Default theme set to dark. Reload the app to see changes.\n"));
9970
+ console.log(chalk14.green("\n\u2705 Default theme set to dark. Reload the app to see changes.\n"));
9532
9971
  } else {
9533
- console.log(chalk13.yellow("\n\u26A0\uFE0F Could not update layout (app/layout.tsx not found).\n"));
9972
+ console.log(chalk14.yellow("\n\u26A0\uFE0F Could not update layout (app/layout.tsx not found).\n"));
9534
9973
  }
9535
9974
  return;
9536
9975
  }
@@ -9546,10 +9985,10 @@ async function chatCommand(message, options) {
9546
9985
  dsm.updateConfig(cfg);
9547
9986
  dsm.save();
9548
9987
  spinner.stop();
9549
- console.log(chalk13.green("\n\u2705 Default theme set to light. Reload the app to see changes.\n"));
9988
+ console.log(chalk14.green("\n\u2705 Default theme set to light. Reload the app to see changes.\n"));
9550
9989
  } catch {
9551
9990
  spinner.stop();
9552
- console.log(chalk13.yellow("\n\u26A0\uFE0F Could not update layout (app/layout.tsx not found).\n"));
9991
+ console.log(chalk14.yellow("\n\u26A0\uFE0F Could not update layout (app/layout.tsx not found).\n"));
9553
9992
  }
9554
9993
  return;
9555
9994
  }
@@ -9559,7 +9998,7 @@ async function chatCommand(message, options) {
9559
9998
  const { created, id } = await ensureThemeToggle(projectRoot);
9560
9999
  spinner.stop();
9561
10000
  console.log(
9562
- chalk13.green(
10001
+ chalk14.green(
9563
10002
  `
9564
10003
  \u2705 ${created ? `Created ${id} (ThemeToggle) and added to layout` : "ThemeToggle already present; layout updated"}.
9565
10004
  `
@@ -9567,7 +10006,7 @@ async function chatCommand(message, options) {
9567
10006
  );
9568
10007
  } catch (e) {
9569
10008
  spinner.fail("Failed to add theme toggle");
9570
- if (e instanceof Error) console.error(chalk13.red("\n\u274C " + e.message + "\n"));
10009
+ if (e instanceof Error) console.error(chalk14.red("\n\u274C " + e.message + "\n"));
9571
10010
  }
9572
10011
  return;
9573
10012
  }
@@ -9583,12 +10022,12 @@ async function chatCommand(message, options) {
9583
10022
  manifest = { ...manifest, shared: validShared };
9584
10023
  await saveManifest2(project.root, manifest);
9585
10024
  if (DEBUG4) {
9586
- console.log(chalk13.dim(`[pre-gen] Cleaned ${cleaned} orphaned component(s) from manifest`));
10025
+ console.log(chalk14.dim(`[pre-gen] Cleaned ${cleaned} orphaned component(s) from manifest`));
9587
10026
  }
9588
10027
  }
9589
10028
  const sharedComponentsSummary = buildSharedComponentsSummary(manifest);
9590
10029
  if (DEBUG4 && sharedComponentsSummary) {
9591
- console.log(chalk13.dim("[add-page] sharedComponentsSummary in prompt:\n" + sharedComponentsSummary));
10030
+ console.log(chalk14.dim("[add-page] sharedComponentsSummary in prompt:\n" + sharedComponentsSummary));
9592
10031
  }
9593
10032
  let requests;
9594
10033
  let uxRecommendations;
@@ -9600,7 +10039,12 @@ async function chatCommand(message, options) {
9600
10039
  ) || []).length >= SPLIT_THRESHOLD;
9601
10040
  if (multiPageHint) {
9602
10041
  try {
9603
- requests = await splitGeneratePages(spinner, message, modCtx, provider, parseOpts);
10042
+ const splitResult = await splitGeneratePages(spinner, message, modCtx, provider, parseOpts);
10043
+ requests = splitResult.requests;
10044
+ if (splitResult.plan && projectRoot) {
10045
+ savePlan(projectRoot, splitResult.plan);
10046
+ await ensurePlanGroupLayouts(projectRoot, splitResult.plan);
10047
+ }
9604
10048
  uxRecommendations = void 0;
9605
10049
  } catch {
9606
10050
  spinner.warn("Split generation encountered an issue \u2014 trying page-by-page...");
@@ -9673,7 +10117,12 @@ async function chatCommand(message, options) {
9673
10117
  if (isTruncated || isJsonError) {
9674
10118
  spinner.warn("Response too large \u2014 splitting into smaller requests...");
9675
10119
  try {
9676
- requests = await splitGeneratePages(spinner, message, modCtx, provider, parseOpts);
10120
+ const splitResult = await splitGeneratePages(spinner, message, modCtx, provider, parseOpts);
10121
+ requests = splitResult.requests;
10122
+ if (splitResult.plan && projectRoot) {
10123
+ savePlan(projectRoot, splitResult.plan);
10124
+ await ensurePlanGroupLayouts(projectRoot, splitResult.plan);
10125
+ }
9677
10126
  uxRecommendations = void 0;
9678
10127
  } catch {
9679
10128
  throw firstError;
@@ -9685,10 +10134,10 @@ async function chatCommand(message, options) {
9685
10134
  }
9686
10135
  if (requests.length === 0) {
9687
10136
  spinner.fail("No modifications found in your request");
9688
- console.log(chalk13.yellow("\n\u{1F4A1} Try being more specific, e.g.:"));
9689
- console.log(chalk13.dim(' - "make buttons blue"'));
9690
- console.log(chalk13.dim(' - "add a pricing page"'));
9691
- console.log(chalk13.dim(' - "change primary color to green"'));
10137
+ console.log(chalk14.yellow("\n\u{1F4A1} Try being more specific, e.g.:"));
10138
+ console.log(chalk14.dim(' - "make buttons blue"'));
10139
+ console.log(chalk14.dim(' - "add a pricing page"'));
10140
+ console.log(chalk14.dim(' - "change primary color to green"'));
9692
10141
  return;
9693
10142
  }
9694
10143
  spinner.succeed(`Parsed ${requests.length} modification(s)`);
@@ -9696,11 +10145,11 @@ async function chatCommand(message, options) {
9696
10145
  normalizedRequests = normalizedRequests.map((req) => {
9697
10146
  const result = normalizeRequest(req, dsm.getConfig());
9698
10147
  if ("error" in result) {
9699
- console.log(chalk13.yellow(` \u26A0 Skipped: ${result.error}`));
10148
+ console.log(chalk14.yellow(` \u26A0 Skipped: ${result.error}`));
9700
10149
  return null;
9701
10150
  }
9702
10151
  if (result.type !== req.type) {
9703
- console.log(chalk13.dim(` \u2139 Adjusted: ${req.type} \u2192 ${result.type} (target: ${req.target})`));
10152
+ console.log(chalk14.dim(` \u2139 Adjusted: ${req.type} \u2192 ${result.type} (target: ${req.target})`));
9704
10153
  }
9705
10154
  return result;
9706
10155
  }).filter((r) => r !== null);
@@ -9756,13 +10205,13 @@ async function chatCommand(message, options) {
9756
10205
  }
9757
10206
  }
9758
10207
  if (DEBUG4) {
9759
- console.log(chalk13.gray(`
10208
+ console.log(chalk14.gray(`
9760
10209
  [DEBUG] Pre-flight analysis for page "${page.name || page.route}": `));
9761
- console.log(chalk13.gray(` Page sections: ${page.sections?.length || 0}`));
10210
+ console.log(chalk14.gray(` Page sections: ${page.sections?.length || 0}`));
9762
10211
  if (page.sections?.[0]?.props?.fields) {
9763
- console.log(chalk13.gray(` First section has ${page.sections[0].props.fields.length} fields`));
10212
+ console.log(chalk14.gray(` First section has ${page.sections[0].props.fields.length} fields`));
9764
10213
  page.sections[0].props.fields.forEach((f, i) => {
9765
- console.log(chalk13.gray(` Field ${i}: component=${f.component}`));
10214
+ console.log(chalk14.gray(` Field ${i}: component=${f.component}`));
9766
10215
  });
9767
10216
  }
9768
10217
  }
@@ -9772,7 +10221,7 @@ async function chatCommand(message, options) {
9772
10221
  try {
9773
10222
  const sharedPath = resolve9(projectRoot, entry.file);
9774
10223
  if (existsSync16(sharedPath)) {
9775
- const sharedCode = readFileSync10(sharedPath, "utf-8");
10224
+ const sharedCode = readFileSync11(sharedPath, "utf-8");
9776
10225
  const sharedImports = sharedCode.matchAll(/@\/components\/ui\/([a-z0-9-]+)/g);
9777
10226
  for (const m of sharedImports) {
9778
10227
  if (m[1]) allNeededComponentIds.add(m[1]);
@@ -9785,8 +10234,8 @@ async function chatCommand(message, options) {
9785
10234
  const INVALID_COMPONENT_IDS = /* @__PURE__ */ new Set(["ui", "shared", "lib", "utils", "hooks", "app", "components"]);
9786
10235
  for (const id of INVALID_COMPONENT_IDS) allNeededComponentIds.delete(id);
9787
10236
  if (DEBUG4) {
9788
- console.log(chalk13.gray("\n[DEBUG] Pre-flight analysis (consolidated):"));
9789
- console.log(chalk13.gray(` All needed components: ${Array.from(allNeededComponentIds).join(", ")}`));
10237
+ console.log(chalk14.gray("\n[DEBUG] Pre-flight analysis (consolidated):"));
10238
+ console.log(chalk14.gray(` All needed components: ${Array.from(allNeededComponentIds).join(", ")}`));
9790
10239
  console.log("");
9791
10240
  }
9792
10241
  const missingComponents = [];
@@ -9794,56 +10243,59 @@ async function chatCommand(message, options) {
9794
10243
  const isRegistered = !!cm.read(componentId);
9795
10244
  const filePath = join11(projectRoot, "components", "ui", `${componentId}.tsx`);
9796
10245
  const fileExists = existsSync16(filePath);
9797
- if (DEBUG4) console.log(chalk13.gray(` Checking ${componentId}: registered=${isRegistered} file=${fileExists}`));
10246
+ if (DEBUG4) console.log(chalk14.gray(` Checking ${componentId}: registered=${isRegistered} file=${fileExists}`));
9798
10247
  if (!isRegistered || !fileExists) {
9799
10248
  missingComponents.push(componentId);
9800
10249
  }
9801
10250
  }
9802
10251
  if (missingComponents.length > 0) {
9803
10252
  spinner.stop();
9804
- console.log(chalk13.cyan("\n\u{1F50D} Pre-flight check: Installing missing components...\n"));
10253
+ console.log(chalk14.cyan("\n\u{1F50D} Pre-flight check: Installing missing components...\n"));
9805
10254
  const provider2 = getComponentProvider();
9806
10255
  for (const componentId of missingComponents) {
9807
10256
  if (DEBUG4) {
9808
- console.log(chalk13.gray(` [DEBUG] Trying to install: ${componentId}`));
9809
- console.log(chalk13.gray(` [DEBUG] provider.has(${componentId}): ${provider2.has(componentId)}`));
10257
+ console.log(chalk14.gray(` [DEBUG] Trying to install: ${componentId}`));
10258
+ console.log(chalk14.gray(` [DEBUG] provider.has(${componentId}): ${provider2.has(componentId)}`));
9810
10259
  }
9811
10260
  if (provider2.has(componentId)) {
9812
10261
  try {
9813
10262
  const result = await provider2.installComponent(componentId, projectRoot);
9814
- if (DEBUG4) console.log(chalk13.gray(` [DEBUG] installComponent result: ${result.success}`));
10263
+ if (DEBUG4) console.log(chalk14.gray(` [DEBUG] installComponent result: ${result.success}`));
9815
10264
  if (result.success && result.componentDef) {
9816
10265
  if (!cm.read(componentId)) {
9817
- if (DEBUG4) console.log(chalk13.gray(` [DEBUG] Registering ${result.componentDef.id} (${result.componentDef.name})`));
10266
+ if (DEBUG4)
10267
+ console.log(
10268
+ chalk14.gray(` [DEBUG] Registering ${result.componentDef.id} (${result.componentDef.name})`)
10269
+ );
9818
10270
  const regResult = await cm.register(result.componentDef);
9819
10271
  if (DEBUG4) {
9820
10272
  console.log(
9821
- chalk13.gray(
10273
+ chalk14.gray(
9822
10274
  ` [DEBUG] Register result: ${regResult.success ? "SUCCESS" : "FAILED"}${!regResult.success && regResult.message ? ` - ${regResult.message}` : ""}`
9823
10275
  )
9824
10276
  );
9825
10277
  }
9826
10278
  if (regResult.success) {
9827
10279
  preflightInstalledIds.push(result.componentDef.id);
9828
- console.log(chalk13.green(` \u2728 Auto-installed ${result.componentDef.name} component`));
10280
+ console.log(chalk14.green(` \u2728 Auto-installed ${result.componentDef.name} component`));
9829
10281
  dsm.updateConfig(regResult.config);
9830
10282
  cm.updateConfig(regResult.config);
9831
10283
  pm.updateConfig(regResult.config);
9832
10284
  }
9833
10285
  } else {
9834
10286
  preflightInstalledIds.push(result.componentDef.id);
9835
- console.log(chalk13.green(` \u2728 Re-installed ${result.componentDef.name} component (file was missing)`));
10287
+ console.log(chalk14.green(` \u2728 Re-installed ${result.componentDef.name} component (file was missing)`));
9836
10288
  }
9837
10289
  }
9838
10290
  } catch (error) {
9839
- console.log(chalk13.red(` \u274C Failed to install ${componentId}:`));
9840
- console.log(chalk13.red(` ${error instanceof Error ? error.message : error}`));
10291
+ console.log(chalk14.red(` \u274C Failed to install ${componentId}:`));
10292
+ console.log(chalk14.red(` ${error instanceof Error ? error.message : error}`));
9841
10293
  if (error instanceof Error && error.stack) {
9842
- console.log(chalk13.gray(` ${error.stack.split("\n")[1]}`));
10294
+ console.log(chalk14.gray(` ${error.stack.split("\n")[1]}`));
9843
10295
  }
9844
10296
  }
9845
10297
  } else {
9846
- console.log(chalk13.yellow(` \u26A0\uFE0F Component ${componentId} not available`));
10298
+ console.log(chalk14.yellow(` \u26A0\uFE0F Component ${componentId} not available`));
9847
10299
  }
9848
10300
  }
9849
10301
  console.log("");
@@ -9854,11 +10306,11 @@ async function chatCommand(message, options) {
9854
10306
  const toInstallNpm = [...neededPkgs].filter((p) => !installedPkgs.has(p));
9855
10307
  if (toInstallNpm.length > 0) {
9856
10308
  spinner.stop();
9857
- console.log(chalk13.cyan(`
10309
+ console.log(chalk14.cyan(`
9858
10310
  \u{1F4E6} Auto-installing missing dependencies: ${toInstallNpm.join(", ")}
9859
10311
  `));
9860
10312
  const ok = await installPackages(projectRoot, toInstallNpm);
9861
- if (!ok) console.log(chalk13.yellow(` Run manually: npm install ${toInstallNpm.join(" ")}
10313
+ if (!ok) console.log(chalk14.yellow(` Run manually: npm install ${toInstallNpm.join(" ")}
9862
10314
  `));
9863
10315
  spinner.start("Applying modifications...");
9864
10316
  }
@@ -9869,7 +10321,7 @@ async function chatCommand(message, options) {
9869
10321
  if (componentId && preflightComponentIds.has(componentId)) {
9870
10322
  if (DEBUG4) {
9871
10323
  console.log(
9872
- chalk13.gray(`[DEBUG] Filtered duplicate add-component: ${componentId} (already installed in pre-flight)`)
10324
+ chalk14.gray(`[DEBUG] Filtered duplicate add-component: ${componentId} (already installed in pre-flight)`)
9873
10325
  );
9874
10326
  }
9875
10327
  return false;
@@ -9878,11 +10330,11 @@ async function chatCommand(message, options) {
9878
10330
  return true;
9879
10331
  });
9880
10332
  if (DEBUG4 && preflightComponentIds.size > 0) {
9881
- console.log(chalk13.gray(`[DEBUG] Remaining requests after filtering: ${normalizedRequests.length}`));
10333
+ console.log(chalk14.gray(`[DEBUG] Remaining requests after filtering: ${normalizedRequests.length}`));
9882
10334
  }
9883
10335
  try {
9884
10336
  createBackup(projectRoot);
9885
- if (DEBUG4) console.log(chalk13.dim("[backup] Created snapshot"));
10337
+ if (DEBUG4) console.log(chalk14.dim("[backup] Created snapshot"));
9886
10338
  } catch {
9887
10339
  }
9888
10340
  const navBefore = takeNavSnapshot(
@@ -9894,6 +10346,17 @@ async function chatCommand(message, options) {
9894
10346
  const result = await applyModification(request, dsm, cm, pm, projectRoot, provider, message);
9895
10347
  results.push(result);
9896
10348
  }
10349
+ for (const request of normalizedRequests) {
10350
+ const changes = request.changes;
10351
+ if ((request.type === "add-page" || request.type === "update-page") && changes?.route === "/" && changes?.pageCode) {
10352
+ const cfg = dsm.getConfig();
10353
+ if (cfg.settings.homePagePlaceholder) {
10354
+ cfg.settings.homePagePlaceholder = false;
10355
+ dsm.updateConfig(cfg);
10356
+ }
10357
+ break;
10358
+ }
10359
+ }
9897
10360
  const currentConfig = dsm.getConfig();
9898
10361
  const autoScaffoldEnabled = currentConfig.settings.autoScaffold === true;
9899
10362
  const scaffoldedPages = [];
@@ -9907,7 +10370,7 @@ async function chatCommand(message, options) {
9907
10370
  let pageCode = "";
9908
10371
  if (existsSync16(pageFilePath)) {
9909
10372
  try {
9910
- pageCode = readFileSync10(pageFilePath, "utf-8");
10373
+ pageCode = readFileSync11(pageFilePath, "utf-8");
9911
10374
  } catch {
9912
10375
  }
9913
10376
  }
@@ -9926,10 +10389,10 @@ async function chatCommand(message, options) {
9926
10389
  const SCAFFOLD_AI_LIMIT = 10;
9927
10390
  if (missingRoutes.length > 0 && missingRoutes.length <= SCAFFOLD_AI_LIMIT) {
9928
10391
  spinner.stop();
9929
- console.log(chalk13.cyan(`
10392
+ console.log(chalk14.cyan(`
9930
10393
  \u{1F517} Auto-scaffolding ${missingRoutes.length} linked page(s)...`));
9931
10394
  console.log(
9932
- chalk13.dim(
10395
+ chalk14.dim(
9933
10396
  ` (${missingRoutes.length} additional AI call(s) \u2014 disable with settings.autoScaffold: false in config)
9934
10397
  `
9935
10398
  )
@@ -9966,7 +10429,7 @@ async function chatCommand(message, options) {
9966
10429
  }
9967
10430
  } catch (err) {
9968
10431
  scaffoldSpinner.warn(` Could not scaffold "${pageName}" (${linkedRoute}) \u2014 skipped`);
9969
- if (DEBUG4) console.log(chalk13.dim(` ${err instanceof Error ? err.message : "unknown error"}`));
10432
+ if (DEBUG4) console.log(chalk14.dim(` ${err instanceof Error ? err.message : "unknown error"}`));
9970
10433
  }
9971
10434
  }
9972
10435
  console.log("");
@@ -9974,7 +10437,7 @@ async function chatCommand(message, options) {
9974
10437
  } else if (missingRoutes.length > SCAFFOLD_AI_LIMIT) {
9975
10438
  spinner.stop();
9976
10439
  console.log(
9977
- chalk13.yellow(
10440
+ chalk14.yellow(
9978
10441
  `
9979
10442
  \u26A0 Found ${missingRoutes.length} linked pages \u2014 creating placeholder pages (too many for AI generation).`
9980
10443
  )
@@ -10003,7 +10466,7 @@ async function chatCommand(message, options) {
10003
10466
  scaffoldedPages.push({ route: linkedRoute, name: `${pageName} (placeholder)` });
10004
10467
  }
10005
10468
  console.log(
10006
- chalk13.cyan(` Created ${missingRoutes.length} placeholder pages. Use \`coherent chat\` to fill them.
10469
+ chalk14.cyan(` Created ${missingRoutes.length} placeholder pages. Use \`coherent chat\` to fill them.
10007
10470
  `)
10008
10471
  );
10009
10472
  spinner.start("Finalizing...");
@@ -10018,7 +10481,7 @@ async function chatCommand(message, options) {
10018
10481
  for (const mod of result.modified) {
10019
10482
  if (mod.startsWith("app/") && mod.endsWith("/page.tsx")) {
10020
10483
  try {
10021
- const code = readFileSync10(resolve9(projectRoot, mod), "utf-8");
10484
+ const code = readFileSync11(resolve9(projectRoot, mod), "utf-8");
10022
10485
  const issues = validatePageQuality(code, allRoutes).filter(
10023
10486
  (i) => i.type === "BROKEN_INTERNAL_LINK"
10024
10487
  );
@@ -10031,9 +10494,9 @@ async function chatCommand(message, options) {
10031
10494
  }
10032
10495
  }
10033
10496
  if (linkIssues.length > 0) {
10034
- console.log(chalk13.yellow("\n\u{1F517} Broken internal links:"));
10497
+ console.log(chalk14.yellow("\n\u{1F517} Broken internal links:"));
10035
10498
  for (const { page, message: message2 } of linkIssues) {
10036
- console.log(chalk13.dim(` ${page}: ${message2}`));
10499
+ console.log(chalk14.dim(` ${page}: ${message2}`));
10037
10500
  }
10038
10501
  }
10039
10502
  }
@@ -10046,7 +10509,7 @@ async function chatCommand(message, options) {
10046
10509
  if (latestConfig.theme.defaultMode !== targetMode) {
10047
10510
  latestConfig.theme.defaultMode = targetMode;
10048
10511
  dsm.updateConfig(latestConfig);
10049
- if (DEBUG4) console.log(chalk13.dim(` [theme] Set defaultMode to "${targetMode}"`));
10512
+ if (DEBUG4) console.log(chalk14.dim(` [theme] Set defaultMode to "${targetMode}"`));
10050
10513
  }
10051
10514
  const layoutPath = resolve9(projectRoot, "app", "layout.tsx");
10052
10515
  try {
@@ -10054,11 +10517,11 @@ async function chatCommand(message, options) {
10054
10517
  if (targetMode === "dark" && !layoutCode.includes('className="dark"')) {
10055
10518
  layoutCode = layoutCode.replace(/<html\s+lang="en"/, '<html lang="en" className="dark"');
10056
10519
  await writeFile(layoutPath, layoutCode);
10057
- console.log(chalk13.dim(` \u{1F319} Applied dark theme to layout`));
10520
+ console.log(chalk14.dim(` \u{1F319} Applied dark theme to layout`));
10058
10521
  } else if (targetMode === "light" && layoutCode.includes('className="dark"')) {
10059
10522
  layoutCode = layoutCode.replace(' className="dark"', "");
10060
10523
  await writeFile(layoutPath, layoutCode);
10061
- console.log(chalk13.dim(` \u2600\uFE0F Applied light theme to layout`));
10524
+ console.log(chalk14.dim(` \u2600\uFE0F Applied light theme to layout`));
10062
10525
  }
10063
10526
  } catch {
10064
10527
  }
@@ -10088,6 +10551,10 @@ async function chatCommand(message, options) {
10088
10551
  await regenerateFiles(Array.from(allModified), updatedConfig, projectRoot, { navChanged, storedHashes });
10089
10552
  spinner.succeed("Files regenerated");
10090
10553
  }
10554
+ const finalDeps = await scanAndInstallSharedDeps(projectRoot);
10555
+ if (finalDeps.length > 0) {
10556
+ console.log(chalk14.dim(` Auto-installed shared deps: ${finalDeps.join(", ")}`));
10557
+ }
10091
10558
  try {
10092
10559
  fixGlobalsCss(projectRoot, updatedConfig);
10093
10560
  } catch {
@@ -10098,7 +10565,7 @@ async function chatCommand(message, options) {
10098
10565
  const layoutFile = resolve9(projectRoot, "app", "layout.tsx");
10099
10566
  const filesToHash = [layoutFile];
10100
10567
  if (existsSync16(sharedDir)) {
10101
- for (const f of readdirSync2(sharedDir)) {
10568
+ for (const f of readdirSync3(sharedDir)) {
10102
10569
  if (f.endsWith(".tsx")) filesToHash.push(resolve9(sharedDir, f));
10103
10570
  }
10104
10571
  }
@@ -10110,7 +10577,7 @@ async function chatCommand(message, options) {
10110
10577
  }
10111
10578
  await saveHashes(projectRoot, updatedHashes);
10112
10579
  } catch {
10113
- if (DEBUG4) console.log(chalk13.dim("[hashes] Could not save file hashes"));
10580
+ if (DEBUG4) console.log(chalk14.dim("[hashes] Could not save file hashes"));
10114
10581
  }
10115
10582
  const successfulPairs = normalizedRequests.map((request, index) => ({ request, result: results[index] })).filter(({ result }) => result.success);
10116
10583
  if (successfulPairs.length > 0) {
@@ -10127,9 +10594,9 @@ async function chatCommand(message, options) {
10127
10594
  const preflightNames = preflightInstalledIds.map((id) => updatedConfig.components.find((c) => c.id === id)?.name).filter(Boolean);
10128
10595
  showPreview(normalizedRequests, results, updatedConfig, preflightNames);
10129
10596
  if (scaffoldedPages.length > 0) {
10130
- console.log(chalk13.cyan("\u{1F517} Auto-scaffolded linked pages:"));
10597
+ console.log(chalk14.cyan("\u{1F517} Auto-scaffolded linked pages:"));
10131
10598
  scaffoldedPages.forEach(({ route, name }) => {
10132
- console.log(chalk13.white(` \u2728 ${name} \u2192 ${route}`));
10599
+ console.log(chalk14.white(` \u2728 ${name} \u2192 ${route}`));
10133
10600
  });
10134
10601
  console.log("");
10135
10602
  }
@@ -10151,58 +10618,58 @@ ${uxRecommendations}
10151
10618
  );
10152
10619
  }
10153
10620
  await appendFile(recPath, section);
10154
- console.log(chalk13.cyan("\n\u{1F4CB} UX Recommendations:"));
10621
+ console.log(chalk14.cyan("\n\u{1F4CB} UX Recommendations:"));
10155
10622
  for (const line of uxRecommendations.split("\n").filter(Boolean)) {
10156
- console.log(chalk13.dim(` ${line}`));
10623
+ console.log(chalk14.dim(` ${line}`));
10157
10624
  }
10158
- console.log(chalk13.dim(" \u2192 Saved to /design-system/docs/recommendations"));
10625
+ console.log(chalk14.dim(" \u2192 Saved to /design-system/docs/recommendations"));
10159
10626
  } catch (e) {
10160
10627
  console.log(
10161
- chalk13.yellow("\n\u26A0\uFE0F Could not write recommendations.md: " + (e instanceof Error ? e.message : String(e)))
10628
+ chalk14.yellow("\n\u26A0\uFE0F Could not write recommendations.md: " + (e instanceof Error ? e.message : String(e)))
10162
10629
  );
10163
- console.log(chalk13.dim("Recommendations:\n") + uxRecommendations);
10630
+ console.log(chalk14.dim("Recommendations:\n") + uxRecommendations);
10164
10631
  }
10165
10632
  }
10166
10633
  } catch (error) {
10167
10634
  spinner.fail("Chat command failed");
10168
- console.error(chalk13.red("\n\u2716 Chat command failed"));
10635
+ console.error(chalk14.red("\n\u2716 Chat command failed"));
10169
10636
  const zodError = error;
10170
10637
  const issues = zodError.issues || error.errors;
10171
10638
  if (issues && Array.isArray(issues)) {
10172
- console.log(chalk13.yellow("\n\u26A0\uFE0F AI generated incomplete data. Missing or invalid fields:"));
10639
+ console.log(chalk14.yellow("\n\u26A0\uFE0F AI generated incomplete data. Missing or invalid fields:"));
10173
10640
  issues.forEach((err) => {
10174
- console.log(chalk13.gray(` \u2022 ${err.path.join(".")}: ${err.message}`));
10641
+ console.log(chalk14.gray(` \u2022 ${err.path.join(".")}: ${err.message}`));
10175
10642
  });
10176
- console.log(chalk13.cyan("\n\u{1F4A1} Try being more specific, e.g.:"));
10177
- console.log(chalk13.white(' coherent chat "add a dashboard page with hero section using Button component"'));
10178
- console.log(chalk13.white(' coherent chat "add pricing page"'));
10643
+ console.log(chalk14.cyan("\n\u{1F4A1} Try being more specific, e.g.:"));
10644
+ console.log(chalk14.white(' coherent chat "add a dashboard page with hero section using Button component"'));
10645
+ console.log(chalk14.white(' coherent chat "add pricing page"'));
10179
10646
  } else if (error instanceof Error) {
10180
- console.error(chalk13.red(error.message));
10647
+ console.error(chalk14.red(error.message));
10181
10648
  if (error.message.includes("Unterminated string") || error.message.includes("Unexpected end of JSON") || error.message.includes("Failed to parse modification") && error.message.includes("JSON")) {
10182
10649
  console.log(
10183
- chalk13.yellow("\n\u{1F4A1} The AI response was too large or contained invalid JSON. Try splitting your request:")
10650
+ chalk14.yellow("\n\u{1F4A1} The AI response was too large or contained invalid JSON. Try splitting your request:")
10184
10651
  );
10185
- console.log(chalk13.white(' coherent chat "add dashboard page with stats and recent activity"'));
10186
- console.log(chalk13.white(' coherent chat "add account page"'));
10187
- console.log(chalk13.white(' coherent chat "add settings page"'));
10652
+ console.log(chalk14.white(' coherent chat "add dashboard page with stats and recent activity"'));
10653
+ console.log(chalk14.white(' coherent chat "add account page"'));
10654
+ console.log(chalk14.white(' coherent chat "add settings page"'));
10188
10655
  } else if (error.message.includes("API key not found") || error.message.includes("ANTHROPIC_API_KEY") || error.message.includes("OPENAI_API_KEY")) {
10189
10656
  const isOpenAI = error.message.includes("OpenAI") || typeof provider !== "undefined" && provider === "openai";
10190
10657
  const providerName = isOpenAI ? "OpenAI" : "Anthropic Claude";
10191
10658
  const envVar = isOpenAI ? "OPENAI_API_KEY" : "ANTHROPIC_API_KEY";
10192
10659
  const url = isOpenAI ? "https://platform.openai.com" : "https://console.anthropic.com";
10193
- console.log(chalk13.yellow("\n\u{1F4A1} Setup Instructions:"));
10194
- console.log(chalk13.dim(` 1. Get your ${providerName} API key from: ${url}`));
10195
- console.log(chalk13.dim(" 2. Create a .env file in the current directory:"));
10196
- console.log(chalk13.cyan(` echo "${envVar}=your_key_here" > .env`));
10197
- console.log(chalk13.dim(" 3. Or export it in your shell:"));
10198
- console.log(chalk13.cyan(` export ${envVar}=your_key_here`));
10660
+ console.log(chalk14.yellow("\n\u{1F4A1} Setup Instructions:"));
10661
+ console.log(chalk14.dim(` 1. Get your ${providerName} API key from: ${url}`));
10662
+ console.log(chalk14.dim(" 2. Create a .env file in the current directory:"));
10663
+ console.log(chalk14.cyan(` echo "${envVar}=your_key_here" > .env`));
10664
+ console.log(chalk14.dim(" 3. Or export it in your shell:"));
10665
+ console.log(chalk14.cyan(` export ${envVar}=your_key_here`));
10199
10666
  if (isOpenAI) {
10200
- console.log(chalk13.dim('\n Also ensure "openai" package is installed:'));
10201
- console.log(chalk13.cyan(" npm install openai"));
10667
+ console.log(chalk14.dim('\n Also ensure "openai" package is installed:'));
10668
+ console.log(chalk14.cyan(" npm install openai"));
10202
10669
  }
10203
10670
  }
10204
10671
  } else {
10205
- console.error(chalk13.red("Unknown error occurred"));
10672
+ console.error(chalk14.red("Unknown error occurred"));
10206
10673
  }
10207
10674
  console.log("");
10208
10675
  if (options._throwOnError) {
@@ -10215,21 +10682,21 @@ ${uxRecommendations}
10215
10682
  }
10216
10683
 
10217
10684
  // src/commands/preview.ts
10218
- import chalk14 from "chalk";
10685
+ import chalk15 from "chalk";
10219
10686
  import ora3 from "ora";
10220
10687
  import { spawn } from "child_process";
10221
- import { existsSync as existsSync19, rmSync as rmSync3, readFileSync as readFileSync13, writeFileSync as writeFileSync10 } from "fs";
10688
+ import { existsSync as existsSync19, rmSync as rmSync3, readFileSync as readFileSync14, writeFileSync as writeFileSync10, readdirSync as readdirSync5 } from "fs";
10222
10689
  import { resolve as resolve10, join as join14 } from "path";
10223
10690
  import { readdir as readdir2 } from "fs/promises";
10224
10691
  import { DesignSystemManager as DesignSystemManager8, ComponentGenerator as ComponentGenerator3 } from "@getcoherent/core";
10225
10692
 
10226
10693
  // src/utils/file-watcher.ts
10227
- import { readFileSync as readFileSync12, writeFileSync as writeFileSync9, existsSync as existsSync18 } from "fs";
10694
+ import { readFileSync as readFileSync13, writeFileSync as writeFileSync9, existsSync as existsSync18 } from "fs";
10228
10695
  import { relative as relative4, join as join13 } from "path";
10229
10696
  import { loadManifest as loadManifest9, saveManifest as saveManifest3 } from "@getcoherent/core";
10230
10697
 
10231
10698
  // src/utils/component-integrity.ts
10232
- import { existsSync as existsSync17, readFileSync as readFileSync11, readdirSync as readdirSync3 } from "fs";
10699
+ import { existsSync as existsSync17, readFileSync as readFileSync12, readdirSync as readdirSync4 } from "fs";
10233
10700
  import { join as join12, relative as relative3 } from "path";
10234
10701
  function extractExportedComponentNames(code) {
10235
10702
  const names = [];
@@ -10263,7 +10730,7 @@ function findPagesImporting(projectRoot, componentName, componentFile) {
10263
10730
  for (const absPath of pageFiles) {
10264
10731
  if (absPath.includes("design-system")) continue;
10265
10732
  try {
10266
- const code = readFileSync11(absPath, "utf-8");
10733
+ const code = readFileSync12(absPath, "utf-8");
10267
10734
  const hasNamedImport = new RegExp(`import\\s+\\{[^}]*\\b${componentName}\\b[^}]*\\}\\s+from\\s+['"]`).test(code);
10268
10735
  const hasDefaultImport = new RegExp(`import\\s+${componentName}\\s+from\\s+['"]`).test(code);
10269
10736
  const hasPathImport = code.includes(`@/${componentImportPath}`);
@@ -10279,7 +10746,7 @@ function isUsedInLayout(projectRoot, componentName) {
10279
10746
  const layoutPath = join12(projectRoot, "app", "layout.tsx");
10280
10747
  if (!existsSync17(layoutPath)) return false;
10281
10748
  try {
10282
- const code = readFileSync11(layoutPath, "utf-8");
10749
+ const code = readFileSync12(layoutPath, "utf-8");
10283
10750
  return code.includes(componentName);
10284
10751
  } catch {
10285
10752
  return false;
@@ -10300,7 +10767,7 @@ function findUnregisteredComponents(projectRoot, manifest) {
10300
10767
  const relFile = relative3(projectRoot, absPath);
10301
10768
  if (registeredFiles.has(relFile)) continue;
10302
10769
  try {
10303
- const code = readFileSync11(absPath, "utf-8");
10770
+ const code = readFileSync12(absPath, "utf-8");
10304
10771
  const exports = extractExportedComponentNames(code);
10305
10772
  for (const name of exports) {
10306
10773
  if (registeredNames.has(name)) continue;
@@ -10322,7 +10789,7 @@ function findInlineDuplicates(projectRoot, manifest) {
10322
10789
  if (absPath.includes("design-system")) continue;
10323
10790
  let code;
10324
10791
  try {
10325
- code = readFileSync11(absPath, "utf-8");
10792
+ code = readFileSync12(absPath, "utf-8");
10326
10793
  } catch {
10327
10794
  continue;
10328
10795
  }
@@ -10354,7 +10821,7 @@ function findComponentFileByExportName(projectRoot, componentName) {
10354
10821
  );
10355
10822
  for (const absPath of files) {
10356
10823
  try {
10357
- const code = readFileSync11(absPath, "utf-8");
10824
+ const code = readFileSync12(absPath, "utf-8");
10358
10825
  const exports = extractExportedComponentNames(code);
10359
10826
  if (exports.includes(componentName)) {
10360
10827
  return relative3(projectRoot, absPath);
@@ -10399,7 +10866,7 @@ function reconcileComponents(projectRoot, manifest) {
10399
10866
  }
10400
10867
  let code;
10401
10868
  try {
10402
- code = readFileSync11(join12(projectRoot, entry.file), "utf-8");
10869
+ code = readFileSync12(join12(projectRoot, entry.file), "utf-8");
10403
10870
  } catch {
10404
10871
  return true;
10405
10872
  }
@@ -10476,7 +10943,7 @@ function collectFiles(dir, filter, skipDirs = []) {
10476
10943
  function walk(d) {
10477
10944
  let entries;
10478
10945
  try {
10479
- entries = readdirSync3(d, { withFileTypes: true });
10946
+ entries = readdirSync4(d, { withFileTypes: true });
10480
10947
  } catch {
10481
10948
  return;
10482
10949
  }
@@ -10522,7 +10989,7 @@ function getWatcherConfig(projectRoot) {
10522
10989
  try {
10523
10990
  const pkgPath = join13(projectRoot, "package.json");
10524
10991
  if (!existsSync18(pkgPath)) return defaultWatcherConfig();
10525
- const pkg = JSON.parse(readFileSync12(pkgPath, "utf-8"));
10992
+ const pkg = JSON.parse(readFileSync13(pkgPath, "utf-8"));
10526
10993
  const c = pkg?.coherent?.watcher ?? {};
10527
10994
  return {
10528
10995
  enabled: c.enabled !== false,
@@ -10550,18 +11017,18 @@ async function handleFileChange(projectRoot, filePath) {
10550
11017
  if (relativePath.includes("node_modules") || relativePath.includes(".next")) return;
10551
11018
  let content;
10552
11019
  try {
10553
- content = readFileSync12(filePath, "utf-8");
11020
+ content = readFileSync13(filePath, "utf-8");
10554
11021
  } catch {
10555
11022
  return;
10556
11023
  }
10557
11024
  const config2 = getWatcherConfig(projectRoot);
10558
- const chalk33 = (await import("chalk")).default;
11025
+ const chalk34 = (await import("chalk")).default;
10559
11026
  if (config2.autoInstall) {
10560
11027
  const missing = findMissingPackagesInCode(content, projectRoot);
10561
11028
  if (missing.length > 0) {
10562
11029
  const ok = await installPackages(projectRoot, missing);
10563
11030
  if (ok) {
10564
- console.log(chalk33.cyan(`
11031
+ console.log(chalk34.cyan(`
10565
11032
  \u{1F527} Auto-installed: ${missing.join(", ")} (needed by ${relativePath})`));
10566
11033
  }
10567
11034
  }
@@ -10570,12 +11037,12 @@ async function handleFileChange(projectRoot, filePath) {
10570
11037
  const fixed = sanitizeMetadataStrings(ensureUseClientIfNeeded(content));
10571
11038
  if (fixed !== content) {
10572
11039
  writeFileSync9(filePath, fixed, "utf-8");
10573
- console.log(chalk33.cyan(` \u{1F527} Auto-fixed syntax in ${relativePath}`));
11040
+ console.log(chalk34.cyan(` \u{1F527} Auto-fixed syntax in ${relativePath}`));
10574
11041
  }
10575
11042
  }
10576
11043
  if (config2.warnNativeElements && hasNativeElements(content)) {
10577
- console.log(chalk33.yellow(` \u26A0 ${relativePath}: uses native HTML elements (<button>, <select>, etc.)`));
10578
- console.log(chalk33.dim(" Use components from @/components/ui/ instead"));
11044
+ console.log(chalk34.yellow(` \u26A0 ${relativePath}: uses native HTML elements (<button>, <select>, etc.)`));
11045
+ console.log(chalk34.dim(" Use components from @/components/ui/ instead"));
10579
11046
  }
10580
11047
  if (config2.warnSharedReuse) {
10581
11048
  let manifest;
@@ -10588,8 +11055,8 @@ async function handleFileChange(projectRoot, filePath) {
10588
11055
  const dupes = findInlineDuplicatesOfShared(content, manifest);
10589
11056
  for (const d of dupes) {
10590
11057
  const importPath = d.file.replace(/\.tsx$/, "").replace(/^components\/shared\//, "");
10591
- console.log(chalk33.yellow(` \u26A0 ${relativePath}: has inline code similar to ${d.cid} (${d.name})`));
10592
- console.log(chalk33.dim(` Consider: import { ${d.name} } from "@/components/shared/${importPath}"`));
11058
+ console.log(chalk34.yellow(` \u26A0 ${relativePath}: has inline code similar to ${d.cid} (${d.name})`));
11059
+ console.log(chalk34.dim(` Consider: import { ${d.name} } from "@/components/shared/${importPath}"`));
10593
11060
  }
10594
11061
  }
10595
11062
  }
@@ -10598,7 +11065,7 @@ async function handleFileDelete(projectRoot, filePath) {
10598
11065
  const relativePath = relative4(projectRoot, filePath).replace(/\\/g, "/");
10599
11066
  if (!relativePath.startsWith("components/") || relativePath.startsWith("components/ui/")) return;
10600
11067
  try {
10601
- const chalk33 = (await import("chalk")).default;
11068
+ const chalk34 = (await import("chalk")).default;
10602
11069
  const manifest = await loadManifest9(projectRoot);
10603
11070
  const orphaned = manifest.shared.find((s) => s.file === relativePath);
10604
11071
  if (orphaned) {
@@ -10607,7 +11074,7 @@ async function handleFileDelete(projectRoot, filePath) {
10607
11074
  shared: manifest.shared.filter((s) => s.id !== orphaned.id)
10608
11075
  };
10609
11076
  await saveManifest3(projectRoot, cleaned);
10610
- console.log(chalk33.cyan(`
11077
+ console.log(chalk34.cyan(`
10611
11078
  \u{1F5D1} Auto-removed ${orphaned.id} (${orphaned.name}) \u2014 file deleted`));
10612
11079
  await writeCursorRules(projectRoot);
10613
11080
  }
@@ -10619,18 +11086,18 @@ async function detectNewComponent(projectRoot, filePath) {
10619
11086
  if (!relativePath.startsWith("components/") || relativePath.startsWith("components/ui/")) return;
10620
11087
  if (!relativePath.endsWith(".tsx") && !relativePath.endsWith(".jsx")) return;
10621
11088
  try {
10622
- const chalk33 = (await import("chalk")).default;
11089
+ const chalk34 = (await import("chalk")).default;
10623
11090
  const manifest = await loadManifest9(projectRoot);
10624
11091
  const alreadyRegistered = manifest.shared.some((s) => s.file === relativePath);
10625
11092
  if (alreadyRegistered) return;
10626
- const code = readFileSync12(filePath, "utf-8");
11093
+ const code = readFileSync13(filePath, "utf-8");
10627
11094
  const exports = extractExportedComponentNames(code);
10628
11095
  if (exports.length > 0) {
10629
11096
  const alreadyByName = exports.every((n) => manifest.shared.some((s) => s.name === n));
10630
11097
  if (!alreadyByName) {
10631
- console.log(chalk33.cyan(`
11098
+ console.log(chalk34.cyan(`
10632
11099
  \u2139 New component detected: ${exports[0]} in ${relativePath}`));
10633
- console.log(chalk33.dim(" Register with: coherent sync"));
11100
+ console.log(chalk34.dim(" Register with: coherent sync"));
10634
11101
  }
10635
11102
  }
10636
11103
  } catch {
@@ -10717,17 +11184,17 @@ function clearStaleCache(projectRoot) {
10717
11184
  const nextDir = join14(projectRoot, ".next");
10718
11185
  if (existsSync19(nextDir)) {
10719
11186
  rmSync3(nextDir, { recursive: true, force: true });
10720
- console.log(chalk14.dim(" \u2714 Cleared stale build cache"));
11187
+ console.log(chalk15.dim(" \u2714 Cleared stale build cache"));
10721
11188
  }
10722
11189
  }
10723
11190
  async function preflightDependencyCheck(projectRoot) {
10724
11191
  const missing = await findMissingPackages(projectRoot);
10725
11192
  if (missing.length === 0) return;
10726
- console.log(chalk14.cyan(`
11193
+ console.log(chalk15.cyan(`
10727
11194
  Auto-installing missing dependencies: ${missing.join(", ")}`));
10728
11195
  const ok = await installPackages(projectRoot, missing);
10729
- if (ok) console.log(chalk14.dim(" \u2714 Installed"));
10730
- else console.log(chalk14.yellow(` Run manually: npm install ${missing.join(" ")}`));
11196
+ if (ok) console.log(chalk15.dim(" \u2714 Installed"));
11197
+ else console.log(chalk15.yellow(` Run manually: npm install ${missing.join(" ")}`));
10731
11198
  }
10732
11199
  async function listPageFiles(appDir) {
10733
11200
  const out = [];
@@ -10747,11 +11214,11 @@ async function validateSyntax(projectRoot) {
10747
11214
  const appDir = join14(projectRoot, "app");
10748
11215
  const pages = await listPageFiles(appDir);
10749
11216
  for (const file of pages) {
10750
- const content = readFileSync13(file, "utf-8");
11217
+ const content = readFileSync14(file, "utf-8");
10751
11218
  const fixed = fixUnescapedLtInJsx(sanitizeMetadataStrings(ensureUseClientIfNeeded(content)));
10752
11219
  if (fixed !== content) {
10753
11220
  writeFileSync10(file, fixed, "utf-8");
10754
- console.log(chalk14.dim(` \u2714 Auto-fixed syntax: ${file.replace(projectRoot, ".").replace(/^\.[/\\]/, "")}`));
11221
+ console.log(chalk15.dim(` \u2714 Auto-fixed syntax: ${file.replace(projectRoot, ".").replace(/^\.[/\\]/, "")}`));
10755
11222
  }
10756
11223
  }
10757
11224
  }
@@ -10760,9 +11227,14 @@ async function fixMissingComponentExports(projectRoot) {
10760
11227
  const uiDir = join14(projectRoot, "components", "ui");
10761
11228
  if (!existsSync19(appDir) || !existsSync19(uiDir)) return;
10762
11229
  const pages = await listPageFiles(appDir);
11230
+ const sharedDir = join14(projectRoot, "components", "shared");
11231
+ if (existsSync19(sharedDir)) {
11232
+ const sharedFiles = readdirSync5(sharedDir).filter((f) => f.endsWith(".tsx") || f.endsWith(".ts")).map((f) => join14(sharedDir, f));
11233
+ pages.push(...sharedFiles);
11234
+ }
10763
11235
  const neededExports = /* @__PURE__ */ new Map();
10764
11236
  for (const file of pages) {
10765
- const content = readFileSync13(file, "utf-8");
11237
+ const content = readFileSync14(file, "utf-8");
10766
11238
  const importRe = /import\s*\{([^}]+)\}\s*from\s*['"]@\/components\/ui\/([^'"]+)['"]/g;
10767
11239
  let m;
10768
11240
  while ((m = importRe.exec(content)) !== null) {
@@ -10788,7 +11260,7 @@ async function fixMissingComponentExports(projectRoot) {
10788
11260
  try {
10789
11261
  const result = await provider.installComponent(componentId, projectRoot);
10790
11262
  if (result.success) {
10791
- console.log(chalk14.dim(` \u2714 Installed missing ${componentId}.tsx`));
11263
+ console.log(chalk15.dim(` \u2714 Installed missing ${componentId}.tsx`));
10792
11264
  }
10793
11265
  } catch {
10794
11266
  }
@@ -10800,13 +11272,13 @@ async function fixMissingComponentExports(projectRoot) {
10800
11272
  mkdirSync10(uiDir, { recursive: true });
10801
11273
  const newContent = await generator.generate(def);
10802
11274
  writeFileSync10(componentFile, newContent, "utf-8");
10803
- console.log(chalk14.dim(` \u2714 Created missing ${componentId}.tsx`));
11275
+ console.log(chalk15.dim(` \u2714 Created missing ${componentId}.tsx`));
10804
11276
  } catch {
10805
11277
  }
10806
11278
  }
10807
11279
  continue;
10808
11280
  }
10809
- const content = readFileSync13(componentFile, "utf-8");
11281
+ const content = readFileSync14(componentFile, "utf-8");
10810
11282
  const exportRe = /export\s+(?:const|function|class)\s+(\w+)|export\s*\{([^}]+)\}/g;
10811
11283
  const existingExports = /* @__PURE__ */ new Set();
10812
11284
  let em;
@@ -10823,7 +11295,7 @@ async function fixMissingComponentExports(projectRoot) {
10823
11295
  try {
10824
11296
  const result = await provider.installComponent(componentId, projectRoot, { force: true });
10825
11297
  if (result.success) {
10826
- console.log(chalk14.dim(` \u2714 Reinstalled ${componentId}.tsx (added missing exports: ${missing.join(", ")})`));
11298
+ console.log(chalk15.dim(` \u2714 Reinstalled ${componentId}.tsx (added missing exports: ${missing.join(", ")})`));
10827
11299
  }
10828
11300
  } catch {
10829
11301
  }
@@ -10833,7 +11305,7 @@ async function fixMissingComponentExports(projectRoot) {
10833
11305
  try {
10834
11306
  const newContent = await generator.generate(def);
10835
11307
  writeFileSync10(componentFile, newContent, "utf-8");
10836
- console.log(chalk14.dim(` \u2714 Regenerated ${componentId}.tsx (added missing exports: ${missing.join(", ")})`));
11308
+ console.log(chalk15.dim(` \u2714 Regenerated ${componentId}.tsx (added missing exports: ${missing.join(", ")})`));
10837
11309
  } catch {
10838
11310
  }
10839
11311
  }
@@ -10859,7 +11331,7 @@ async function backfillPageAnalysis(projectRoot) {
10859
11331
  filePath = join14(projectRoot, "app", route.slice(1), "page.tsx");
10860
11332
  }
10861
11333
  if (!existsSync19(filePath)) continue;
10862
- const code = readFileSync13(filePath, "utf-8");
11334
+ const code = readFileSync14(filePath, "utf-8");
10863
11335
  if (code.length < 50) continue;
10864
11336
  page.pageAnalysis = analyzePageCode(code);
10865
11337
  changed = true;
@@ -10892,14 +11364,14 @@ async function healthCheck(port) {
10892
11364
  try {
10893
11365
  const res = await fetch(`http://localhost:${port}`);
10894
11366
  if (res.status === 200) {
10895
- console.log(chalk14.green(`
11367
+ console.log(chalk15.green(`
10896
11368
  \u2705 Preview healthy at http://localhost:${port}`));
10897
11369
  } else {
10898
- console.log(chalk14.yellow(`
11370
+ console.log(chalk15.yellow(`
10899
11371
  \u26A0 Preview returned ${res.status}. Run: coherent fix`));
10900
11372
  }
10901
11373
  } catch {
10902
- console.log(chalk14.yellow(`
11374
+ console.log(chalk15.yellow(`
10903
11375
  \u26A0 Preview not responding. Run: coherent fix`));
10904
11376
  }
10905
11377
  }
@@ -10938,29 +11410,29 @@ function launchWithMonitoring(projectRoot, restarts) {
10938
11410
  const shadcnId = extractShadcnComponentFromModuleNotFound(msg);
10939
11411
  if (shadcnId && !installingSet.has(shadcnId)) {
10940
11412
  installingSet.add(shadcnId);
10941
- console.log(chalk14.yellow(`
11413
+ console.log(chalk15.yellow(`
10942
11414
  \u26A0 Missing component detected: ${shadcnId}`));
10943
- console.log(chalk14.cyan(" Auto-installing..."));
11415
+ console.log(chalk15.cyan(" Auto-installing..."));
10944
11416
  autoInstallShadcnComponent(shadcnId, projectRoot).then((ok) => {
10945
11417
  if (ok) {
10946
- console.log(chalk14.green(` \u2714 Installed ${shadcnId}.tsx. Restarting...`));
11418
+ console.log(chalk15.green(` \u2714 Installed ${shadcnId}.tsx. Restarting...`));
10947
11419
  intentionalRestart = true;
10948
11420
  server.kill("SIGTERM");
10949
11421
  launchWithMonitoring(projectRoot, restarts + 1).then(resolvePromise).catch(rejectPromise);
10950
11422
  } else {
10951
- console.log(chalk14.red(` \u2716 Could not install ${shadcnId}. Run: npx shadcn@latest add ${shadcnId}`));
11423
+ console.log(chalk15.red(` \u2716 Could not install ${shadcnId}. Run: npx shadcn@latest add ${shadcnId}`));
10952
11424
  }
10953
11425
  });
10954
11426
  } else if (!shadcnId) {
10955
11427
  const pkg = extractPackageFromModuleNotFound(msg);
10956
11428
  if (pkg && !installingSet.has(pkg)) {
10957
11429
  installingSet.add(pkg);
10958
- console.log(chalk14.yellow(`
11430
+ console.log(chalk15.yellow(`
10959
11431
  \u26A0 Missing package detected: ${pkg}`));
10960
- console.log(chalk14.cyan(" Auto-installing..."));
11432
+ console.log(chalk15.cyan(" Auto-installing..."));
10961
11433
  installPackages(projectRoot, [pkg]).then((ok) => {
10962
11434
  if (ok) {
10963
- console.log(chalk14.green(` \u2714 Installed ${pkg}. Restarting...`));
11435
+ console.log(chalk15.green(` \u2714 Installed ${pkg}. Restarting...`));
10964
11436
  intentionalRestart = true;
10965
11437
  server.kill("SIGTERM");
10966
11438
  launchWithMonitoring(projectRoot, restarts + 1).then(resolvePromise).catch(rejectPromise);
@@ -10970,19 +11442,19 @@ function launchWithMonitoring(projectRoot, restarts) {
10970
11442
  }
10971
11443
  }
10972
11444
  if (msg.includes("Failed to compile")) {
10973
- console.log(chalk14.yellow("\n\u26A0 Compilation error detected."));
10974
- console.log(chalk14.dim(' Hint: run "coherent fix" in another terminal to auto-fix'));
10975
- console.log(chalk14.dim(' Or: coherent chat "fix the broken page"'));
11445
+ console.log(chalk15.yellow("\n\u26A0 Compilation error detected."));
11446
+ console.log(chalk15.dim(' Hint: run "coherent fix" in another terminal to auto-fix'));
11447
+ console.log(chalk15.dim(' Or: coherent chat "fix the broken page"'));
10976
11448
  }
10977
11449
  });
10978
11450
  server.on("exit", (code) => {
10979
11451
  if (intentionalRestart) return;
10980
11452
  if (code !== 0 && code !== null) {
10981
- console.log(chalk14.red(`
11453
+ console.log(chalk15.red(`
10982
11454
  \u274C Dev server exited with code ${code}`));
10983
- console.log(chalk14.dim(' Check the output above. Fix and run "coherent preview" again.\n'));
11455
+ console.log(chalk15.dim(' Check the output above. Fix and run "coherent preview" again.\n'));
10984
11456
  } else {
10985
- console.log(chalk14.dim("\n\u{1F44B} Dev server stopped"));
11457
+ console.log(chalk15.dim("\n\u{1F44B} Dev server stopped"));
10986
11458
  }
10987
11459
  process.exit(code ?? 0);
10988
11460
  });
@@ -10991,7 +11463,7 @@ function launchWithMonitoring(projectRoot, restarts) {
10991
11463
  });
10992
11464
  const shutdown = () => {
10993
11465
  closeWatcher();
10994
- console.log(chalk14.dim("\n\n\u{1F6D1} Stopping dev server..."));
11466
+ console.log(chalk15.dim("\n\n\u{1F6D1} Stopping dev server..."));
10995
11467
  server.kill("SIGTERM");
10996
11468
  };
10997
11469
  process.on("SIGINT", shutdown);
@@ -11003,9 +11475,9 @@ async function openBrowser(url) {
11003
11475
  const open = await import("open");
11004
11476
  await open.default(url);
11005
11477
  } catch (error) {
11006
- console.log(chalk14.yellow(`
11478
+ console.log(chalk15.yellow(`
11007
11479
  \u26A0\uFE0F Could not open browser automatically`));
11008
- console.log(chalk14.dim(` Please open ${url} manually`));
11480
+ console.log(chalk15.dim(` Please open ${url} manually`));
11009
11481
  }
11010
11482
  }
11011
11483
  function startDevServer(projectRoot) {
@@ -11036,8 +11508,8 @@ async function previewCommand() {
11036
11508
  try {
11037
11509
  if (!checkProjectInitialized(projectRoot)) {
11038
11510
  spinner.fail("Project not initialized");
11039
- console.log(chalk14.red("\n\u274C Project not found"));
11040
- console.log(chalk14.dim('Run "coherent init" first to create a project.'));
11511
+ console.log(chalk15.red("\n\u274C Project not found"));
11512
+ console.log(chalk15.dim('Run "coherent init" first to create a project.'));
11041
11513
  process.exit(1);
11042
11514
  }
11043
11515
  spinner.text = "Checking dependencies...";
@@ -11045,16 +11517,16 @@ async function previewCommand() {
11045
11517
  spinner.warn("Dependencies not installed");
11046
11518
  const pm = getPackageManager(projectRoot);
11047
11519
  const installCommand = pm === "pnpm" ? "pnpm install" : "npm install";
11048
- console.log(chalk14.yellow("\n\u26A0\uFE0F Dependencies not installed"));
11049
- console.log(chalk14.cyan(`
11520
+ console.log(chalk15.yellow("\n\u26A0\uFE0F Dependencies not installed"));
11521
+ console.log(chalk15.cyan(`
11050
11522
  Running ${installCommand}...
11051
11523
  `));
11052
11524
  const ok = await runInstall(projectRoot);
11053
11525
  if (!ok) {
11054
- console.error(chalk14.red('\n\u274C Install failed. Fix errors above and run "coherent preview" again.\n'));
11526
+ console.error(chalk15.red('\n\u274C Install failed. Fix errors above and run "coherent preview" again.\n'));
11055
11527
  process.exit(1);
11056
11528
  }
11057
- console.log(chalk14.green("\n\u2705 Dependencies installed\n"));
11529
+ console.log(chalk15.green("\n\u2705 Dependencies installed\n"));
11058
11530
  } else {
11059
11531
  spinner.succeed("Project ready");
11060
11532
  }
@@ -11077,30 +11549,30 @@ async function previewCommand() {
11077
11549
  await fixMissingComponentExports(projectRoot);
11078
11550
  await backfillPageAnalysis(projectRoot);
11079
11551
  spinner.succeed("Project ready");
11080
- console.log(chalk14.dim(" \u{1F4A1} Edited files manually? Run `coherent sync` to update the Design System.\n"));
11081
- console.log(chalk14.blue("\n\u{1F680} Starting Next.js dev server...\n"));
11552
+ console.log(chalk15.dim(" \u{1F4A1} Edited files manually? Run `coherent sync` to update the Design System.\n"));
11553
+ console.log(chalk15.blue("\n\u{1F680} Starting Next.js dev server...\n"));
11082
11554
  await launchWithMonitoring(projectRoot, 0);
11083
11555
  } catch (error) {
11084
11556
  spinner.fail("Failed to start dev server");
11085
11557
  if (error instanceof Error) {
11086
- console.error(chalk14.red(`
11558
+ console.error(chalk15.red(`
11087
11559
  \u274C ${error.message}`));
11088
11560
  if (error.message.includes("package.json")) {
11089
- console.log(chalk14.yellow("\n\u{1F4A1} Tip: Make sure you're in a Coherent project directory."));
11090
- console.log(chalk14.dim(' Run "coherent init" to create a new project.'));
11561
+ console.log(chalk15.yellow("\n\u{1F4A1} Tip: Make sure you're in a Coherent project directory."));
11562
+ console.log(chalk15.dim(' Run "coherent init" to create a new project.'));
11091
11563
  }
11092
11564
  } else {
11093
- console.error(chalk14.red("Unknown error occurred"));
11565
+ console.error(chalk15.red("Unknown error occurred"));
11094
11566
  }
11095
11567
  process.exit(1);
11096
11568
  }
11097
11569
  }
11098
11570
 
11099
11571
  // src/commands/export.ts
11100
- import chalk15 from "chalk";
11572
+ import chalk16 from "chalk";
11101
11573
  import ora4 from "ora";
11102
11574
  import { spawn as spawn2 } from "child_process";
11103
- import { existsSync as existsSync20, rmSync as rmSync4, readdirSync as readdirSync4 } from "fs";
11575
+ import { existsSync as existsSync20, rmSync as rmSync4, readdirSync as readdirSync6 } from "fs";
11104
11576
  import { resolve as resolve11, join as join15, dirname as dirname7 } from "path";
11105
11577
  import { readdir as readdir3, readFile as readFile6, writeFile as writeFile5, mkdir as mkdir5, copyFile as copyFile2 } from "fs/promises";
11106
11578
  var COPY_EXCLUDE = /* @__PURE__ */ new Set([
@@ -11221,7 +11693,7 @@ function countComponents(outRoot) {
11221
11693
  const dir = join15(outRoot, "components", sub);
11222
11694
  if (!existsSync20(dir)) continue;
11223
11695
  try {
11224
- n += readdirSync4(dir).filter((f) => f.endsWith(".tsx") || f.endsWith(".jsx")).length;
11696
+ n += readdirSync6(dir).filter((f) => f.endsWith(".tsx") || f.endsWith(".jsx")).length;
11225
11697
  } catch {
11226
11698
  }
11227
11699
  }
@@ -11376,7 +11848,7 @@ async function exportCommand(options = {}) {
11376
11848
  const missingDeps = await findMissingDepsInExport(outputDir);
11377
11849
  if (missingDeps.length > 0) {
11378
11850
  console.log(
11379
- chalk15.yellow(
11851
+ chalk16.yellow(
11380
11852
  "\n\u26A0\uFE0F Warning: exported code imports packages not in package.json: " + missingDeps.join(", ") + "\n Add them to dependencies and run npm install in the export dir.\n"
11381
11853
  )
11382
11854
  );
@@ -11392,7 +11864,7 @@ async function exportCommand(options = {}) {
11392
11864
  spinner.succeed("Dependencies installed");
11393
11865
  await ensureReadmeDeploySection(outputDir);
11394
11866
  await patchNextConfigForExport(outputDir);
11395
- console.log(chalk15.dim("\n Tip: run `coherent check` before export to catch quality issues.\n"));
11867
+ console.log(chalk16.dim("\n Tip: run `coherent check` before export to catch quality issues.\n"));
11396
11868
  let buildOk = false;
11397
11869
  if (doBuild) {
11398
11870
  spinner.start("Running next build...");
@@ -11402,7 +11874,7 @@ async function exportCommand(options = {}) {
11402
11874
  spinner.succeed("Build: success");
11403
11875
  } catch (e) {
11404
11876
  spinner.fail("Build failed");
11405
- if (e instanceof Error) console.error(chalk15.red(e.message));
11877
+ if (e instanceof Error) console.error(chalk16.red(e.message));
11406
11878
  }
11407
11879
  } else {
11408
11880
  buildOk = true;
@@ -11410,23 +11882,23 @@ async function exportCommand(options = {}) {
11410
11882
  const pageCount = await countPages(outputDir);
11411
11883
  const componentCount = countComponents(outputDir);
11412
11884
  spinner.stop();
11413
- console.log(chalk15.green("\n\u2705 Exported to " + outputDir + "\n"));
11414
- console.log(chalk15.blue(" Pages: " + pageCount));
11415
- console.log(chalk15.blue(" Components: " + componentCount + " (base + shared)"));
11416
- console.log(chalk15.blue(" Build: " + (doBuild ? buildOk ? "success" : "failed" : "skipped (--no-build)")));
11885
+ console.log(chalk16.green("\n\u2705 Exported to " + outputDir + "\n"));
11886
+ console.log(chalk16.blue(" Pages: " + pageCount));
11887
+ console.log(chalk16.blue(" Components: " + componentCount + " (base + shared)"));
11888
+ console.log(chalk16.blue(" Build: " + (doBuild ? buildOk ? "success" : "failed" : "skipped (--no-build)")));
11417
11889
  console.log("");
11418
- console.log(chalk15.dim(" Deploy: npx vercel " + outputDir));
11419
- console.log(chalk15.dim(" or: npx netlify deploy --dir " + outputDir + "/.next"));
11890
+ console.log(chalk16.dim(" Deploy: npx vercel " + outputDir));
11891
+ console.log(chalk16.dim(" or: npx netlify deploy --dir " + outputDir + "/.next"));
11420
11892
  console.log("");
11421
11893
  } catch (error) {
11422
11894
  spinner.fail("Export failed");
11423
- if (error instanceof Error) console.error(chalk15.red("\n\u274C " + error.message));
11895
+ if (error instanceof Error) console.error(chalk16.red("\n\u274C " + error.message));
11424
11896
  process.exit(1);
11425
11897
  }
11426
11898
  }
11427
11899
 
11428
11900
  // src/commands/status.ts
11429
- import chalk16 from "chalk";
11901
+ import chalk17 from "chalk";
11430
11902
  import { basename } from "path";
11431
11903
  import { DesignSystemManager as DesignSystemManager9 } from "@getcoherent/core";
11432
11904
  function countTokens(tokens) {
@@ -11450,58 +11922,58 @@ async function statusCommand() {
11450
11922
  try {
11451
11923
  const project = findConfig();
11452
11924
  if (!project) {
11453
- console.log(chalk16.yellow("\u26A0\uFE0F Not in a Coherent project\n"));
11925
+ console.log(chalk17.yellow("\u26A0\uFE0F Not in a Coherent project\n"));
11454
11926
  console.log("Initialize a project:");
11455
- console.log(chalk16.white(" $ coherent init\n"));
11927
+ console.log(chalk17.white(" $ coherent init\n"));
11456
11928
  return;
11457
11929
  }
11458
- console.log(chalk16.cyan("\n\u2728 Current Project\n"));
11459
- console.log(chalk16.gray("\u{1F4C1} Location: ") + chalk16.white(project.root));
11460
- console.log(chalk16.gray("\u{1F4C4} Config: ") + chalk16.white(basename(project.configPath)));
11930
+ console.log(chalk17.cyan("\n\u2728 Current Project\n"));
11931
+ console.log(chalk17.gray("\u{1F4C1} Location: ") + chalk17.white(project.root));
11932
+ console.log(chalk17.gray("\u{1F4C4} Config: ") + chalk17.white(basename(project.configPath)));
11461
11933
  console.log("");
11462
11934
  try {
11463
11935
  const manager = new DesignSystemManager9(project.configPath);
11464
11936
  await manager.load();
11465
11937
  const config2 = manager.getConfig();
11466
- console.log(chalk16.cyan("\u{1F4CA} Statistics:\n"));
11938
+ console.log(chalk17.cyan("\u{1F4CA} Statistics:\n"));
11467
11939
  const pageCount = Array.isArray(config2.pages) ? config2.pages.length : Object.keys(config2.pages || {}).length;
11468
- console.log(chalk16.gray(" Pages: ") + chalk16.white(String(pageCount)));
11940
+ console.log(chalk17.gray(" Pages: ") + chalk17.white(String(pageCount)));
11469
11941
  const componentCount = Array.isArray(config2.components) ? config2.components.length : Object.keys(config2.components || {}).length;
11470
- console.log(chalk16.gray(" Components: ") + chalk16.white(String(componentCount)));
11942
+ console.log(chalk17.gray(" Components: ") + chalk17.white(String(componentCount)));
11471
11943
  const tokenCount = countTokens(config2.tokens);
11472
- console.log(chalk16.gray(" Design tokens: ") + chalk16.white(String(tokenCount)));
11944
+ console.log(chalk17.gray(" Design tokens: ") + chalk17.white(String(tokenCount)));
11473
11945
  console.log("");
11474
11946
  const recent = readRecentChanges(project.root);
11475
11947
  if (recent.length > 0) {
11476
- console.log(chalk16.cyan("\u{1F4DD} Recent changes:\n"));
11948
+ console.log(chalk17.cyan("\u{1F4DD} Recent changes:\n"));
11477
11949
  recent.slice(0, 5).forEach((change) => {
11478
11950
  const ago = formatTimeAgo(change.timestamp);
11479
- console.log(chalk16.gray(" \u2022 ") + chalk16.white(change.description) + chalk16.gray(` (${ago})`));
11951
+ console.log(chalk17.gray(" \u2022 ") + chalk17.white(change.description) + chalk17.gray(` (${ago})`));
11480
11952
  });
11481
11953
  console.log("");
11482
11954
  }
11483
- console.log(chalk16.cyan("\u{1F680} Quick actions:\n"));
11484
- console.log(chalk16.white(' $ coherent chat "add new page"'));
11485
- console.log(chalk16.white(" $ coherent preview"));
11486
- console.log(chalk16.white(" $ coherent export"));
11955
+ console.log(chalk17.cyan("\u{1F680} Quick actions:\n"));
11956
+ console.log(chalk17.white(' $ coherent chat "add new page"'));
11957
+ console.log(chalk17.white(" $ coherent preview"));
11958
+ console.log(chalk17.white(" $ coherent export"));
11487
11959
  console.log("");
11488
11960
  } catch (error) {
11489
- console.error(chalk16.red("Error loading config:"));
11961
+ console.error(chalk17.red("Error loading config:"));
11490
11962
  if (error instanceof Error) {
11491
- console.error(chalk16.red(` ${error.message}`));
11963
+ console.error(chalk17.red(` ${error.message}`));
11492
11964
  } else {
11493
- console.error(chalk16.red(" Unknown error"));
11965
+ console.error(chalk17.red(" Unknown error"));
11494
11966
  }
11495
11967
  console.log("");
11496
11968
  }
11497
11969
  } catch (error) {
11498
- console.error(chalk16.red("\u274C Command failed:"), error instanceof Error ? error.message : "Unknown error");
11970
+ console.error(chalk17.red("\u274C Command failed:"), error instanceof Error ? error.message : "Unknown error");
11499
11971
  process.exit(1);
11500
11972
  }
11501
11973
  }
11502
11974
 
11503
11975
  // src/commands/regenerate-docs.ts
11504
- import chalk17 from "chalk";
11976
+ import chalk18 from "chalk";
11505
11977
  import ora5 from "ora";
11506
11978
  import { DesignSystemManager as DesignSystemManager10 } from "@getcoherent/core";
11507
11979
  import { ProjectScaffolder as ProjectScaffolder2 } from "@getcoherent/core";
@@ -11509,9 +11981,9 @@ async function regenerateDocsCommand() {
11509
11981
  try {
11510
11982
  const project = findConfig();
11511
11983
  if (!project) {
11512
- console.log(chalk17.yellow("\u26A0\uFE0F Not in a Coherent project\n"));
11984
+ console.log(chalk18.yellow("\u26A0\uFE0F Not in a Coherent project\n"));
11513
11985
  console.log("Run this command from a project root that has design-system.config.ts");
11514
- console.log(chalk17.white(" $ coherent init # in an empty folder first\n"));
11986
+ console.log(chalk18.white(" $ coherent init # in an empty folder first\n"));
11515
11987
  process.exit(1);
11516
11988
  }
11517
11989
  const spinner = ora5("Regenerating documentation pages...").start();
@@ -11523,24 +11995,24 @@ async function regenerateDocsCommand() {
11523
11995
  await scaffolder.generateDocsPages();
11524
11996
  spinner.succeed("Documentation pages updated");
11525
11997
  console.log(
11526
- chalk17.gray(
11998
+ chalk18.gray(
11527
11999
  "\nUpdated: app/design-system/docs/ (layout, page, components, tokens, for-designers, recommendations)\n"
11528
12000
  )
11529
12001
  );
11530
12002
  } catch (err) {
11531
12003
  spinner.fail("Failed to regenerate docs");
11532
- console.error(chalk17.red(err instanceof Error ? err.message : String(err)));
12004
+ console.error(chalk18.red(err instanceof Error ? err.message : String(err)));
11533
12005
  process.exit(1);
11534
12006
  }
11535
12007
  } catch (error) {
11536
- console.error(chalk17.red("\u274C Command failed:"), error instanceof Error ? error.message : "Unknown error");
12008
+ console.error(chalk18.red("\u274C Command failed:"), error instanceof Error ? error.message : "Unknown error");
11537
12009
  process.exit(1);
11538
12010
  }
11539
12011
  }
11540
12012
 
11541
12013
  // src/commands/fix.ts
11542
- 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";
12014
+ import chalk19 from "chalk";
12015
+ import { readdirSync as readdirSync7, readFileSync as readFileSync15, existsSync as existsSync21, writeFileSync as writeFileSync11, rmSync as rmSync5, mkdirSync as mkdirSync7 } from "fs";
11544
12016
  import { resolve as resolve12, join as join16 } from "path";
11545
12017
  import {
11546
12018
  DesignSystemManager as DesignSystemManager11,
@@ -11565,7 +12037,7 @@ function extractComponentIdsFromCode2(code) {
11565
12037
  function listTsxFiles(dir) {
11566
12038
  const files = [];
11567
12039
  try {
11568
- const entries = readdirSync5(dir, { withFileTypes: true });
12040
+ const entries = readdirSync7(dir, { withFileTypes: true });
11569
12041
  for (const e of entries) {
11570
12042
  const full = join16(dir, e.name);
11571
12043
  if (e.isDirectory() && e.name !== "node_modules" && !e.name.startsWith(".")) {
@@ -11591,31 +12063,31 @@ async function fixCommand(opts = {}) {
11591
12063
  const fixes = [];
11592
12064
  const remaining = [];
11593
12065
  if (dryRun) {
11594
- console.log(chalk18.cyan("\ncoherent fix --dry-run\n"));
12066
+ console.log(chalk19.cyan("\ncoherent fix --dry-run\n"));
11595
12067
  } else {
11596
- console.log(chalk18.cyan("\ncoherent fix\n"));
12068
+ console.log(chalk19.cyan("\ncoherent fix\n"));
11597
12069
  }
11598
12070
  if (!skipCache) {
11599
12071
  const nextDir = join16(projectRoot, ".next");
11600
12072
  if (existsSync21(nextDir)) {
11601
12073
  if (!dryRun) rmSync5(nextDir, { recursive: true, force: true });
11602
12074
  fixes.push("Cleared build cache");
11603
- console.log(chalk18.green(" \u2714 Cleared build cache"));
12075
+ console.log(chalk19.green(" \u2714 Cleared build cache"));
11604
12076
  }
11605
12077
  }
11606
12078
  const missingPkgs = await findMissingPackages(projectRoot);
11607
12079
  if (missingPkgs.length > 0) {
11608
12080
  if (dryRun) {
11609
12081
  fixes.push(`Would install packages: ${missingPkgs.join(", ")}`);
11610
- console.log(chalk18.green(` \u2714 Would install packages: ${missingPkgs.join(", ")}`));
12082
+ console.log(chalk19.green(` \u2714 Would install packages: ${missingPkgs.join(", ")}`));
11611
12083
  } else {
11612
12084
  const ok = await installPackages(projectRoot, missingPkgs);
11613
12085
  if (ok) {
11614
12086
  fixes.push(`Installed missing packages: ${missingPkgs.join(", ")}`);
11615
- console.log(chalk18.green(` \u2714 Installed missing packages: ${missingPkgs.join(", ")}`));
12087
+ console.log(chalk19.green(` \u2714 Installed missing packages: ${missingPkgs.join(", ")}`));
11616
12088
  } else {
11617
12089
  remaining.push(`Failed to install: ${missingPkgs.join(", ")}. Run: npm install ${missingPkgs.join(" ")}`);
11618
- console.log(chalk18.yellow(` \u26A0 Could not install: ${missingPkgs.join(", ")}`));
12090
+ console.log(chalk19.yellow(` \u26A0 Could not install: ${missingPkgs.join(", ")}`));
11619
12091
  }
11620
12092
  }
11621
12093
  }
@@ -11624,7 +12096,7 @@ async function fixCommand(opts = {}) {
11624
12096
  const componentsTsxFiles = listTsxFiles(resolve12(projectRoot, "components"));
11625
12097
  const allComponentIds = /* @__PURE__ */ new Set();
11626
12098
  for (const file of [...allTsxFiles, ...componentsTsxFiles]) {
11627
- const content = readFileSync14(file, "utf-8");
12099
+ const content = readFileSync15(file, "utf-8");
11628
12100
  extractComponentIdsFromCode2(content).forEach((id) => allComponentIds.add(id));
11629
12101
  }
11630
12102
  let dsm = null;
@@ -11652,7 +12124,7 @@ async function fixCommand(opts = {}) {
11652
12124
  if (toInstall.length > 0) {
11653
12125
  if (dryRun) {
11654
12126
  fixes.push(`Would install components: ${toInstall.join(", ")}`);
11655
- console.log(chalk18.green(` \u2714 Would install components: ${toInstall.join(", ")}`));
12127
+ console.log(chalk19.green(` \u2714 Would install components: ${toInstall.join(", ")}`));
11656
12128
  } else {
11657
12129
  let installed = 0;
11658
12130
  for (const componentId of toInstall) {
@@ -11681,14 +12153,14 @@ async function fixCommand(opts = {}) {
11681
12153
  installed++;
11682
12154
  } catch (err) {
11683
12155
  console.log(
11684
- chalk18.yellow(` \u26A0 Failed to install ${componentId}: ${err instanceof Error ? err.message : "unknown"}`)
12156
+ chalk19.yellow(` \u26A0 Failed to install ${componentId}: ${err instanceof Error ? err.message : "unknown"}`)
11685
12157
  );
11686
12158
  }
11687
12159
  }
11688
12160
  if (installed > 0) {
11689
12161
  await dsm.save();
11690
12162
  fixes.push(`Installed missing components: ${toInstall.join(", ")}`);
11691
- console.log(chalk18.green(` \u2714 Installed missing components: ${toInstall.join(", ")}`));
12163
+ console.log(chalk19.green(` \u2714 Installed missing components: ${toInstall.join(", ")}`));
11692
12164
  }
11693
12165
  }
11694
12166
  }
@@ -11696,7 +12168,7 @@ async function fixCommand(opts = {}) {
11696
12168
  const userTsxFiles = allTsxFiles.filter((f) => !f.includes("/design-system/"));
11697
12169
  let syntaxFixed = 0;
11698
12170
  for (const file of userTsxFiles) {
11699
- const content = readFileSync14(file, "utf-8");
12171
+ const content = readFileSync15(file, "utf-8");
11700
12172
  const fixed = fixUnescapedLtInJsx(
11701
12173
  fixEscapedClosingQuotes(sanitizeMetadataStrings(ensureUseClientIfNeeded(content)))
11702
12174
  );
@@ -11708,13 +12180,13 @@ async function fixCommand(opts = {}) {
11708
12180
  if (syntaxFixed > 0) {
11709
12181
  const verb = dryRun ? "Would fix" : "Fixed";
11710
12182
  fixes.push(`${verb} syntax in ${syntaxFixed} file(s)`);
11711
- console.log(chalk18.green(` \u2714 ${verb} syntax: ${syntaxFixed} file(s) (use client, metadata, quotes)`));
12183
+ console.log(chalk19.green(` \u2714 ${verb} syntax: ${syntaxFixed} file(s) (use client, metadata, quotes)`));
11712
12184
  }
11713
12185
  if (!skipQuality) {
11714
12186
  let qualityFixCount = 0;
11715
12187
  const qualityFixDetails = [];
11716
12188
  for (const file of userTsxFiles) {
11717
- const content = readFileSync14(file, "utf-8");
12189
+ const content = readFileSync15(file, "utf-8");
11718
12190
  const { code: autoFixed, fixes: fileFixes } = await autoFixCode(content);
11719
12191
  if (autoFixed !== content) {
11720
12192
  if (!dryRun) writeFileSync11(file, autoFixed, "utf-8");
@@ -11726,14 +12198,14 @@ async function fixCommand(opts = {}) {
11726
12198
  const uniqueFixes = [...new Set(qualityFixDetails)];
11727
12199
  const verb = dryRun ? "Would fix" : "Fixed";
11728
12200
  fixes.push(`${verb} quality in ${qualityFixCount} file(s)`);
11729
- console.log(chalk18.green(` \u2714 ${verb} ${uniqueFixes.length} quality issue type(s): ${uniqueFixes.join(", ")}`));
12201
+ console.log(chalk19.green(` \u2714 ${verb} ${uniqueFixes.length} quality issue type(s): ${uniqueFixes.join(", ")}`));
11730
12202
  }
11731
12203
  }
11732
12204
  let totalErrors = 0;
11733
12205
  let totalWarnings = 0;
11734
12206
  const fileIssues = [];
11735
12207
  for (const file of allTsxFiles) {
11736
- const code = dryRun ? readFileSync14(file, "utf-8") : readFileSync14(file, "utf-8");
12208
+ const code = dryRun ? readFileSync15(file, "utf-8") : readFileSync15(file, "utf-8");
11737
12209
  const relativePath = file.replace(projectRoot + "/", "");
11738
12210
  const baseName = file.split("/").pop() || "";
11739
12211
  const isAuthPage = relativePath.includes("(auth)");
@@ -11771,13 +12243,13 @@ async function fixCommand(opts = {}) {
11771
12243
  if (dryRun) {
11772
12244
  fixes.push(`Would update ${o.id} path to ${newPath}`);
11773
12245
  } else {
11774
- console.log(chalk18.green(` \u2714 Updated ${o.id} (${o.name}) path \u2192 ${newPath}`));
12246
+ console.log(chalk19.green(` \u2714 Updated ${o.id} (${o.name}) path \u2192 ${newPath}`));
11775
12247
  }
11776
12248
  } else {
11777
12249
  if (dryRun) {
11778
12250
  fixes.push(`Would remove orphaned ${o.id} (${o.name})`);
11779
12251
  } else {
11780
- console.log(chalk18.green(` \u2714 Removed orphaned ${o.id} (${o.name}) \u2014 file missing`));
12252
+ console.log(chalk19.green(` \u2714 Removed orphaned ${o.id} (${o.name}) \u2014 file missing`));
11781
12253
  }
11782
12254
  }
11783
12255
  }
@@ -11790,7 +12262,7 @@ async function fixCommand(opts = {}) {
11790
12262
  entry.usedIn = fullActual;
11791
12263
  manifestModified = true;
11792
12264
  if (!dryRun) {
11793
- console.log(chalk18.green(` \u2714 Updated ${entry.id} usedIn: ${fullActual.join(", ") || "none"}`));
12265
+ console.log(chalk19.green(` \u2714 Updated ${entry.id} usedIn: ${fullActual.join(", ") || "none"}`));
11794
12266
  }
11795
12267
  }
11796
12268
  }
@@ -11808,7 +12280,7 @@ async function fixCommand(opts = {}) {
11808
12280
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
11809
12281
  });
11810
12282
  manifest.nextId++;
11811
- console.log(chalk18.green(` \u2714 Registered ${id} (${comp.name}) from ${comp.file}`));
12283
+ console.log(chalk19.green(` \u2714 Registered ${id} (${comp.name}) from ${comp.file}`));
11812
12284
  } else {
11813
12285
  fixes.push(`Would register ${comp.name} from ${comp.file}`);
11814
12286
  }
@@ -11828,41 +12300,41 @@ async function fixCommand(opts = {}) {
11828
12300
  } catch {
11829
12301
  }
11830
12302
  if (fixes.length === 0 && totalErrors === 0 && totalWarnings === 0 && remaining.length === 0) {
11831
- console.log(chalk18.green("\n \u2705 Everything looks good \u2014 no issues found\n"));
11832
- console.log(chalk18.cyan(" Run: coherent preview\n"));
12303
+ console.log(chalk19.green("\n \u2705 Everything looks good \u2014 no issues found\n"));
12304
+ console.log(chalk19.cyan(" Run: coherent preview\n"));
11833
12305
  return;
11834
12306
  }
11835
12307
  if (fixes.length > 0) console.log("");
11836
12308
  if (totalErrors > 0 || totalWarnings > 0 || remaining.length > 0) {
11837
- console.log(chalk18.dim(" \u2500".repeat(25)));
11838
- console.log(chalk18.yellow(`
12309
+ console.log(chalk19.dim(" \u2500".repeat(25)));
12310
+ console.log(chalk19.yellow(`
11839
12311
  Remaining (need manual fix or AI):`));
11840
12312
  for (const { path: path4, report } of fileIssues) {
11841
- console.log(chalk18.dim(` \u{1F4C4} ${path4}`));
12313
+ console.log(chalk19.dim(` \u{1F4C4} ${path4}`));
11842
12314
  console.log(report);
11843
12315
  }
11844
12316
  for (const r of remaining) {
11845
- console.log(chalk18.yellow(` \u26A0 ${r}`));
12317
+ console.log(chalk19.yellow(` \u26A0 ${r}`));
11846
12318
  }
11847
12319
  console.log("");
11848
12320
  const parts = [];
11849
- if (totalErrors > 0) parts.push(chalk18.red(`\u274C ${totalErrors} error(s)`));
11850
- if (totalWarnings > 0) parts.push(chalk18.yellow(`\u26A0 ${totalWarnings} warning(s)`));
12321
+ if (totalErrors > 0) parts.push(chalk19.red(`\u274C ${totalErrors} error(s)`));
12322
+ if (totalWarnings > 0) parts.push(chalk19.yellow(`\u26A0 ${totalWarnings} warning(s)`));
11851
12323
  if (parts.length > 0) console.log(` ${parts.join(" ")}`);
11852
12324
  }
11853
- console.log(chalk18.cyan("\n Run: coherent preview\n"));
12325
+ console.log(chalk19.cyan("\n Run: coherent preview\n"));
11854
12326
  }
11855
12327
 
11856
12328
  // src/commands/check.ts
11857
- import chalk19 from "chalk";
12329
+ import chalk20 from "chalk";
11858
12330
  import { resolve as resolve13 } from "path";
11859
- import { readdirSync as readdirSync6, readFileSync as readFileSync15, statSync as statSync2, existsSync as existsSync22 } from "fs";
12331
+ import { readdirSync as readdirSync8, readFileSync as readFileSync16, statSync as statSync2, existsSync as existsSync22 } from "fs";
11860
12332
  import { loadManifest as loadManifest11 } from "@getcoherent/core";
11861
12333
  var EXCLUDED_DIRS = /* @__PURE__ */ new Set(["node_modules", "design-system"]);
11862
12334
  function findTsxFiles(dir) {
11863
12335
  const results = [];
11864
12336
  try {
11865
- const entries = readdirSync6(dir);
12337
+ const entries = readdirSync8(dir);
11866
12338
  for (const entry of entries) {
11867
12339
  const full = resolve13(dir, entry);
11868
12340
  const stat = statSync2(full);
@@ -11902,7 +12374,7 @@ async function checkCommand(opts = {}) {
11902
12374
  const appDir = resolve13(projectRoot, "app");
11903
12375
  const files = findTsxFiles(appDir);
11904
12376
  result.pages.total = files.length;
11905
- if (!opts.json) console.log(chalk19.cyan("\n \u{1F4C4} Pages") + chalk19.dim(` (${files.length} scanned)
12377
+ if (!opts.json) console.log(chalk20.cyan("\n \u{1F4C4} Pages") + chalk20.dim(` (${files.length} scanned)
11906
12378
  `));
11907
12379
  const autoFixableTypes = /* @__PURE__ */ new Set([
11908
12380
  "RAW_COLOR",
@@ -11913,7 +12385,7 @@ async function checkCommand(opts = {}) {
11913
12385
  "NATIVE_TABLE"
11914
12386
  ]);
11915
12387
  for (const file of files) {
11916
- const code = readFileSync15(file, "utf-8");
12388
+ const code = readFileSync16(file, "utf-8");
11917
12389
  const relativePath = file.replace(projectRoot + "/", "");
11918
12390
  const baseName = file.split("/").pop() || "";
11919
12391
  const isAuthPage = relativePath.includes("(auth)");
@@ -11932,7 +12404,7 @@ async function checkCommand(opts = {}) {
11932
12404
  result.autoFixable += fileAutoFixable;
11933
12405
  if (filteredIssues.length === 0) {
11934
12406
  result.pages.clean++;
11935
- if (!opts.json) console.log(chalk19.green(` \u2714 ${relativePath}`) + chalk19.dim(" \u2014 clean"));
12407
+ if (!opts.json) console.log(chalk20.green(` \u2714 ${relativePath}`) + chalk20.dim(" \u2014 clean"));
11936
12408
  continue;
11937
12409
  }
11938
12410
  if (errors > 0) result.pages.withErrors++;
@@ -11945,9 +12417,9 @@ async function checkCommand(opts = {}) {
11945
12417
  });
11946
12418
  if (!opts.json) {
11947
12419
  const parts = [];
11948
- if (errors > 0) parts.push(chalk19.red(`${errors} error(s)`));
11949
- if (warnings > 0) parts.push(chalk19.yellow(`${warnings} warning(s)`));
11950
- console.log(chalk19.yellow(` \u26A0 ${relativePath}`) + chalk19.dim(` \u2014 ${parts.join(", ")}`));
12420
+ if (errors > 0) parts.push(chalk20.red(`${errors} error(s)`));
12421
+ if (warnings > 0) parts.push(chalk20.yellow(`${warnings} warning(s)`));
12422
+ console.log(chalk20.yellow(` \u26A0 ${relativePath}`) + chalk20.dim(` \u2014 ${parts.join(", ")}`));
11951
12423
  console.log(formatIssues(filteredIssues));
11952
12424
  }
11953
12425
  }
@@ -11955,7 +12427,7 @@ async function checkCommand(opts = {}) {
11955
12427
  routeSet.add("/");
11956
12428
  routeSet.add("#");
11957
12429
  for (const file of files) {
11958
- const code = readFileSync15(file, "utf-8");
12430
+ const code = readFileSync16(file, "utf-8");
11959
12431
  const relativePath = file.replace(projectRoot + "/", "");
11960
12432
  const lines = code.split("\n");
11961
12433
  const linkHrefRe = /href\s*=\s*["'](\/[a-z0-9/-]*)["']/gi;
@@ -11973,15 +12445,15 @@ async function checkCommand(opts = {}) {
11973
12445
  }
11974
12446
  }
11975
12447
  if (!opts.json && result.links.broken.length > 0) {
11976
- console.log(chalk19.yellow(`
11977
- \u{1F517} Internal Links`) + chalk19.dim(` (${result.links.total} scanned)
12448
+ console.log(chalk20.yellow(`
12449
+ \u{1F517} Internal Links`) + chalk20.dim(` (${result.links.total} scanned)
11978
12450
  `));
11979
12451
  for (const b of result.links.broken) {
11980
- console.log(chalk19.red(` \u2717 ${b.file}:${b.line}`) + chalk19.dim(` \u2192 ${b.href} (route does not exist)`));
12452
+ console.log(chalk20.red(` \u2717 ${b.file}:${b.line}`) + chalk20.dim(` \u2192 ${b.href} (route does not exist)`));
11981
12453
  }
11982
12454
  } else if (!opts.json && result.links.total > 0) {
11983
- console.log(chalk19.green(`
11984
- \u{1F517} Internal Links`) + chalk19.dim(` \u2014 all ${result.links.total} links resolve \u2713`));
12455
+ console.log(chalk20.green(`
12456
+ \u{1F517} Internal Links`) + chalk20.dim(` \u2014 all ${result.links.total} links resolve \u2713`));
11985
12457
  }
11986
12458
  try {
11987
12459
  const manifest = await loadManifest11(project.root);
@@ -11990,7 +12462,7 @@ async function checkCommand(opts = {}) {
11990
12462
  const fullPath = resolve13(project.root, entry.file);
11991
12463
  if (!existsSync22(fullPath)) {
11992
12464
  result.pages.withErrors++;
11993
- if (!opts.json) console.log(chalk19.red(`
12465
+ if (!opts.json) console.log(chalk20.red(`
11994
12466
  \u2717 Missing shared component file: ${entry.id} (${entry.file})`));
11995
12467
  }
11996
12468
  }
@@ -12002,8 +12474,8 @@ async function checkCommand(opts = {}) {
12002
12474
  try {
12003
12475
  const manifest = await loadManifest11(projectRoot);
12004
12476
  if (!opts.json && manifest.shared.length > 0) {
12005
- console.log(chalk19.cyan(`
12006
- \u{1F9E9} Shared Components`) + chalk19.dim(` (${manifest.shared.length} registered)
12477
+ console.log(chalk20.cyan(`
12478
+ \u{1F9E9} Shared Components`) + chalk20.dim(` (${manifest.shared.length} registered)
12007
12479
  `));
12008
12480
  }
12009
12481
  let consistent = 0;
@@ -12017,23 +12489,23 @@ async function checkCommand(opts = {}) {
12017
12489
  if (!fileExists) {
12018
12490
  _orphaned++;
12019
12491
  if (!opts.json) {
12020
- console.log(chalk19.red(` \u274C ${entry.id} (${entry.name}) \u2014 file missing: ${entry.file}`));
12021
- console.log(chalk19.dim(` Fix: coherent fix or coherent sync`));
12492
+ console.log(chalk20.red(` \u274C ${entry.id} (${entry.name}) \u2014 file missing: ${entry.file}`));
12493
+ console.log(chalk20.dim(` Fix: coherent fix or coherent sync`));
12022
12494
  }
12023
12495
  continue;
12024
12496
  }
12025
12497
  try {
12026
- const code = readFileSync15(filePath, "utf-8");
12498
+ const code = readFileSync16(filePath, "utf-8");
12027
12499
  const actualExports = extractExportedComponentNames(code);
12028
12500
  if (actualExports.length > 0 && !actualExports.includes(entry.name)) {
12029
12501
  _nameMismatch++;
12030
12502
  if (!opts.json) {
12031
12503
  console.log(
12032
- chalk19.yellow(
12504
+ chalk20.yellow(
12033
12505
  ` \u26A0 ${entry.id} \u2014 manifest name "${entry.name}" doesn't match export "${actualExports[0]}"`
12034
12506
  )
12035
12507
  );
12036
- console.log(chalk19.dim(` Fix: coherent sync`));
12508
+ console.log(chalk20.dim(` Fix: coherent sync`));
12037
12509
  }
12038
12510
  }
12039
12511
  } catch {
@@ -12048,35 +12520,35 @@ async function checkCommand(opts = {}) {
12048
12520
  if (totalUsage === 0) {
12049
12521
  unused++;
12050
12522
  if (!opts.json) {
12051
- console.log(chalk19.blue(` \u2139 ${entry.id} (${entry.name}) \u2014 registered but not used anywhere`));
12052
- console.log(chalk19.dim(` Remove: coherent components shared remove ${entry.id}`));
12523
+ console.log(chalk20.blue(` \u2139 ${entry.id} (${entry.name}) \u2014 registered but not used anywhere`));
12524
+ console.log(chalk20.dim(` Remove: coherent components shared remove ${entry.id}`));
12053
12525
  }
12054
12526
  } else {
12055
12527
  consistent++;
12056
12528
  const usageDesc = inLayout ? `layout + ${actualUsedIn.length} page(s)` : `${actualUsedIn.length} page(s)`;
12057
12529
  if (!opts.json) {
12058
- const staleNote = isStale ? chalk19.yellow(" [usedIn stale]") : "";
12059
- console.log(chalk19.green(` \u2714 ${entry.id} (${entry.name})`) + chalk19.dim(` \u2014 ${usageDesc}`) + staleNote);
12530
+ const staleNote = isStale ? chalk20.yellow(" [usedIn stale]") : "";
12531
+ console.log(chalk20.green(` \u2714 ${entry.id} (${entry.name})`) + chalk20.dim(` \u2014 ${usageDesc}`) + staleNote);
12060
12532
  }
12061
12533
  }
12062
12534
  }
12063
12535
  const unregistered = findUnregisteredComponents(projectRoot, manifest);
12064
12536
  if (unregistered.length > 0 && !opts.json) {
12065
- console.log(chalk19.cyan(`
12537
+ console.log(chalk20.cyan(`
12066
12538
  \u{1F4E6} Unregistered components found:`));
12067
12539
  for (const comp of unregistered) {
12068
- console.log(chalk19.blue(` \u2139 ${comp.name}`) + chalk19.dim(` \u2014 ${comp.file} (not in manifest)`));
12069
- console.log(chalk19.dim(` Register: coherent sync`));
12540
+ console.log(chalk20.blue(` \u2139 ${comp.name}`) + chalk20.dim(` \u2014 ${comp.file} (not in manifest)`));
12541
+ console.log(chalk20.dim(` Register: coherent sync`));
12070
12542
  }
12071
12543
  }
12072
12544
  const inlineDupes = findInlineDuplicates(projectRoot, manifest);
12073
12545
  if (inlineDupes.length > 0 && !opts.json) {
12074
- console.log(chalk19.cyan(`
12546
+ console.log(chalk20.cyan(`
12075
12547
  \u{1F50D} Inline duplicates:`));
12076
12548
  for (const dup of inlineDupes) {
12077
- console.log(chalk19.yellow(` \u26A0 ${dup.pageFile}`) + chalk19.dim(` has inline ${dup.componentName}`));
12549
+ console.log(chalk20.yellow(` \u26A0 ${dup.pageFile}`) + chalk20.dim(` has inline ${dup.componentName}`));
12078
12550
  console.log(
12079
- chalk19.dim(
12551
+ chalk20.dim(
12080
12552
  ` Use shared: import { ${dup.componentName} } from "@/${dup.sharedFile.replace(".tsx", "")}"`
12081
12553
  )
12082
12554
  );
@@ -12103,24 +12575,24 @@ async function checkCommand(opts = {}) {
12103
12575
  console.log(JSON.stringify(result, null, 2));
12104
12576
  return;
12105
12577
  }
12106
- console.log(chalk19.dim("\n " + "\u2500".repeat(50)));
12578
+ console.log(chalk20.dim("\n " + "\u2500".repeat(50)));
12107
12579
  const summaryParts = [];
12108
12580
  if (!skipPages) {
12109
- summaryParts.push(`${chalk19.green(`${result.pages.clean} clean`)} pages`);
12110
- if (result.pages.withErrors > 0) summaryParts.push(chalk19.red(`${result.pages.withErrors} with errors`));
12111
- if (result.pages.withWarnings > 0) summaryParts.push(chalk19.yellow(`${result.pages.withWarnings} with warnings`));
12581
+ summaryParts.push(`${chalk20.green(`${result.pages.clean} clean`)} pages`);
12582
+ if (result.pages.withErrors > 0) summaryParts.push(chalk20.red(`${result.pages.withErrors} with errors`));
12583
+ if (result.pages.withWarnings > 0) summaryParts.push(chalk20.yellow(`${result.pages.withWarnings} with warnings`));
12112
12584
  }
12113
12585
  if (!skipShared && result.shared.total > 0) {
12114
12586
  summaryParts.push(`${result.shared.consistent} healthy shared`);
12115
12587
  if (result.shared.unused > 0) summaryParts.push(`${result.shared.unused} unused`);
12116
12588
  }
12117
12589
  if (result.links.broken.length > 0) {
12118
- summaryParts.push(chalk19.red(`${result.links.broken.length} broken link(s)`));
12590
+ summaryParts.push(chalk20.red(`${result.links.broken.length} broken link(s)`));
12119
12591
  }
12120
12592
  console.log(`
12121
12593
  ${summaryParts.join(" | ")}`);
12122
12594
  if (result.autoFixable > 0) {
12123
- console.log(chalk19.cyan(`
12595
+ console.log(chalk20.cyan(`
12124
12596
  Auto-fixable: ${result.autoFixable} issues. Run: coherent fix`));
12125
12597
  }
12126
12598
  console.log("");
@@ -12129,21 +12601,21 @@ async function checkCommand(opts = {}) {
12129
12601
  }
12130
12602
 
12131
12603
  // src/commands/repair.ts
12132
- import chalk20 from "chalk";
12604
+ import chalk21 from "chalk";
12133
12605
  async function repairCommand() {
12134
- console.log(chalk20.dim(" \u2139\uFE0F `coherent repair` is deprecated \u2014 use `coherent fix` instead\n"));
12606
+ console.log(chalk21.dim(" \u2139\uFE0F `coherent repair` is deprecated \u2014 use `coherent fix` instead\n"));
12135
12607
  await fixCommand();
12136
12608
  }
12137
12609
 
12138
12610
  // src/commands/doctor.ts
12139
- import chalk21 from "chalk";
12611
+ import chalk22 from "chalk";
12140
12612
  async function doctorCommand() {
12141
- console.log(chalk21.dim(" \u2139\uFE0F `coherent doctor` is deprecated \u2014 use `coherent fix` instead\n"));
12613
+ console.log(chalk22.dim(" \u2139\uFE0F `coherent doctor` is deprecated \u2014 use `coherent fix` instead\n"));
12142
12614
  await fixCommand();
12143
12615
  }
12144
12616
 
12145
12617
  // src/commands/rules.ts
12146
- import chalk22 from "chalk";
12618
+ import chalk23 from "chalk";
12147
12619
  async function rulesCommand() {
12148
12620
  try {
12149
12621
  const result = await regenerateCursorRules();
@@ -12154,31 +12626,31 @@ async function rulesCommand() {
12154
12626
  if (result.sharedCount !== void 0) parts.push(`${result.sharedCount} shared components`);
12155
12627
  if (result.tokenKeys !== void 0) parts.push(`${result.tokenKeys} design token keys`);
12156
12628
  const summary = parts.length > 0 ? ` (${parts.join(", ")})` : "";
12157
- console.log(chalk22.green(`\u2714 Updated .cursorrules and CLAUDE.md${summary}
12629
+ console.log(chalk23.green(`\u2714 Updated .cursorrules and CLAUDE.md${summary}
12158
12630
  `));
12159
12631
  } catch (error) {
12160
- console.error(chalk22.red("\u274C Command failed:"), error instanceof Error ? error.message : "Unknown error");
12632
+ console.error(chalk23.red("\u274C Command failed:"), error instanceof Error ? error.message : "Unknown error");
12161
12633
  process.exit(1);
12162
12634
  }
12163
12635
  }
12164
12636
 
12165
12637
  // src/commands/validate.ts
12166
- import chalk23 from "chalk";
12638
+ import chalk24 from "chalk";
12167
12639
  async function validateCommand() {
12168
- console.log(chalk23.dim(" \u2139\uFE0F `coherent validate` is deprecated \u2014 use `coherent check` instead\n"));
12640
+ console.log(chalk24.dim(" \u2139\uFE0F `coherent validate` is deprecated \u2014 use `coherent check` instead\n"));
12169
12641
  await checkCommand({ pages: true });
12170
12642
  }
12171
12643
 
12172
12644
  // src/commands/audit.ts
12173
- import chalk24 from "chalk";
12645
+ import chalk25 from "chalk";
12174
12646
  async function auditCommand(options) {
12175
- console.log(chalk24.dim(" \u2139\uFE0F `coherent audit` is deprecated \u2014 use `coherent check` instead\n"));
12647
+ console.log(chalk25.dim(" \u2139\uFE0F `coherent audit` is deprecated \u2014 use `coherent check` instead\n"));
12176
12648
  await checkCommand({ shared: true, json: options.json });
12177
12649
  }
12178
12650
 
12179
12651
  // src/commands/components.ts
12180
12652
  import { Command } from "commander";
12181
- import chalk25 from "chalk";
12653
+ import chalk26 from "chalk";
12182
12654
  import {
12183
12655
  DesignSystemManager as DesignSystemManager12,
12184
12656
  ComponentManager as ComponentManager7,
@@ -12229,9 +12701,9 @@ function createComponentsCommand() {
12229
12701
  console.log(JSON.stringify({ shared: manifest.shared, ui: installed2 }, null, 2));
12230
12702
  return;
12231
12703
  }
12232
- console.log(chalk25.bold("\n\u{1F4E6} Shared Components"));
12704
+ console.log(chalk26.bold("\n\u{1F4E6} Shared Components"));
12233
12705
  if (manifest.shared.length === 0) {
12234
- console.log(chalk25.gray(" None yet. Generate pages with header/footer to create them.\n"));
12706
+ console.log(chalk26.gray(" None yet. Generate pages with header/footer to create them.\n"));
12235
12707
  } else {
12236
12708
  const order = { layout: 0, section: 1, widget: 2 };
12237
12709
  const sorted = [...manifest.shared].sort(
@@ -12239,9 +12711,9 @@ function createComponentsCommand() {
12239
12711
  );
12240
12712
  console.log("");
12241
12713
  sorted.forEach((entry) => {
12242
- const usage = entry.usedIn.length === 0 ? chalk25.gray("unused") : entry.usedIn.includes("app/layout.tsx") ? chalk25.green("all pages") : chalk25.gray(entry.usedIn.join(", "));
12714
+ const usage = entry.usedIn.length === 0 ? chalk26.gray("unused") : entry.usedIn.includes("app/layout.tsx") ? chalk26.green("all pages") : chalk26.gray(entry.usedIn.join(", "));
12243
12715
  console.log(
12244
- ` ${chalk25.cyan(entry.id.padEnd(8))} ${chalk25.white(entry.name.padEnd(18))} ${chalk25.gray(entry.type.padEnd(9))} ${usage}`
12716
+ ` ${chalk26.cyan(entry.id.padEnd(8))} ${chalk26.white(entry.name.padEnd(18))} ${chalk26.gray(entry.type.padEnd(9))} ${usage}`
12245
12717
  );
12246
12718
  });
12247
12719
  console.log("");
@@ -12250,24 +12722,24 @@ function createComponentsCommand() {
12250
12722
  const availableShadcn = listShadcnComponents();
12251
12723
  const installedIds = new Set(installed.map((c) => c.id));
12252
12724
  const notInstalled = availableShadcn.filter((id) => !installedIds.has(id));
12253
- console.log(chalk25.bold("\u{1F9E9} UI Components (shadcn)"));
12725
+ console.log(chalk26.bold("\u{1F9E9} UI Components (shadcn)"));
12254
12726
  if (installed.length === 0) {
12255
- console.log(chalk25.gray(" None installed yet.\n"));
12727
+ console.log(chalk26.gray(" None installed yet.\n"));
12256
12728
  } else {
12257
12729
  const names = installed.map((c) => c.name).sort();
12258
- console.log(chalk25.green(` Installed (${names.length}): `) + chalk25.white(names.join(", ")));
12730
+ console.log(chalk26.green(` Installed (${names.length}): `) + chalk26.white(names.join(", ")));
12259
12731
  }
12260
12732
  if (notInstalled.length > 0) {
12261
- console.log(chalk25.gray(` Available (${notInstalled.length}): `) + chalk25.gray(notInstalled.join(", ")));
12733
+ console.log(chalk26.gray(` Available (${notInstalled.length}): `) + chalk26.gray(notInstalled.join(", ")));
12262
12734
  }
12263
12735
  console.log("");
12264
- console.log(chalk25.cyan("\u{1F4A1} Commands:"));
12265
- console.log(chalk25.white(' coherent chat "add a testimonial component"'));
12266
- console.log(chalk25.white(' coherent chat --component "Header" "add a search button"'));
12736
+ console.log(chalk26.cyan("\u{1F4A1} Commands:"));
12737
+ console.log(chalk26.white(' coherent chat "add a testimonial component"'));
12738
+ console.log(chalk26.white(' coherent chat --component "Header" "add a search button"'));
12267
12739
  console.log("");
12268
12740
  });
12269
12741
  cmd.command("add <name>").description("Install a specific component").action(async (name) => {
12270
- console.log(chalk25.yellow(`
12742
+ console.log(chalk26.yellow(`
12271
12743
  \u{1F4A1} Use: coherent chat "add ${name} component"
12272
12744
  `));
12273
12745
  });
@@ -12280,25 +12752,25 @@ function createComponentsCommand() {
12280
12752
  console.log(JSON.stringify(manifest, null, 2));
12281
12753
  return;
12282
12754
  }
12283
- console.log(chalk25.bold("\n\u{1F4E6} Shared Components\n"));
12755
+ console.log(chalk26.bold("\n\u{1F4E6} Shared Components\n"));
12284
12756
  if (manifest.shared.length === 0) {
12285
- console.log(chalk25.yellow(" No shared components yet.\n"));
12286
- console.log(chalk25.gray(' Create via chat: coherent chat "add a page with header and footer"\n'));
12757
+ console.log(chalk26.yellow(" No shared components yet.\n"));
12758
+ console.log(chalk26.gray(' Create via chat: coherent chat "add a page with header and footer"\n'));
12287
12759
  return;
12288
12760
  }
12289
12761
  const order = { layout: 0, section: 1, widget: 2 };
12290
12762
  const sorted = [...manifest.shared].sort((a, b) => order[a.type] - order[b.type] || a.name.localeCompare(b.name));
12291
12763
  sorted.forEach((entry) => {
12292
- const usedIn = entry.usedIn.length === 0 ? chalk25.gray("(not used yet)") : entry.usedIn.length === 1 && entry.usedIn[0] === "app/layout.tsx" ? chalk25.gray("layout.tsx (all pages)") : chalk25.gray(`used in: ${entry.usedIn.join(", ")}`);
12293
- console.log(chalk25.cyan(` ${entry.id}`), chalk25.white(entry.name), chalk25.gray(entry.type));
12764
+ const usedIn = entry.usedIn.length === 0 ? chalk26.gray("(not used yet)") : entry.usedIn.length === 1 && entry.usedIn[0] === "app/layout.tsx" ? chalk26.gray("layout.tsx (all pages)") : chalk26.gray(`used in: ${entry.usedIn.join(", ")}`);
12765
+ console.log(chalk26.cyan(` ${entry.id}`), chalk26.white(entry.name), chalk26.gray(entry.type));
12294
12766
  if (opts.verbose) {
12295
- console.log(chalk25.gray(` file: ${entry.file}`));
12296
- if (entry.description) console.log(chalk25.gray(` ${entry.description}`));
12767
+ console.log(chalk26.gray(` file: ${entry.file}`));
12768
+ if (entry.description) console.log(chalk26.gray(` ${entry.description}`));
12297
12769
  }
12298
- console.log(chalk25.gray(` ${usedIn}`));
12770
+ console.log(chalk26.gray(` ${usedIn}`));
12299
12771
  console.log("");
12300
12772
  });
12301
- console.log(chalk25.cyan("\u{1F4A1} Modify by ID:"), chalk25.white('coherent chat "in CID-001 add a search button"\n'));
12773
+ console.log(chalk26.cyan("\u{1F4A1} Modify by ID:"), chalk26.white('coherent chat "in CID-001 add a search button"\n'));
12302
12774
  });
12303
12775
  sharedCmd.command("add <name>").description("Create a shared component (layout/section/widget) and register in manifest").option("-t, --type <type>", "Type: layout | section | widget", "layout").option("-d, --description <desc>", "Description").action(async (name, opts) => {
12304
12776
  const project = findConfig();
@@ -12310,12 +12782,12 @@ function createComponentsCommand() {
12310
12782
  description: opts.description,
12311
12783
  usedIn: type === "layout" ? ["app/layout.tsx"] : []
12312
12784
  });
12313
- console.log(chalk25.green(`
12785
+ console.log(chalk26.green(`
12314
12786
  \u2705 Created ${result.id} (${result.name}) at ${result.file}
12315
12787
  `));
12316
12788
  if (type === "layout") {
12317
12789
  const updated = await integrateSharedLayoutIntoRootLayout3(project.root);
12318
- if (updated) console.log(chalk25.cyan(" Updated app/layout.tsx to use shared layout components.\n"));
12790
+ if (updated) console.log(chalk26.cyan(" Updated app/layout.tsx to use shared layout components.\n"));
12319
12791
  }
12320
12792
  const sharedPagePath = resolve14(project.root, "app/design-system/shared/page.tsx");
12321
12793
  if (!existsSync23(sharedPagePath)) {
@@ -12325,23 +12797,23 @@ function createComponentsCommand() {
12325
12797
  const config2 = dsm.getConfig();
12326
12798
  const written = await writeDesignSystemFiles(project.root, config2, { sharedOnly: true });
12327
12799
  if (written.length > 0) {
12328
- console.log(chalk25.cyan(" Added Design System shared pages: /design-system/shared\n"));
12800
+ console.log(chalk26.cyan(" Added Design System shared pages: /design-system/shared\n"));
12329
12801
  }
12330
12802
  } catch (e) {
12331
- if (process.env.COHERENT_DEBUG === "1") console.error(chalk25.dim("DS shared pages write failed:"), e);
12803
+ if (process.env.COHERENT_DEBUG === "1") console.error(chalk26.dim("DS shared pages write failed:"), e);
12332
12804
  }
12333
12805
  }
12334
12806
  try {
12335
12807
  await writeCursorRules(project.root);
12336
12808
  } catch (e) {
12337
- if (process.env.COHERENT_DEBUG === "1") console.error(chalk25.dim("Could not update .cursorrules:"), e);
12809
+ if (process.env.COHERENT_DEBUG === "1") console.error(chalk26.dim("Could not update .cursorrules:"), e);
12338
12810
  }
12339
12811
  });
12340
12812
  return cmd;
12341
12813
  }
12342
12814
 
12343
12815
  // src/commands/import-cmd.ts
12344
- import chalk26 from "chalk";
12816
+ import chalk27 from "chalk";
12345
12817
  import ora6 from "ora";
12346
12818
  import { writeFile as writeFile7, mkdir as mkdir7 } from "fs/promises";
12347
12819
  import { resolve as resolve15, join as join18, dirname as dirname9 } from "path";
@@ -12446,25 +12918,25 @@ function createImportCommand() {
12446
12918
  }
12447
12919
  async function importFigmaAction(urlOrKey, opts) {
12448
12920
  if (typeof urlOrKey !== "string" || !urlOrKey.trim()) {
12449
- console.error(chalk26.red("\n\u274C Figma URL or file key is required.\n"));
12450
- console.log(chalk26.dim(" Usage: coherent import figma <url-or-key> --token <your-token>\n"));
12921
+ console.error(chalk27.red("\n\u274C Figma URL or file key is required.\n"));
12922
+ console.log(chalk27.dim(" Usage: coherent import figma <url-or-key> --token <your-token>\n"));
12451
12923
  process.exit(1);
12452
12924
  }
12453
12925
  const token = opts.token ?? process.env.FIGMA_ACCESS_TOKEN ?? process.env.FIGMA_TOKEN;
12454
12926
  if (!token || typeof token !== "string") {
12455
- console.error(chalk26.red("\n\u274C Figma token required.\n"));
12456
- console.log(chalk26.dim(" Use: coherent import figma <url-or-key> --token <your-token>"));
12457
- console.log(chalk26.dim(" Or set FIGMA_ACCESS_TOKEN or FIGMA_TOKEN in your environment.\n"));
12458
- console.log(chalk26.dim(" Get a token: Figma \u2192 Settings \u2192 Personal access tokens.\n"));
12927
+ console.error(chalk27.red("\n\u274C Figma token required.\n"));
12928
+ console.log(chalk27.dim(" Use: coherent import figma <url-or-key> --token <your-token>"));
12929
+ console.log(chalk27.dim(" Or set FIGMA_ACCESS_TOKEN or FIGMA_TOKEN in your environment.\n"));
12930
+ console.log(chalk27.dim(" Get a token: Figma \u2192 Settings \u2192 Personal access tokens.\n"));
12459
12931
  process.exit(1);
12460
12932
  }
12461
12933
  const generatePages = opts.pages !== false;
12462
12934
  const dryRun = Boolean(opts.dryRun);
12463
12935
  const fileKey = FigmaClient.extractFileKey(urlOrKey);
12464
12936
  if (!fileKey) {
12465
- console.error(chalk26.red("\n\u274C Invalid Figma URL or file key.\n"));
12466
- console.log(chalk26.dim(" Use a URL like: https://www.figma.com/file/ABC123/MyDesign"));
12467
- console.log(chalk26.dim(" Or the file key: ABC123\n"));
12937
+ console.error(chalk27.red("\n\u274C Invalid Figma URL or file key.\n"));
12938
+ console.log(chalk27.dim(" Use a URL like: https://www.figma.com/file/ABC123/MyDesign"));
12939
+ console.log(chalk27.dim(" Or the file key: ABC123\n"));
12468
12940
  process.exit(1);
12469
12941
  }
12470
12942
  const project = findConfig();
@@ -12641,7 +13113,7 @@ export const config = ${JSON.stringify(fullConfig, null, 2)} as const
12641
13113
  try {
12642
13114
  await writeCursorRules(projectRoot);
12643
13115
  } catch (e) {
12644
- if (process.env.COHERENT_DEBUG === "1") console.error(chalk26.dim("Could not update .cursorrules:"), e);
13116
+ if (process.env.COHERENT_DEBUG === "1") console.error(chalk27.dim("Could not update .cursorrules:"), e);
12645
13117
  }
12646
13118
  } else {
12647
13119
  stats.filesWritten.push(DESIGN_SYSTEM_CONFIG_PATH);
@@ -12651,7 +13123,7 @@ export const config = ${JSON.stringify(fullConfig, null, 2)} as const
12651
13123
  } catch (err) {
12652
13124
  spinner.fail("Import failed");
12653
13125
  const message = err instanceof Error ? err.message : String(err);
12654
- console.error(chalk26.red("\n\u274C " + message + "\n"));
13126
+ console.error(chalk27.red("\n\u274C " + message + "\n"));
12655
13127
  process.exit(1);
12656
13128
  }
12657
13129
  }
@@ -12659,36 +13131,36 @@ function printReport(stats, opts) {
12659
13131
  const { dryRun, generatePages, fileName } = opts;
12660
13132
  console.log("");
12661
13133
  if (dryRun) {
12662
- console.log(chalk26.yellow("\u2550\u2550\u2550 Dry run (no files written) \u2550\u2550\u2550"));
13134
+ console.log(chalk27.yellow("\u2550\u2550\u2550 Dry run (no files written) \u2550\u2550\u2550"));
12663
13135
  console.log("");
12664
13136
  }
12665
- console.log(chalk26.green("\u2705 Figma import complete"));
13137
+ console.log(chalk27.green("\u2705 Figma import complete"));
12666
13138
  console.log("");
12667
- console.log(chalk26.cyan(" Statistics"));
12668
- console.log(chalk26.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
12669
- console.log(chalk26.blue(` File: ${fileName}`));
12670
- console.log(chalk26.blue(` Color styles: ${stats.colorStyles}`));
12671
- console.log(chalk26.blue(` Text styles: ${stats.textStyles}`));
13139
+ console.log(chalk27.cyan(" Statistics"));
13140
+ console.log(chalk27.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
13141
+ console.log(chalk27.blue(` File: ${fileName}`));
13142
+ console.log(chalk27.blue(` Color styles: ${stats.colorStyles}`));
13143
+ console.log(chalk27.blue(` Text styles: ${stats.textStyles}`));
12672
13144
  console.log(
12673
- chalk26.blue(` Components: ${stats.componentsTotal} (${stats.baseCount} \u2192 base, ${stats.sharedCount} \u2192 shared)`)
13145
+ chalk27.blue(` Components: ${stats.componentsTotal} (${stats.baseCount} \u2192 base, ${stats.sharedCount} \u2192 shared)`)
12674
13146
  );
12675
- console.log(chalk26.blue(` Pages: ${stats.pagesGenerated}${!generatePages ? " (skipped by --no-pages)" : ""}`));
12676
- console.log(chalk26.blue(` design-system.config: ${stats.configUpdated ? "updated" : "\u2014"}`));
12677
- console.log(chalk26.blue(` Layout (Header/Footer): ${stats.layoutIntegrated ? "integrated" : "\u2014"}`));
12678
- console.log(chalk26.blue(` DS viewer files: ${stats.dsFilesWritten}`));
13147
+ console.log(chalk27.blue(` Pages: ${stats.pagesGenerated}${!generatePages ? " (skipped by --no-pages)" : ""}`));
13148
+ console.log(chalk27.blue(` design-system.config: ${stats.configUpdated ? "updated" : "\u2014"}`));
13149
+ console.log(chalk27.blue(` Layout (Header/Footer): ${stats.layoutIntegrated ? "integrated" : "\u2014"}`));
13150
+ console.log(chalk27.blue(` DS viewer files: ${stats.dsFilesWritten}`));
12679
13151
  console.log(
12680
- chalk26.blue(` Total files ${dryRun ? "that would be written" : "written"}: ${stats.filesWritten.length}`)
13152
+ chalk27.blue(` Total files ${dryRun ? "that would be written" : "written"}: ${stats.filesWritten.length}`)
12681
13153
  );
12682
13154
  console.log("");
12683
13155
  if (stats.filesWritten.length > 0 && stats.filesWritten.length <= 30) {
12684
- console.log(chalk26.dim(" Files:"));
12685
- stats.filesWritten.forEach((f) => console.log(chalk26.dim(` ${f}`)));
13156
+ console.log(chalk27.dim(" Files:"));
13157
+ stats.filesWritten.forEach((f) => console.log(chalk27.dim(` ${f}`)));
12686
13158
  console.log("");
12687
13159
  }
12688
13160
  }
12689
13161
 
12690
13162
  // src/commands/ds.ts
12691
- import chalk27 from "chalk";
13163
+ import chalk28 from "chalk";
12692
13164
  import ora7 from "ora";
12693
13165
  import { DesignSystemManager as DesignSystemManager14 } from "@getcoherent/core";
12694
13166
  async function dsRegenerateCommand() {
@@ -12703,18 +13175,18 @@ async function dsRegenerateCommand() {
12703
13175
  const config2 = dsm.getConfig();
12704
13176
  const written = await writeDesignSystemFiles(project.root, config2);
12705
13177
  spinner.succeed(`Regenerated ${written.length} Design System file(s)`);
12706
- console.log(chalk27.gray(" app/design-system/* and app/api/design-system/*\n"));
12707
- console.log(chalk27.cyan(" Open /design-system in the app to view.\n"));
13178
+ console.log(chalk28.gray(" app/design-system/* and app/api/design-system/*\n"));
13179
+ console.log(chalk28.cyan(" Open /design-system in the app to view.\n"));
12708
13180
  } catch (error) {
12709
- console.error(chalk27.red("\u274C Command failed:"), error instanceof Error ? error.message : "Unknown error");
13181
+ console.error(chalk28.red("\u274C Command failed:"), error instanceof Error ? error.message : "Unknown error");
12710
13182
  process.exit(1);
12711
13183
  }
12712
13184
  }
12713
13185
 
12714
13186
  // src/commands/update.ts
12715
- import chalk28 from "chalk";
13187
+ import chalk29 from "chalk";
12716
13188
  import ora8 from "ora";
12717
- import { readFileSync as readFileSync16, existsSync as existsSync25 } from "fs";
13189
+ import { readFileSync as readFileSync17, existsSync as existsSync25 } from "fs";
12718
13190
  import { join as join19 } from "path";
12719
13191
  import { DesignSystemManager as DesignSystemManager15, CLI_VERSION as CLI_VERSION4 } from "@getcoherent/core";
12720
13192
 
@@ -12764,14 +13236,14 @@ async function updateCommand(opts) {
12764
13236
  const projectVersion = config2.coherentVersion || "0.0.0";
12765
13237
  if (compareSemver(projectVersion, CLI_VERSION4) === 0) {
12766
13238
  spinner.succeed("Project is already up to date");
12767
- console.log(chalk28.gray(` Version: v${CLI_VERSION4}
13239
+ console.log(chalk29.gray(` Version: v${CLI_VERSION4}
12768
13240
  `));
12769
13241
  return;
12770
13242
  }
12771
13243
  if (compareSemver(projectVersion, CLI_VERSION4) > 0) {
12772
13244
  spinner.warn("Project was created with a newer CLI version");
12773
- console.log(chalk28.yellow(` Project: v${projectVersion} \u2192 CLI: v${CLI_VERSION4}`));
12774
- console.log(chalk28.yellow(" Update your CLI: npm install -g @getcoherent/cli@latest\n"));
13245
+ console.log(chalk29.yellow(` Project: v${projectVersion} \u2192 CLI: v${CLI_VERSION4}`));
13246
+ console.log(chalk29.yellow(" Update your CLI: npm install -g @getcoherent/cli@latest\n"));
12775
13247
  return;
12776
13248
  }
12777
13249
  const report = {
@@ -12817,36 +13289,36 @@ async function updateCommand(opts) {
12817
13289
  }
12818
13290
  function printReport2(report) {
12819
13291
  const from = report.fromVersion ? `v${report.fromVersion}` : "unknown";
12820
- console.log(chalk28.green(`
13292
+ console.log(chalk29.green(`
12821
13293
  \u2714 Project updated: ${from} \u2192 v${report.toVersion}
12822
13294
  `));
12823
13295
  if (report.overlayFiles > 0) {
12824
- console.log(chalk28.white(` \u2714 Regenerated platform overlay (${report.overlayFiles} files)`));
13296
+ console.log(chalk29.white(` \u2714 Regenerated platform overlay (${report.overlayFiles} files)`));
12825
13297
  }
12826
13298
  if (report.migrationsApplied.length > 0) {
12827
13299
  for (const desc of report.migrationsApplied) {
12828
- console.log(chalk28.white(` \u2714 Migrated config: ${desc}`));
13300
+ console.log(chalk29.white(` \u2714 Migrated config: ${desc}`));
12829
13301
  }
12830
13302
  }
12831
13303
  if (report.rulesUpdated) {
12832
- console.log(chalk28.white(" \u2714 Updated .cursorrules and CLAUDE.md"));
13304
+ console.log(chalk29.white(" \u2714 Updated .cursorrules and CLAUDE.md"));
12833
13305
  }
12834
13306
  if (report.missingCssVars.length > 0) {
12835
13307
  console.log("");
12836
- console.log(chalk28.yellow(" \u26A0 New CSS variables available in globals.css:"));
13308
+ console.log(chalk29.yellow(" \u26A0 New CSS variables available in globals.css:"));
12837
13309
  for (const v of report.missingCssVars.slice(0, 10)) {
12838
- console.log(chalk28.gray(` ${v}`));
13310
+ console.log(chalk29.gray(` ${v}`));
12839
13311
  }
12840
13312
  if (report.missingCssVars.length > 10) {
12841
- console.log(chalk28.gray(` ... and ${report.missingCssVars.length - 10} more`));
13313
+ console.log(chalk29.gray(` ... and ${report.missingCssVars.length - 10} more`));
12842
13314
  }
12843
13315
  console.log("");
12844
- console.log(chalk28.cyan(" To add them automatically:"));
12845
- console.log(chalk28.white(" coherent update --patch-globals\n"));
13316
+ console.log(chalk29.cyan(" To add them automatically:"));
13317
+ console.log(chalk29.white(" coherent update --patch-globals\n"));
12846
13318
  }
12847
13319
  console.log("");
12848
- console.log(chalk28.dim(" Your pages and components were NOT modified."));
12849
- console.log(chalk28.dim(" Run `coherent check` to check existing pages against new rules.\n"));
13320
+ console.log(chalk29.dim(" Your pages and components were NOT modified."));
13321
+ console.log(chalk29.dim(" Run `coherent check` to check existing pages against new rules.\n"));
12850
13322
  }
12851
13323
  var EXPECTED_CSS_VARS = [
12852
13324
  "--background",
@@ -12887,7 +13359,7 @@ function checkMissingCssVars(projectRoot) {
12887
13359
  const globalsPath = join19(projectRoot, "app", "globals.css");
12888
13360
  if (!existsSync25(globalsPath)) return [];
12889
13361
  try {
12890
- const content = readFileSync16(globalsPath, "utf-8");
13362
+ const content = readFileSync17(globalsPath, "utf-8");
12891
13363
  return EXPECTED_CSS_VARS.filter((v) => !content.includes(v));
12892
13364
  } catch {
12893
13365
  return [];
@@ -12897,7 +13369,7 @@ function patchGlobalsCss(projectRoot, missingVars) {
12897
13369
  const globalsPath = join19(projectRoot, "app", "globals.css");
12898
13370
  if (!existsSync25(globalsPath) || missingVars.length === 0) return;
12899
13371
  const { writeFileSync: writeFileSync14 } = __require("fs");
12900
- let content = readFileSync16(globalsPath, "utf-8");
13372
+ let content = readFileSync17(globalsPath, "utf-8");
12901
13373
  const defaultValues = {
12902
13374
  "--chart-1": "220 70% 50%",
12903
13375
  "--chart-2": "160 60% 45%",
@@ -12930,7 +13402,7 @@ function patchGlobalsCss(projectRoot, missingVars) {
12930
13402
  }
12931
13403
 
12932
13404
  // src/commands/undo.ts
12933
- import chalk29 from "chalk";
13405
+ import chalk30 from "chalk";
12934
13406
  async function undoCommand(options) {
12935
13407
  try {
12936
13408
  const project = findConfig();
@@ -12939,43 +13411,43 @@ async function undoCommand(options) {
12939
13411
  const backups = listBackups(projectRoot);
12940
13412
  if (options.list) {
12941
13413
  if (backups.length === 0) {
12942
- console.log(chalk29.yellow("No backups found."));
13414
+ console.log(chalk30.yellow("No backups found."));
12943
13415
  return;
12944
13416
  }
12945
- console.log(chalk29.bold("\n\u{1F4E6} Available backups:\n"));
13417
+ console.log(chalk30.bold("\n\u{1F4E6} Available backups:\n"));
12946
13418
  for (const b of backups) {
12947
13419
  const date = new Date(b.timestamp);
12948
13420
  const timeStr = date.toLocaleString();
12949
- console.log(chalk29.white(` ${b.name}`));
12950
- console.log(chalk29.dim(` ${timeStr} \u2014 ${b.files} file(s)`));
13421
+ console.log(chalk30.white(` ${b.name}`));
13422
+ console.log(chalk30.dim(` ${timeStr} \u2014 ${b.files} file(s)`));
12951
13423
  console.log();
12952
13424
  }
12953
13425
  return;
12954
13426
  }
12955
13427
  if (backups.length === 0) {
12956
- console.log(chalk29.yellow("No backups found. Nothing to undo."));
13428
+ console.log(chalk30.yellow("No backups found. Nothing to undo."));
12957
13429
  return;
12958
13430
  }
12959
13431
  const latest = backups[0];
12960
13432
  const ok = restoreBackup(projectRoot, latest.name);
12961
13433
  if (!ok) {
12962
- console.log(chalk29.red("Failed to restore backup."));
13434
+ console.log(chalk30.red("Failed to restore backup."));
12963
13435
  return;
12964
13436
  }
12965
- console.log(chalk29.green("\n\u2705 Restored to previous state:\n"));
12966
- console.log(chalk29.dim(` Snapshot: ${new Date(latest.timestamp).toLocaleString()}`));
12967
- console.log(chalk29.dim(` Files: ${latest.files} restored`));
12968
- console.log(chalk29.cyan("\n Run: coherent preview\n"));
13437
+ console.log(chalk30.green("\n\u2705 Restored to previous state:\n"));
13438
+ console.log(chalk30.dim(` Snapshot: ${new Date(latest.timestamp).toLocaleString()}`));
13439
+ console.log(chalk30.dim(` Files: ${latest.files} restored`));
13440
+ console.log(chalk30.cyan("\n Run: coherent preview\n"));
12969
13441
  } catch (error) {
12970
- console.error(chalk29.red("\u274C Undo failed:"), error instanceof Error ? error.message : "Unknown error");
13442
+ console.error(chalk30.red("\u274C Undo failed:"), error instanceof Error ? error.message : "Unknown error");
12971
13443
  process.exit(1);
12972
13444
  }
12973
13445
  }
12974
13446
 
12975
13447
  // src/commands/sync.ts
12976
- import chalk30 from "chalk";
13448
+ import chalk31 from "chalk";
12977
13449
  import ora9 from "ora";
12978
- import { existsSync as existsSync26, readFileSync as readFileSync17 } from "fs";
13450
+ import { existsSync as existsSync26, readFileSync as readFileSync18 } from "fs";
12979
13451
  import { join as join20, relative as relative5, dirname as dirname10 } from "path";
12980
13452
  import { readdir as readdir4, readFile as readFile7 } from "fs/promises";
12981
13453
  import { DesignSystemManager as DesignSystemManager16 } from "@getcoherent/core";
@@ -12985,7 +13457,7 @@ function extractTokensFromProject(projectRoot) {
12985
13457
  const darkColors = {};
12986
13458
  const globalsPath = join20(projectRoot, "app", "globals.css");
12987
13459
  if (existsSync26(globalsPath)) {
12988
- const css = readFileSync17(globalsPath, "utf-8");
13460
+ const css = readFileSync18(globalsPath, "utf-8");
12989
13461
  const rootMatch = css.match(/:root\s*\{([^}]+)\}/s);
12990
13462
  if (rootMatch) parseVarsInto(rootMatch[1], lightColors);
12991
13463
  const darkMatch = css.match(/\.dark\s*\{([^}]+)\}/s);
@@ -12994,7 +13466,7 @@ function extractTokensFromProject(projectRoot) {
12994
13466
  const layoutPath = join20(projectRoot, "app", "layout.tsx");
12995
13467
  let layoutCode = "";
12996
13468
  if (existsSync26(layoutPath)) {
12997
- layoutCode = readFileSync17(layoutPath, "utf-8");
13469
+ layoutCode = readFileSync18(layoutPath, "utf-8");
12998
13470
  const rootInline = layoutCode.match(/:root\s*\{([^}]+)\}/s);
12999
13471
  if (rootInline && Object.keys(lightColors).length === 0) {
13000
13472
  parseVarsInto(rootInline[1], lightColors);
@@ -13012,7 +13484,7 @@ function extractTokensFromProject(projectRoot) {
13012
13484
  defaultMode = "dark";
13013
13485
  }
13014
13486
  let radius;
13015
- const allCss = [existsSync26(globalsPath) ? readFileSync17(globalsPath, "utf-8") : "", layoutCode].join("\n");
13487
+ const allCss = [existsSync26(globalsPath) ? readFileSync18(globalsPath, "utf-8") : "", layoutCode].join("\n");
13016
13488
  const radiusMatch = allCss.match(/--radius:\s*([^;]+);/);
13017
13489
  if (radiusMatch) radius = radiusMatch[1].trim();
13018
13490
  return {
@@ -13211,7 +13683,7 @@ async function syncCommand(options = {}) {
13211
13683
  const doTokens = runAll || options.tokens === true;
13212
13684
  const doComponents = runAll || options.components === true;
13213
13685
  const doPatterns = runAll || options.patterns === true;
13214
- if (dryRun) console.log(chalk30.yellow(" [dry-run] No files will be written\n"));
13686
+ if (dryRun) console.log(chalk31.yellow(" [dry-run] No files will be written\n"));
13215
13687
  const spinner = ora9("Scanning project files...").start();
13216
13688
  try {
13217
13689
  const appDir = join20(project.root, "app");
@@ -13352,84 +13824,84 @@ async function syncCommand(options = {}) {
13352
13824
  spinner.succeed("Updated .cursorrules and CLAUDE.md");
13353
13825
  }
13354
13826
  console.log("");
13355
- console.log(chalk30.green(`\u2705 Design System ${dryRun ? "analyzed" : "synced"} with actual code
13827
+ console.log(chalk31.green(`\u2705 Design System ${dryRun ? "analyzed" : "synced"} with actual code
13356
13828
  `));
13357
- console.log(chalk30.blue("\u{1F4C4} Pages:"));
13829
+ console.log(chalk31.blue("\u{1F4C4} Pages:"));
13358
13830
  for (const page of discoveredPages) {
13359
13831
  const a = analyzePageCode(page.code);
13360
13832
  const comps = Object.entries(a.componentUsage || {}).filter(([, c]) => c > 0).map(([n]) => n);
13361
- console.log(chalk30.gray(` ${page.route} \u2014 ${page.name}`));
13362
- if (comps.length > 0) console.log(chalk30.gray(` Components: ${comps.join(", ")}`));
13363
- if (a.sections?.length) console.log(chalk30.gray(` Sections: ${a.sections.map((s) => s.name).join(", ")}`));
13833
+ console.log(chalk31.gray(` ${page.route} \u2014 ${page.name}`));
13834
+ if (comps.length > 0) console.log(chalk31.gray(` Components: ${comps.join(", ")}`));
13835
+ if (a.sections?.length) console.log(chalk31.gray(` Sections: ${a.sections.map((s) => s.name).join(", ")}`));
13364
13836
  }
13365
13837
  if (doTokens && extractedTokens) {
13366
13838
  console.log("");
13367
- console.log(chalk30.blue("\u{1F3A8} Design Tokens (from globals.css):"));
13839
+ console.log(chalk31.blue("\u{1F3A8} Design Tokens (from globals.css):"));
13368
13840
  const lc = Object.keys(extractedTokens.colors.light).length;
13369
13841
  const dc = Object.keys(extractedTokens.colors.dark).length;
13370
- console.log(chalk30.gray(` Light: ${lc} variables | Dark: ${dc} variables`));
13371
- console.log(chalk30.gray(` Default mode: ${extractedTokens.defaultMode}`));
13372
- if (extractedTokens.radius) console.log(chalk30.gray(` Border radius: ${extractedTokens.radius}`));
13842
+ console.log(chalk31.gray(` Light: ${lc} variables | Dark: ${dc} variables`));
13843
+ console.log(chalk31.gray(` Default mode: ${extractedTokens.defaultMode}`));
13844
+ if (extractedTokens.radius) console.log(chalk31.gray(` Border radius: ${extractedTokens.radius}`));
13373
13845
  }
13374
13846
  if (doComponents && reconcileResult) {
13375
13847
  console.log("");
13376
- console.log(chalk30.blue("\u{1F9E9} Shared Components:"));
13848
+ console.log(chalk31.blue("\u{1F9E9} Shared Components:"));
13377
13849
  for (const r of reconcileResult.removed) {
13378
- console.log(chalk30.red(` \u{1F5D1} Removed ${r.id} (${r.name}) \u2014 ${r.reason}`));
13850
+ console.log(chalk31.red(` \u{1F5D1} Removed ${r.id} (${r.name}) \u2014 ${r.reason}`));
13379
13851
  }
13380
13852
  for (const u of reconcileResult.updated) {
13381
- console.log(chalk30.cyan(` \u{1F4DD} Updated ${u.id} ${u.field}: ${u.from} \u2192 ${u.to}`));
13853
+ console.log(chalk31.cyan(` \u{1F4DD} Updated ${u.id} ${u.field}: ${u.from} \u2192 ${u.to}`));
13382
13854
  }
13383
13855
  for (const a of reconcileResult.added) {
13384
- console.log(chalk30.green(` \u2728 Added ${a.id} (${a.name}) \u2014 ${a.file} (${a.type})`));
13856
+ console.log(chalk31.green(` \u2728 Added ${a.id} (${a.name}) \u2014 ${a.file} (${a.type})`));
13385
13857
  }
13386
13858
  for (const w of reconcileResult.warnings) {
13387
- console.log(chalk30.yellow(` \u26A0 ${w.message}`));
13388
- console.log(chalk30.dim(` ${w.suggestion}`));
13859
+ console.log(chalk31.yellow(` \u26A0 ${w.message}`));
13860
+ console.log(chalk31.dim(` ${w.suggestion}`));
13389
13861
  }
13390
13862
  if (reconcileResult.removed.length === 0 && reconcileResult.updated.length === 0 && reconcileResult.added.length === 0 && reconcileResult.warnings.length === 0) {
13391
- console.log(chalk30.gray(" All components consistent \u2713"));
13863
+ console.log(chalk31.gray(" All components consistent \u2713"));
13392
13864
  }
13393
13865
  }
13394
13866
  if (doPatterns && Object.keys(stylePatterns).length > 0) {
13395
13867
  console.log("");
13396
- console.log(chalk30.blue("\u{1F4D0} Style Patterns:"));
13397
- if (stylePatterns.card) console.log(chalk30.gray(` Cards: ${stylePatterns.card.slice(0, 80)}`));
13398
- if (stylePatterns.section) console.log(chalk30.gray(` Sections: ${stylePatterns.section}`));
13399
- if (stylePatterns.terminal) console.log(chalk30.gray(` Terminal: ${stylePatterns.terminal.slice(0, 80)}`));
13400
- if (stylePatterns.iconContainer) console.log(chalk30.gray(` Icons: ${stylePatterns.iconContainer.slice(0, 80)}`));
13868
+ console.log(chalk31.blue("\u{1F4D0} Style Patterns:"));
13869
+ if (stylePatterns.card) console.log(chalk31.gray(` Cards: ${stylePatterns.card.slice(0, 80)}`));
13870
+ if (stylePatterns.section) console.log(chalk31.gray(` Sections: ${stylePatterns.section}`));
13871
+ if (stylePatterns.terminal) console.log(chalk31.gray(` Terminal: ${stylePatterns.terminal.slice(0, 80)}`));
13872
+ if (stylePatterns.iconContainer) console.log(chalk31.gray(` Icons: ${stylePatterns.iconContainer.slice(0, 80)}`));
13401
13873
  if (stylePatterns.heroHeadline)
13402
- console.log(chalk30.gray(` Hero headline: ${stylePatterns.heroHeadline.slice(0, 80)}`));
13874
+ console.log(chalk31.gray(` Hero headline: ${stylePatterns.heroHeadline.slice(0, 80)}`));
13403
13875
  if (stylePatterns.sectionTitle)
13404
- console.log(chalk30.gray(` Section title: ${stylePatterns.sectionTitle.slice(0, 80)}`));
13876
+ console.log(chalk31.gray(` Section title: ${stylePatterns.sectionTitle.slice(0, 80)}`));
13405
13877
  }
13406
13878
  const tokenUsage = extractActualTokenUsage(allPageCode);
13407
13879
  if (tokenUsage.colors.length > 0) {
13408
13880
  console.log("");
13409
- console.log(chalk30.blue("\u{1F3F7}\uFE0F Actual token usage (from classNames):"));
13881
+ console.log(chalk31.blue("\u{1F3F7}\uFE0F Actual token usage (from classNames):"));
13410
13882
  console.log(
13411
- chalk30.gray(
13883
+ chalk31.gray(
13412
13884
  ` Colors: ${tokenUsage.colors.slice(0, 12).join(", ")}${tokenUsage.colors.length > 12 ? ` (+${tokenUsage.colors.length - 12})` : ""}`
13413
13885
  )
13414
13886
  );
13415
13887
  console.log(
13416
- chalk30.gray(
13888
+ chalk31.gray(
13417
13889
  ` Typography: ${tokenUsage.typography.slice(0, 8).join(", ")}${tokenUsage.typography.length > 8 ? ` (+${tokenUsage.typography.length - 8})` : ""}`
13418
13890
  )
13419
13891
  );
13420
- console.log(chalk30.gray(` Radius: ${tokenUsage.borderRadius.join(", ")}`));
13892
+ console.log(chalk31.gray(` Radius: ${tokenUsage.borderRadius.join(", ")}`));
13421
13893
  }
13422
13894
  const reusable = extractReusablePatterns(allPageCode);
13423
13895
  if (reusable.length > 0) {
13424
13896
  console.log("");
13425
- console.log(chalk30.blue(`\u{1F501} Repeating patterns (${reusable.length} \u2014 potential reusable components):`));
13897
+ console.log(chalk31.blue(`\u{1F501} Repeating patterns (${reusable.length} \u2014 potential reusable components):`));
13426
13898
  for (const p of reusable.slice(0, 5)) {
13427
- console.log(chalk30.gray(` \xD7${p.count}: ${p.sample}${p.sample.length < p.pattern.length ? "..." : ""}`));
13899
+ console.log(chalk31.gray(` \xD7${p.count}: ${p.sample}${p.sample.length < p.pattern.length ? "..." : ""}`));
13428
13900
  }
13429
13901
  }
13430
13902
  console.log("");
13431
13903
  if (!dryRun) {
13432
- console.log(chalk30.cyan(" Open /design-system in the app to see the updated view."));
13904
+ console.log(chalk31.cyan(" Open /design-system in the app to see the updated view."));
13433
13905
  }
13434
13906
  console.log("");
13435
13907
  } catch (err) {
@@ -13440,9 +13912,9 @@ async function syncCommand(options = {}) {
13440
13912
  }
13441
13913
 
13442
13914
  // src/commands/migrate.ts
13443
- import chalk31 from "chalk";
13915
+ import chalk32 from "chalk";
13444
13916
  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";
13917
+ import { existsSync as existsSync27, mkdirSync as mkdirSync8, cpSync, rmSync as rmSync6, writeFileSync as writeFileSync12, readFileSync as readFileSync19, readdirSync as readdirSync9 } from "fs";
13446
13918
  import { join as join21 } from "path";
13447
13919
  function backupDir(projectRoot) {
13448
13920
  const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
@@ -13477,7 +13949,7 @@ function rollback(projectRoot) {
13477
13949
  const guard = guardPath(projectRoot);
13478
13950
  if (!existsSync27(guard)) return false;
13479
13951
  try {
13480
- const data = JSON.parse(readFileSync18(guard, "utf-8"));
13952
+ const data = JSON.parse(readFileSync19(guard, "utf-8"));
13481
13953
  const backup = data.backup;
13482
13954
  if (!existsSync27(backup)) return false;
13483
13955
  const uiBackup = join21(backup, "components-ui");
@@ -13517,30 +13989,30 @@ async function migrateAction(options) {
13517
13989
  }
13518
13990
  const guard = guardPath(projectRoot);
13519
13991
  if (existsSync27(guard)) {
13520
- console.log(chalk31.yellow("A migration is already in progress."));
13521
- console.log(chalk31.dim("Run `coherent migrate --rollback` to undo, or delete .coherent/migration-in-progress"));
13992
+ console.log(chalk32.yellow("A migration is already in progress."));
13993
+ console.log(chalk32.dim("Run `coherent migrate --rollback` to undo, or delete .coherent/migration-in-progress"));
13522
13994
  return;
13523
13995
  }
13524
13996
  const uiDir = join21(projectRoot, "components", "ui");
13525
13997
  if (!existsSync27(uiDir)) {
13526
- console.log(chalk31.yellow("No components/ui directory found. Nothing to migrate."));
13998
+ console.log(chalk32.yellow("No components/ui directory found. Nothing to migrate."));
13527
13999
  return;
13528
14000
  }
13529
14001
  const provider = getComponentProvider();
13530
14002
  const managedIds = new Set(provider.listNames());
13531
- const files = readdirSync7(uiDir).filter((f) => f.endsWith(".tsx"));
14003
+ const files = readdirSync9(uiDir).filter((f) => f.endsWith(".tsx"));
13532
14004
  const migratable = files.map((f) => f.replace(".tsx", "")).filter((id) => managedIds.has(id));
13533
14005
  if (migratable.length === 0) {
13534
- console.log(chalk31.green("All components are already up to date."));
14006
+ console.log(chalk32.green("All components are already up to date."));
13535
14007
  return;
13536
14008
  }
13537
- console.log(chalk31.cyan(`
14009
+ console.log(chalk32.cyan(`
13538
14010
  Found ${migratable.length} component(s) to migrate:`));
13539
14011
  for (const id of migratable) {
13540
- console.log(chalk31.dim(` - ${id}`));
14012
+ console.log(chalk32.dim(` - ${id}`));
13541
14013
  }
13542
14014
  if (options.dryRun) {
13543
- console.log(chalk31.yellow("\n[dry-run] No changes applied."));
14015
+ console.log(chalk32.yellow("\n[dry-run] No changes applied."));
13544
14016
  return;
13545
14017
  }
13546
14018
  const spinner = ora10("Migrating components...").start();
@@ -13557,12 +14029,12 @@ Found ${migratable.length} component(s) to migrate:`));
13557
14029
  if (result.success) {
13558
14030
  migrated++;
13559
14031
  } else {
13560
- console.warn(chalk31.yellow(` \u26A0 Failed to migrate ${id}`));
14032
+ console.warn(chalk32.yellow(` \u26A0 Failed to migrate ${id}`));
13561
14033
  }
13562
14034
  }
13563
14035
  clearGuard(projectRoot);
13564
14036
  spinner.succeed(`Migrated ${migrated}/${migratable.length} components to real shadcn/ui`);
13565
- console.log(chalk31.dim(` Backup saved to: ${backup}`));
14037
+ console.log(chalk32.dim(` Backup saved to: ${backup}`));
13566
14038
  } catch (err) {
13567
14039
  spinner.fail("Migration failed \u2014 rolling back");
13568
14040
  rollback(projectRoot);
@@ -13571,10 +14043,10 @@ Found ${migratable.length} component(s) to migrate:`));
13571
14043
  }
13572
14044
 
13573
14045
  // src/utils/update-notifier.ts
13574
- import { existsSync as existsSync28, mkdirSync as mkdirSync9, readFileSync as readFileSync19, writeFileSync as writeFileSync13 } from "fs";
14046
+ import { existsSync as existsSync28, mkdirSync as mkdirSync9, readFileSync as readFileSync20, writeFileSync as writeFileSync13 } from "fs";
13575
14047
  import { join as join22 } from "path";
13576
14048
  import { homedir } from "os";
13577
- import chalk32 from "chalk";
14049
+ import chalk33 from "chalk";
13578
14050
  import { CLI_VERSION as CLI_VERSION5 } from "@getcoherent/core";
13579
14051
  var DEBUG5 = process.env.COHERENT_DEBUG === "1";
13580
14052
  var PACKAGE_NAME = "@getcoherent/cli";
@@ -13584,7 +14056,7 @@ var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
13584
14056
  function readCache() {
13585
14057
  try {
13586
14058
  if (!existsSync28(CACHE_FILE)) return null;
13587
- const raw = readFileSync19(CACHE_FILE, "utf-8");
14059
+ const raw = readFileSync20(CACHE_FILE, "utf-8");
13588
14060
  return JSON.parse(raw);
13589
14061
  } catch (e) {
13590
14062
  if (DEBUG5) console.error("Failed to read update cache:", e);
@@ -13645,8 +14117,8 @@ async function checkForUpdates() {
13645
14117
  }
13646
14118
  function printUpdateNotice(latest) {
13647
14119
  console.log(
13648
- chalk32.yellow(`
13649
- \u2B06 Update available: v${CLI_VERSION5} \u2192 v${latest}`) + chalk32.dim(`
14120
+ chalk33.yellow(`
14121
+ \u2B06 Update available: v${CLI_VERSION5} \u2192 v${latest}`) + chalk33.dim(`
13650
14122
  Run: npm update -g ${PACKAGE_NAME}
13651
14123
  `)
13652
14124
  );