@decantr/cli 2.5.1 → 2.7.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.
@@ -20,6 +20,8 @@ import {
20
20
  createDoctrineMap,
21
21
  getCliTelemetryIdentityStatus,
22
22
  isOptedIn,
23
+ loadBundledContentItem,
24
+ loadBundledContentList,
23
25
  optIn,
24
26
  scanAmbientContext,
25
27
  scanProjectInteractions,
@@ -29,11 +31,11 @@ import {
29
31
  sendCliCommandTelemetry,
30
32
  sendNewProjectCompletedTelemetry,
31
33
  writeDoctrineMap
32
- } from "./chunk-IEW2QFYI.js";
34
+ } from "./chunk-KT2ROK2D.js";
33
35
 
34
36
  // src/index.ts
35
- import { existsSync as existsSync26, mkdirSync as mkdirSync12, readdirSync as readdirSync6, readFileSync as readFileSync19, writeFileSync as writeFileSync15 } from "fs";
36
- import { basename as basename2, dirname as dirname4, isAbsolute, join as join27, resolve as resolve4 } from "path";
37
+ import { existsSync as existsSync27, mkdirSync as mkdirSync13, readdirSync as readdirSync7, readFileSync as readFileSync20, writeFileSync as writeFileSync16 } from "fs";
38
+ import { basename as basename2, dirname as dirname4, isAbsolute, join as join28, resolve as resolve4 } from "path";
37
39
  import { fileURLToPath as fileURLToPath2 } from "url";
38
40
  import { evaluateGuard, isV4 as isV47, validateEssence as validateEssence2 } from "@decantr/essence-spec";
39
41
  import {
@@ -45,7 +47,9 @@ import {
45
47
  isContentType as isGetContentType,
46
48
  isPublicBlueprintSet,
47
49
  API_CONTENT_TYPES as LIST_CONTENT_TYPES,
48
- RegistryAPIClient as RegistryAPIClient3
50
+ patternToDiscoveryCandidate,
51
+ RegistryAPIClient as RegistryAPIClient3,
52
+ rankPatternCandidates
49
53
  } from "@decantr/registry";
50
54
  import {
51
55
  auditProject,
@@ -1819,8 +1823,8 @@ async function cmdAddFeature(feature, args, projectRoot = process.cwd()) {
1819
1823
  }
1820
1824
 
1821
1825
  // src/commands/analyze.ts
1822
- import { existsSync as existsSync11, mkdirSync as mkdirSync5, writeFileSync as writeFileSync6 } from "fs";
1823
- import { join as join12 } from "path";
1826
+ import { existsSync as existsSync12, mkdirSync as mkdirSync6, writeFileSync as writeFileSync7 } from "fs";
1827
+ import { join as join13 } from "path";
1824
1828
 
1825
1829
  // src/analyzers/components.ts
1826
1830
  import { existsSync as existsSync5, readdirSync, statSync as statSync2 } from "fs";
@@ -2346,9 +2350,262 @@ function scanLayout(projectRoot) {
2346
2350
  };
2347
2351
  }
2348
2352
 
2353
+ // src/brownfield-intelligence.ts
2354
+ import {
2355
+ existsSync as existsSync9,
2356
+ mkdirSync as mkdirSync5,
2357
+ readdirSync as readdirSync4,
2358
+ readFileSync as readFileSync8,
2359
+ statSync as statSync4,
2360
+ writeFileSync as writeFileSync6
2361
+ } from "fs";
2362
+ import { join as join10, relative } from "path";
2363
+ var CSS_SCAN_DIRS = ["src", "app", "styles", "assets"];
2364
+ var CSS_MAX_FILE_SIZE = 1024 * 1024;
2365
+ function collectCssFiles(projectRoot) {
2366
+ const files = [];
2367
+ const seen = /* @__PURE__ */ new Set();
2368
+ const skip = /* @__PURE__ */ new Set(["node_modules", ".git", ".next", ".decantr", "dist", "build", "coverage"]);
2369
+ const walk = (dir) => {
2370
+ let entries;
2371
+ try {
2372
+ entries = readdirSync4(dir, { withFileTypes: true });
2373
+ } catch {
2374
+ return;
2375
+ }
2376
+ for (const entry of entries) {
2377
+ if (skip.has(entry.name)) continue;
2378
+ const full = join10(dir, entry.name);
2379
+ if (entry.isDirectory()) {
2380
+ walk(full);
2381
+ continue;
2382
+ }
2383
+ if (!entry.isFile() || !entry.name.endsWith(".css")) continue;
2384
+ try {
2385
+ if (statSync4(full).size > CSS_MAX_FILE_SIZE) continue;
2386
+ } catch {
2387
+ continue;
2388
+ }
2389
+ if (!seen.has(full)) {
2390
+ files.push(full);
2391
+ seen.add(full);
2392
+ }
2393
+ }
2394
+ };
2395
+ for (const dir of CSS_SCAN_DIRS.map((segment) => join10(projectRoot, segment))) {
2396
+ if (existsSync9(dir)) walk(dir);
2397
+ }
2398
+ return files.sort();
2399
+ }
2400
+ function selectorFromMatch(raw) {
2401
+ return raw.replace(/\s+/g, " ").trim().slice(0, 120);
2402
+ }
2403
+ function createThemeInventory(projectRoot, styling) {
2404
+ const files = collectCssFiles(projectRoot);
2405
+ const variantMap = /* @__PURE__ */ new Map();
2406
+ const notes = [];
2407
+ const ensureVariant = (id, selector, evidence) => {
2408
+ const existing = variantMap.get(id) ?? {
2409
+ id,
2410
+ selectors: [],
2411
+ tokenCount: 0,
2412
+ colorTokenCount: 0,
2413
+ evidence: []
2414
+ };
2415
+ if (!existing.selectors.includes(selector)) existing.selectors.push(selector);
2416
+ if (!existing.evidence.includes(evidence)) existing.evidence.push(evidence);
2417
+ variantMap.set(id, existing);
2418
+ };
2419
+ for (const file of files) {
2420
+ let content = "";
2421
+ try {
2422
+ content = readFileSync8(file, "utf-8");
2423
+ } catch {
2424
+ continue;
2425
+ }
2426
+ const rel = relative(projectRoot, file).replace(/\\/g, "/");
2427
+ const selectorRegex = /((?:\.[\w-]*dark[\w-]*|\[data-theme=["'][^"']+["']\]|\[data-theme=[^\]]+\]|\[data-[\w-]*theme=["'][^"']+["']\]|html\.dark|:root|\.theme-[\w-]+)[^{]*)\{/g;
2428
+ for (const match of content.matchAll(selectorRegex)) {
2429
+ const selector = selectorFromMatch(match[1] ?? "");
2430
+ if (!selector) continue;
2431
+ let id = "base";
2432
+ const dataTheme = selector.match(/data-(?:[\w-]*theme|theme)=["']?([^"'\]\s]+)/i);
2433
+ const themeClass = selector.match(/\.theme-([a-z0-9-]+)/i);
2434
+ if (/dark/i.test(selector)) id = "dark";
2435
+ if (dataTheme?.[1]) id = dataTheme[1].toLowerCase();
2436
+ if (themeClass?.[1]) id = themeClass[1].toLowerCase();
2437
+ if (selector.includes(":root")) id = "base";
2438
+ ensureVariant(id, selector, rel);
2439
+ }
2440
+ for (const [id, entry] of variantMap) {
2441
+ const scopedSelectors = entry.selectors.filter((selector) => content.includes(selector));
2442
+ if (scopedSelectors.length === 0) continue;
2443
+ const scopedText = scopedSelectors.map((selector) => {
2444
+ const idx = content.indexOf(selector);
2445
+ return idx >= 0 ? content.slice(idx, Math.min(content.length, idx + 3e3)) : "";
2446
+ }).join("\n");
2447
+ const tokens = [...scopedText.matchAll(/--[\w-]+\s*:/g)].length;
2448
+ const colors = [
2449
+ ...scopedText.matchAll(
2450
+ /--[\w-]*(?:color|bg|fg|surface|border|accent|primary|secondary)[\w-]*\s*:/gi
2451
+ )
2452
+ ].length;
2453
+ variantMap.set(id, {
2454
+ ...entry,
2455
+ tokenCount: Math.max(entry.tokenCount, tokens),
2456
+ colorTokenCount: Math.max(entry.colorTokenCount, colors)
2457
+ });
2458
+ }
2459
+ }
2460
+ if (variantMap.size === 0) {
2461
+ ensureVariant("base", ":root or existing component styles", "detected styling inventory");
2462
+ notes.push(
2463
+ "No explicit theme selectors were found; Decantr will treat the current UI as the existing-app authority."
2464
+ );
2465
+ }
2466
+ if (styling.darkMode && !variantMap.has("dark")) {
2467
+ ensureVariant("dark", "dark mode signal", "styling analyzer");
2468
+ }
2469
+ const variants = [...variantMap.values()].sort((a, b) => a.id.localeCompare(b.id));
2470
+ const modes = variants.map((variant) => variant.id);
2471
+ if (variants.length > 2) {
2472
+ notes.push(
2473
+ "Multiple theme variants were observed. Essence V4 remains unchanged; variants are reported here for task-time context."
2474
+ );
2475
+ }
2476
+ return {
2477
+ version: 1,
2478
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
2479
+ localOnly: true,
2480
+ stylingApproach: styling.approach,
2481
+ darkModeDetected: styling.darkMode,
2482
+ modes,
2483
+ variants,
2484
+ tokens: {
2485
+ cssVariables: styling.cssVariables,
2486
+ colors: styling.colors
2487
+ },
2488
+ notes
2489
+ };
2490
+ }
2491
+ function readScreenshotEvidence(projectRoot) {
2492
+ const dir = join10(projectRoot, ".decantr", "evidence", "screenshots");
2493
+ if (!existsSync9(dir)) return [];
2494
+ try {
2495
+ return readdirSync4(dir).filter((file) => file.endsWith(".png") || file.endsWith(".jpg") || file.endsWith(".jpeg")).map((file) => `.decantr/evidence/screenshots/${file}`).sort();
2496
+ } catch {
2497
+ return [];
2498
+ }
2499
+ }
2500
+ function backlogItems(input) {
2501
+ const items = [
2502
+ "Confirm the observed personality and visual target in `.decantr/observed-essence.proposal.json` before asking an AI agent to add net-new UI.",
2503
+ "Enrich high-traffic routes with precise directives: states, interactions, shared components, responsive behavior, and accessibility expectations.",
2504
+ "Run `decantr health --browser --base-url <url> --evidence` after the app is running to attach local screenshot evidence."
2505
+ ];
2506
+ if (input.routes.routes.length > 6) {
2507
+ items.push(
2508
+ "Group mature-app routes into stable zones so future tasks can load focused page or section context instead of the whole app."
2509
+ );
2510
+ }
2511
+ if (input.components.componentCount > 10) {
2512
+ items.push("Identify shared component surfaces and record where reuse beats duplication.");
2513
+ }
2514
+ if (input.themeInventory.variants.length > 1) {
2515
+ items.push(
2516
+ "Document which routes use each observed theme variant; do not promote variants into Essence until the contract boundary is reviewed."
2517
+ );
2518
+ }
2519
+ if (input.features.detected.includes("chat") || input.features.detected.includes("file-upload")) {
2520
+ items.push(
2521
+ "Enrich AI/chat/upload flows with concrete interaction evidence so agents do not replace product behavior with generic patterns."
2522
+ );
2523
+ }
2524
+ if (input.styling.approach !== "decantr-css") {
2525
+ items.push(
2526
+ `Keep Brownfield implementation in the existing ${input.styling.approach} styling system unless adoption mode changes.`
2527
+ );
2528
+ }
2529
+ if (input.layout.shellPattern === "main-only" && input.routes.routes.length > 3) {
2530
+ items.push(
2531
+ "Review shell ownership; the analyzer did not find a clear nav/sidebar/footer structure for a multi-route app."
2532
+ );
2533
+ }
2534
+ return items;
2535
+ }
2536
+ function renderBacklog(items) {
2537
+ return [
2538
+ "# Decantr Brownfield Enrichment Backlog",
2539
+ "",
2540
+ "Use this checklist to turn the first Brownfield attach pass into durable task-time context.",
2541
+ "",
2542
+ ...items.map((item) => `- [ ] ${item}`),
2543
+ ""
2544
+ ].join("\n");
2545
+ }
2546
+ function writeBrownfieldIntelligenceArtifacts(input) {
2547
+ const decantrDir = join10(input.projectRoot, ".decantr");
2548
+ mkdirSync5(decantrDir, { recursive: true });
2549
+ const themeInventory = createThemeInventory(input.projectRoot, input.styling);
2550
+ const screenshots = readScreenshotEvidence(input.projectRoot);
2551
+ const backlog = backlogItems({ ...input, themeInventory });
2552
+ const intelligence = {
2553
+ version: 1,
2554
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
2555
+ localOnly: true,
2556
+ workflow: "brownfield-attach",
2557
+ essenceVersion: "4.0.0",
2558
+ project: {
2559
+ framework: input.project.framework,
2560
+ frameworkVersion: input.project.version ?? null,
2561
+ packageManager: input.project.packageManager,
2562
+ hasTypeScript: input.project.hasTypeScript,
2563
+ hasTailwind: input.project.hasTailwind,
2564
+ existingRuleFiles: input.project.existingRuleFiles
2565
+ },
2566
+ routeIntelligence: {
2567
+ strategy: input.routes.strategy,
2568
+ routeCount: input.routes.routes.length,
2569
+ routes: input.routes.routes.map((route) => ({
2570
+ path: route.path,
2571
+ file: route.file,
2572
+ hasLayout: route.hasLayout
2573
+ }))
2574
+ },
2575
+ componentSurface: {
2576
+ pageCount: input.components.pageCount,
2577
+ componentCount: input.components.componentCount,
2578
+ directories: input.components.directories
2579
+ },
2580
+ styling: {
2581
+ approach: input.styling.approach,
2582
+ configFile: input.styling.configFile ?? null,
2583
+ darkMode: input.styling.darkMode,
2584
+ cssVariableCount: input.styling.cssVariables.length,
2585
+ themeInventoryPath: ".decantr/theme-inventory.json"
2586
+ },
2587
+ layout: input.layout,
2588
+ features: input.features,
2589
+ dependencies: input.dependencies,
2590
+ evidence: {
2591
+ screenshotsLocalOnly: true,
2592
+ screenshots,
2593
+ visualManifestPath: existsSync9(join10(decantrDir, "evidence", "visual-manifest.json")) ? ".decantr/evidence/visual-manifest.json" : null
2594
+ },
2595
+ recommendedNextSteps: backlog
2596
+ };
2597
+ const intelligencePath = join10(decantrDir, "brownfield-intelligence.json");
2598
+ const themeInventoryPath = join10(decantrDir, "theme-inventory.json");
2599
+ const backlogPath = join10(decantrDir, "enrichment-backlog.md");
2600
+ writeFileSync6(intelligencePath, JSON.stringify(intelligence, null, 2) + "\n", "utf-8");
2601
+ writeFileSync6(themeInventoryPath, JSON.stringify(themeInventory, null, 2) + "\n", "utf-8");
2602
+ writeFileSync6(backlogPath, renderBacklog(backlog), "utf-8");
2603
+ return { intelligencePath, themeInventoryPath, backlogPath };
2604
+ }
2605
+
2349
2606
  // src/detect.ts
2350
- import { existsSync as existsSync9, readFileSync as readFileSync8 } from "fs";
2351
- import { join as join10 } from "path";
2607
+ import { existsSync as existsSync10, readFileSync as readFileSync9 } from "fs";
2608
+ import { join as join11 } from "path";
2352
2609
  var RULE_FILES = [
2353
2610
  "CLAUDE.md",
2354
2611
  ".claude/rules",
@@ -2370,52 +2627,52 @@ function detectProject(projectRoot = process.cwd()) {
2370
2627
  existingEssence: false,
2371
2628
  projectRoot
2372
2629
  };
2373
- result.existingEssence = existsSync9(join10(projectRoot, "decantr.essence.json"));
2630
+ result.existingEssence = existsSync10(join11(projectRoot, "decantr.essence.json"));
2374
2631
  for (const ruleFile of RULE_FILES) {
2375
- if (existsSync9(join10(projectRoot, ruleFile))) {
2632
+ if (existsSync10(join11(projectRoot, ruleFile))) {
2376
2633
  result.existingRuleFiles.push(ruleFile);
2377
2634
  }
2378
2635
  }
2379
- if (existsSync9(join10(projectRoot, "pnpm-lock.yaml"))) {
2636
+ if (existsSync10(join11(projectRoot, "pnpm-lock.yaml"))) {
2380
2637
  result.packageManager = "pnpm";
2381
- } else if (existsSync9(join10(projectRoot, "yarn.lock"))) {
2638
+ } else if (existsSync10(join11(projectRoot, "yarn.lock"))) {
2382
2639
  result.packageManager = "yarn";
2383
- } else if (existsSync9(join10(projectRoot, "bun.lockb"))) {
2640
+ } else if (existsSync10(join11(projectRoot, "bun.lockb"))) {
2384
2641
  result.packageManager = "bun";
2385
- } else if (existsSync9(join10(projectRoot, "package-lock.json"))) {
2642
+ } else if (existsSync10(join11(projectRoot, "package-lock.json"))) {
2386
2643
  result.packageManager = "npm";
2387
2644
  }
2388
- result.hasTypeScript = existsSync9(join10(projectRoot, "tsconfig.json"));
2389
- result.hasTailwind = existsSync9(join10(projectRoot, "tailwind.config.js")) || existsSync9(join10(projectRoot, "tailwind.config.ts")) || existsSync9(join10(projectRoot, "tailwind.config.mjs")) || existsSync9(join10(projectRoot, "tailwind.config.cjs"));
2390
- if (existsSync9(join10(projectRoot, "next.config.js")) || existsSync9(join10(projectRoot, "next.config.ts")) || existsSync9(join10(projectRoot, "next.config.mjs"))) {
2645
+ result.hasTypeScript = existsSync10(join11(projectRoot, "tsconfig.json"));
2646
+ result.hasTailwind = existsSync10(join11(projectRoot, "tailwind.config.js")) || existsSync10(join11(projectRoot, "tailwind.config.ts")) || existsSync10(join11(projectRoot, "tailwind.config.mjs")) || existsSync10(join11(projectRoot, "tailwind.config.cjs"));
2647
+ if (existsSync10(join11(projectRoot, "next.config.js")) || existsSync10(join11(projectRoot, "next.config.ts")) || existsSync10(join11(projectRoot, "next.config.mjs"))) {
2391
2648
  result.framework = "nextjs";
2392
2649
  result.version = getPackageVersion(projectRoot, "next");
2393
2650
  return result;
2394
2651
  }
2395
- if (existsSync9(join10(projectRoot, "nuxt.config.js")) || existsSync9(join10(projectRoot, "nuxt.config.ts"))) {
2652
+ if (existsSync10(join11(projectRoot, "nuxt.config.js")) || existsSync10(join11(projectRoot, "nuxt.config.ts"))) {
2396
2653
  result.framework = "nuxt";
2397
2654
  result.version = getPackageVersion(projectRoot, "nuxt");
2398
2655
  return result;
2399
2656
  }
2400
- if (existsSync9(join10(projectRoot, "astro.config.mjs")) || existsSync9(join10(projectRoot, "astro.config.ts"))) {
2657
+ if (existsSync10(join11(projectRoot, "astro.config.mjs")) || existsSync10(join11(projectRoot, "astro.config.ts"))) {
2401
2658
  result.framework = "astro";
2402
2659
  result.version = getPackageVersion(projectRoot, "astro");
2403
2660
  return result;
2404
2661
  }
2405
- if (existsSync9(join10(projectRoot, "svelte.config.js")) || existsSync9(join10(projectRoot, "svelte.config.ts"))) {
2662
+ if (existsSync10(join11(projectRoot, "svelte.config.js")) || existsSync10(join11(projectRoot, "svelte.config.ts"))) {
2406
2663
  result.framework = "svelte";
2407
2664
  result.version = getPackageVersion(projectRoot, "svelte");
2408
2665
  return result;
2409
2666
  }
2410
- if (existsSync9(join10(projectRoot, "angular.json"))) {
2667
+ if (existsSync10(join11(projectRoot, "angular.json"))) {
2411
2668
  result.framework = "angular";
2412
2669
  result.version = getPackageVersion(projectRoot, "@angular/core");
2413
2670
  return result;
2414
2671
  }
2415
- const packageJsonPath = join10(projectRoot, "package.json");
2416
- if (existsSync9(packageJsonPath)) {
2672
+ const packageJsonPath = join11(projectRoot, "package.json");
2673
+ if (existsSync10(packageJsonPath)) {
2417
2674
  try {
2418
- const packageJson = JSON.parse(readFileSync8(packageJsonPath, "utf-8"));
2675
+ const packageJson = JSON.parse(readFileSync9(packageJsonPath, "utf-8"));
2419
2676
  const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
2420
2677
  if (deps.next) {
2421
2678
  result.framework = "nextjs";
@@ -2445,18 +2702,18 @@ function detectProject(projectRoot = process.cwd()) {
2445
2702
  } catch {
2446
2703
  }
2447
2704
  }
2448
- if (result.framework === "unknown" && !existsSync9(packageJsonPath)) {
2449
- if (existsSync9(join10(projectRoot, "index.html"))) {
2705
+ if (result.framework === "unknown" && !existsSync10(packageJsonPath)) {
2706
+ if (existsSync10(join11(projectRoot, "index.html"))) {
2450
2707
  result.framework = "html";
2451
2708
  }
2452
2709
  }
2453
2710
  return result;
2454
2711
  }
2455
2712
  function getPackageVersion(projectRoot, packageName) {
2456
- const packageJsonPath = join10(projectRoot, "package.json");
2457
- if (!existsSync9(packageJsonPath)) return void 0;
2713
+ const packageJsonPath = join11(projectRoot, "package.json");
2714
+ if (!existsSync10(packageJsonPath)) return void 0;
2458
2715
  try {
2459
- const packageJson = JSON.parse(readFileSync8(packageJsonPath, "utf-8"));
2716
+ const packageJson = JSON.parse(readFileSync9(packageJsonPath, "utf-8"));
2460
2717
  const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
2461
2718
  const version = deps[packageName];
2462
2719
  return version?.replace(/^\^|~/, "");
@@ -2489,8 +2746,8 @@ function formatDetection(detected) {
2489
2746
  }
2490
2747
 
2491
2748
  // src/workflow-model.ts
2492
- import { existsSync as existsSync10, readFileSync as readFileSync9 } from "fs";
2493
- import { join as join11 } from "path";
2749
+ import { existsSync as existsSync11, readFileSync as readFileSync10 } from "fs";
2750
+ import { join as join12 } from "path";
2494
2751
  function inferSuggestedShell(layout) {
2495
2752
  if (layout.hasSidebar) return "sidebar-main";
2496
2753
  if (layout.hasTopNav) return "top-nav-main";
@@ -2577,12 +2834,12 @@ function createBrownfieldInitSeed(detected, layout, styling) {
2577
2834
  };
2578
2835
  }
2579
2836
  function readBrownfieldInitSeed(projectRoot) {
2580
- const seedPath = join11(projectRoot, ".decantr", "init-seed.json");
2581
- if (!existsSync10(seedPath)) {
2837
+ const seedPath = join12(projectRoot, ".decantr", "init-seed.json");
2838
+ if (!existsSync11(seedPath)) {
2582
2839
  return null;
2583
2840
  }
2584
2841
  try {
2585
- const parsed = JSON.parse(readFileSync9(seedPath, "utf-8"));
2842
+ const parsed = JSON.parse(readFileSync10(seedPath, "utf-8"));
2586
2843
  if (parsed.workflow !== "brownfield-adoption") {
2587
2844
  return null;
2588
2845
  }
@@ -2693,21 +2950,31 @@ ${BOLD}Analyzing project...${RESET2}
2693
2950
  ]
2694
2951
  }
2695
2952
  };
2696
- const decantrDir = join12(projectRoot, ".decantr");
2697
- if (!existsSync11(decantrDir)) {
2698
- mkdirSync5(decantrDir, { recursive: true });
2699
- }
2700
- const outputPath = join12(decantrDir, "analysis.json");
2701
- const initSeedPath = join12(decantrDir, "init-seed.json");
2702
- const ambientPath = join12(decantrDir, "ambient-context.json");
2703
- const doctrinePath = join12(decantrDir, "doctrine-map.json");
2704
- const reportPath = join12(decantrDir, "brownfield-report.md");
2705
- writeFileSync6(outputPath, JSON.stringify(analysis, null, 2) + "\n", "utf-8");
2706
- writeFileSync6(initSeedPath, JSON.stringify(initSeed, null, 2) + "\n", "utf-8");
2707
- writeFileSync6(ambientPath, JSON.stringify(ambient, null, 2) + "\n", "utf-8");
2953
+ const decantrDir = join13(projectRoot, ".decantr");
2954
+ if (!existsSync12(decantrDir)) {
2955
+ mkdirSync6(decantrDir, { recursive: true });
2956
+ }
2957
+ const outputPath = join13(decantrDir, "analysis.json");
2958
+ const initSeedPath = join13(decantrDir, "init-seed.json");
2959
+ const ambientPath = join13(decantrDir, "ambient-context.json");
2960
+ const doctrinePath = join13(decantrDir, "doctrine-map.json");
2961
+ const reportPath = join13(decantrDir, "brownfield-report.md");
2962
+ writeFileSync7(outputPath, JSON.stringify(analysis, null, 2) + "\n", "utf-8");
2963
+ writeFileSync7(initSeedPath, JSON.stringify(initSeed, null, 2) + "\n", "utf-8");
2964
+ writeFileSync7(ambientPath, JSON.stringify(ambient, null, 2) + "\n", "utf-8");
2708
2965
  writeDoctrineMap(projectRoot, doctrine);
2709
2966
  writeBrownfieldProposal(projectRoot, proposal);
2710
- writeFileSync6(reportPath, generateBrownfieldReport(proposal, ambient, doctrine), "utf-8");
2967
+ writeFileSync7(reportPath, generateBrownfieldReport(proposal, ambient, doctrine), "utf-8");
2968
+ const intelligenceArtifacts = writeBrownfieldIntelligenceArtifacts({
2969
+ projectRoot,
2970
+ project,
2971
+ routes,
2972
+ components,
2973
+ styling,
2974
+ layout,
2975
+ features,
2976
+ dependencies
2977
+ });
2711
2978
  console.log(`
2712
2979
  ${GREEN2}Analysis complete.${RESET2}
2713
2980
  `);
@@ -2743,8 +3010,13 @@ ${DIM2}Written to:${RESET2} ${outputPath}`);
2743
3010
  console.log(`${DIM2}Init seed:${RESET2} ${initSeedPath}`);
2744
3011
  console.log(`${DIM2}Ambient context:${RESET2} ${ambientPath}`);
2745
3012
  console.log(`${DIM2}Doctrine map:${RESET2} ${doctrinePath}`);
2746
- console.log(`${DIM2}Observed proposal:${RESET2} ${join12(decantrDir, "observed-essence.proposal.json")}`);
3013
+ console.log(
3014
+ `${DIM2}Observed proposal:${RESET2} ${join13(decantrDir, "observed-essence.proposal.json")}`
3015
+ );
2747
3016
  console.log(`${DIM2}Brownfield report:${RESET2} ${reportPath}`);
3017
+ console.log(`${DIM2}Brownfield intelligence:${RESET2} ${intelligenceArtifacts.intelligencePath}`);
3018
+ console.log(`${DIM2}Theme inventory:${RESET2} ${intelligenceArtifacts.themeInventoryPath}`);
3019
+ console.log(`${DIM2}Enrichment backlog:${RESET2} ${intelligenceArtifacts.backlogPath}`);
2748
3020
  console.log(
2749
3021
  `
2750
3022
  ${YELLOW}Next step:${RESET2} Review ${BOLD}.decantr/brownfield-report.md${RESET2}, then run ${BOLD}decantr init --existing --accept-proposal${RESET2} to attach Decantr using the observed proposal.
@@ -2769,8 +3041,8 @@ ${YELLOW}Next step:${RESET2} Review ${BOLD}.decantr/brownfield-report.md${RESET2
2769
3041
  }
2770
3042
 
2771
3043
  // src/commands/create.ts
2772
- import { existsSync as existsSync12, mkdirSync as mkdirSync6, writeFileSync as writeFileSync7 } from "fs";
2773
- import { join as join13 } from "path";
3044
+ import { existsSync as existsSync13, mkdirSync as mkdirSync7, writeFileSync as writeFileSync8 } from "fs";
3045
+ import { join as join14 } from "path";
2774
3046
  import {
2775
3047
  CONTENT_TYPE_TO_API_CONTENT_TYPE,
2776
3048
  CONTENT_TYPES
@@ -2966,23 +3238,23 @@ function cmdCreate(type, name, projectRoot = process.cwd()) {
2966
3238
  }
2967
3239
  const contentType = type;
2968
3240
  const plural = PLURAL[contentType];
2969
- const customDir = join13(projectRoot, ".decantr", "custom", plural);
2970
- const filePath = join13(customDir, `${name}.json`);
2971
- if (existsSync12(filePath)) {
3241
+ const customDir = join14(projectRoot, ".decantr", "custom", plural);
3242
+ const filePath = join14(customDir, `${name}.json`);
3243
+ if (existsSync13(filePath)) {
2972
3244
  console.error(`${type} "${name}" already exists at ${filePath}`);
2973
3245
  process.exitCode = 1;
2974
3246
  return;
2975
3247
  }
2976
- mkdirSync6(customDir, { recursive: true });
3248
+ mkdirSync7(customDir, { recursive: true });
2977
3249
  const skeleton = getSkeleton(contentType, name, humanizeId(name));
2978
- writeFileSync7(filePath, JSON.stringify(skeleton, null, 2));
3250
+ writeFileSync8(filePath, JSON.stringify(skeleton, null, 2));
2979
3251
  console.log(`Created ${type} "${name}" at ${filePath}`);
2980
3252
  console.log(`Edit it, then publish with: decantr publish ${type} ${name}`);
2981
3253
  }
2982
3254
 
2983
3255
  // src/commands/export.ts
2984
- import { existsSync as existsSync13, mkdirSync as mkdirSync7, readFileSync as readFileSync10, writeFileSync as writeFileSync8 } from "fs";
2985
- import { dirname as dirname2, join as join14 } from "path";
3256
+ import { existsSync as existsSync14, mkdirSync as mkdirSync8, readFileSync as readFileSync11, writeFileSync as writeFileSync9 } from "fs";
3257
+ import { dirname as dirname2, join as join15 } from "path";
2986
3258
  var GREEN3 = "\x1B[32m";
2987
3259
  var RED2 = "\x1B[31m";
2988
3260
  var DIM3 = "\x1B[2m";
@@ -3148,21 +3420,21 @@ function generateFigmaTokens(tokens) {
3148
3420
  `;
3149
3421
  }
3150
3422
  async function cmdExport(target, projectRoot, options = {}) {
3151
- const essencePath = join14(projectRoot, "decantr.essence.json");
3152
- const tokensPath = join14(projectRoot, "src", "styles", "tokens.css");
3153
- if (!existsSync13(essencePath)) {
3423
+ const essencePath = join15(projectRoot, "decantr.essence.json");
3424
+ const tokensPath = join15(projectRoot, "src", "styles", "tokens.css");
3425
+ if (!existsSync14(essencePath)) {
3154
3426
  console.error(`${RED2}No decantr.essence.json found. Run \`decantr init\` first.${RESET3}`);
3155
3427
  process.exitCode = 1;
3156
3428
  return;
3157
3429
  }
3158
- if (!existsSync13(tokensPath)) {
3430
+ if (!existsSync14(tokensPath)) {
3159
3431
  console.error(
3160
3432
  `${RED2}No src/styles/tokens.css found. Run \`decantr refresh\` to generate tokens.${RESET3}`
3161
3433
  );
3162
3434
  process.exitCode = 1;
3163
3435
  return;
3164
3436
  }
3165
- const tokensCSS = readFileSync10(tokensPath, "utf-8");
3437
+ const tokensCSS = readFileSync11(tokensPath, "utf-8");
3166
3438
  const tokens = parseTokensCSS(tokensCSS);
3167
3439
  if (tokens.size === 0) {
3168
3440
  console.error(`${RED2}No --d-* tokens found in tokens.css.${RESET3}`);
@@ -3171,36 +3443,36 @@ async function cmdExport(target, projectRoot, options = {}) {
3171
3443
  }
3172
3444
  switch (target) {
3173
3445
  case "shadcn": {
3174
- const cssOut = options.output ?? join14(projectRoot, "src", "styles", "shadcn-theme.css");
3175
- const jsonOut = join14(projectRoot, "components.json");
3446
+ const cssOut = options.output ?? join15(projectRoot, "src", "styles", "shadcn-theme.css");
3447
+ const jsonOut = join15(projectRoot, "components.json");
3176
3448
  ensureDir(cssOut);
3177
- writeFileSync8(cssOut, generateShadcnCSS(tokens), "utf-8");
3178
- writeFileSync8(jsonOut, generateShadcnComponentsJSON(), "utf-8");
3449
+ writeFileSync9(cssOut, generateShadcnCSS(tokens), "utf-8");
3450
+ writeFileSync9(jsonOut, generateShadcnComponentsJSON(), "utf-8");
3179
3451
  console.log(`${GREEN3}Exported shadcn theme:${RESET3}`);
3180
3452
  console.log(` ${DIM3}CSS:${RESET3} ${cssOut}`);
3181
3453
  console.log(` ${DIM3}JSON:${RESET3} ${jsonOut}`);
3182
3454
  break;
3183
3455
  }
3184
3456
  case "tailwind": {
3185
- const out = options.output ?? join14(projectRoot, "tailwind.decantr.config.ts");
3457
+ const out = options.output ?? join15(projectRoot, "tailwind.decantr.config.ts");
3186
3458
  ensureDir(out);
3187
- writeFileSync8(out, generateTailwindConfig(tokens), "utf-8");
3459
+ writeFileSync9(out, generateTailwindConfig(tokens), "utf-8");
3188
3460
  console.log(`${GREEN3}Exported Tailwind config:${RESET3}`);
3189
3461
  console.log(` ${DIM3}File:${RESET3} ${out}`);
3190
3462
  break;
3191
3463
  }
3192
3464
  case "css-vars": {
3193
- const out = options.output ?? join14(projectRoot, "decantr-tokens.css");
3465
+ const out = options.output ?? join15(projectRoot, "decantr-tokens.css");
3194
3466
  ensureDir(out);
3195
- writeFileSync8(out, generateCSSVars(tokens), "utf-8");
3467
+ writeFileSync9(out, generateCSSVars(tokens), "utf-8");
3196
3468
  console.log(`${GREEN3}Exported CSS variables:${RESET3}`);
3197
3469
  console.log(` ${DIM3}File:${RESET3} ${out}`);
3198
3470
  break;
3199
3471
  }
3200
3472
  case "figma-tokens": {
3201
- const out = options.output ?? join14(projectRoot, ".decantr", "design", "figma-tokens.json");
3473
+ const out = options.output ?? join15(projectRoot, ".decantr", "design", "figma-tokens.json");
3202
3474
  ensureDir(out);
3203
- writeFileSync8(out, generateFigmaTokens(tokens), "utf-8");
3475
+ writeFileSync9(out, generateFigmaTokens(tokens), "utf-8");
3204
3476
  console.log(`${GREEN3}Exported Figma/Tokens Studio tokens:${RESET3}`);
3205
3477
  console.log(` ${DIM3}File:${RESET3} ${out}`);
3206
3478
  break;
@@ -3209,15 +3481,15 @@ async function cmdExport(target, projectRoot, options = {}) {
3209
3481
  }
3210
3482
  function ensureDir(filePath) {
3211
3483
  const dir = dirname2(filePath);
3212
- if (!existsSync13(dir)) {
3213
- mkdirSync7(dir, { recursive: true });
3484
+ if (!existsSync14(dir)) {
3485
+ mkdirSync8(dir, { recursive: true });
3214
3486
  }
3215
3487
  }
3216
3488
 
3217
3489
  // src/commands/magic.ts
3218
- import { existsSync as existsSync14 } from "fs";
3490
+ import { existsSync as existsSync15 } from "fs";
3219
3491
  import * as fs from "fs/promises";
3220
- import { join as join15 } from "path";
3492
+ import { join as join16 } from "path";
3221
3493
  var BOLD2 = "\x1B[1m";
3222
3494
  var DIM4 = "\x1B[2m";
3223
3495
  var RESET4 = "\x1B[0m";
@@ -3445,8 +3717,8 @@ async function cmdMagic(prompt, projectRoot, options) {
3445
3717
  console.log(` Archetype: ${intent.archetype}`);
3446
3718
  }
3447
3719
  console.log("");
3448
- const essencePath = join15(projectRoot, "decantr.essence.json");
3449
- if (existsSync14(essencePath)) {
3720
+ const essencePath = join16(projectRoot, "decantr.essence.json");
3721
+ if (existsSync15(essencePath)) {
3450
3722
  console.log(error(" decantr.essence.json already exists in this directory."));
3451
3723
  console.log(dim(" Remove it first or use a different directory."));
3452
3724
  process.exitCode = 1;
@@ -3471,7 +3743,7 @@ async function cmdMagic(prompt, projectRoot, options) {
3471
3743
  return;
3472
3744
  }
3473
3745
  const registryClient = new RegistryClient({
3474
- cacheDir: join15(projectRoot, ".decantr", "cache"),
3746
+ cacheDir: join16(projectRoot, ".decantr", "cache"),
3475
3747
  apiUrl: options.registry,
3476
3748
  offline: options.offline
3477
3749
  });
@@ -3742,14 +4014,14 @@ async function cmdMagic(prompt, projectRoot, options) {
3742
4014
  if (result.gitignoreUpdated) {
3743
4015
  console.log(` ${dim(".gitignore updated")}`);
3744
4016
  }
3745
- const contextDir = join15(projectRoot, ".decantr", "context");
4017
+ const contextDir = join16(projectRoot, ".decantr", "context");
3746
4018
  let sectionCount = 0;
3747
4019
  try {
3748
4020
  const files = await fs.readdir(contextDir);
3749
4021
  sectionCount = files.filter((f) => f.startsWith("section-")).length;
3750
4022
  } catch {
3751
4023
  }
3752
- const treatmentsPath = join15(projectRoot, "src", "styles", "treatments.css");
4024
+ const treatmentsPath = join16(projectRoot, "src", "styles", "treatments.css");
3753
4025
  let hasLayers = false;
3754
4026
  try {
3755
4027
  const css = await fs.readFile(treatmentsPath, "utf-8");
@@ -3782,8 +4054,8 @@ ${GREEN4}${BOLD2}Quality summary:${RESET4}`);
3782
4054
  }
3783
4055
 
3784
4056
  // src/commands/migrate.ts
3785
- import { copyFileSync, existsSync as existsSync15, readFileSync as readFileSync11, writeFileSync as writeFileSync9 } from "fs";
3786
- import { join as join16 } from "path";
4057
+ import { copyFileSync, existsSync as existsSync16, readFileSync as readFileSync12, writeFileSync as writeFileSync10 } from "fs";
4058
+ import { join as join17 } from "path";
3787
4059
  import {
3788
4060
  isV4 as isV43,
3789
4061
  migrateToV4,
@@ -3796,12 +4068,12 @@ var YELLOW3 = "\x1B[33m";
3796
4068
  var RESET5 = "\x1B[0m";
3797
4069
  var DIM5 = "\x1B[2m";
3798
4070
  function migrateEssenceFile(essencePath) {
3799
- if (!existsSync15(essencePath)) {
4071
+ if (!existsSync16(essencePath)) {
3800
4072
  return { success: false, error: `File not found: ${essencePath}` };
3801
4073
  }
3802
4074
  let raw;
3803
4075
  try {
3804
- raw = readFileSync11(essencePath, "utf-8");
4076
+ raw = readFileSync12(essencePath, "utf-8");
3805
4077
  } catch (e) {
3806
4078
  return { success: false, error: `Could not read ${essencePath}: ${e.message}` };
3807
4079
  }
@@ -3842,7 +4114,7 @@ function migrateEssenceFile(essencePath) {
3842
4114
  };
3843
4115
  }
3844
4116
  try {
3845
- writeFileSync9(essencePath, JSON.stringify(v4, null, 2) + "\n");
4117
+ writeFileSync10(essencePath, JSON.stringify(v4, null, 2) + "\n");
3846
4118
  } catch (e) {
3847
4119
  return {
3848
4120
  success: false,
@@ -3863,8 +4135,8 @@ async function cmdMigrate(projectRoot = process.cwd(), args = []) {
3863
4135
  process.exitCode = 1;
3864
4136
  return;
3865
4137
  }
3866
- const essencePath = join16(projectRoot, "decantr.essence.json");
3867
- if (!existsSync15(essencePath)) {
4138
+ const essencePath = join17(projectRoot, "decantr.essence.json");
4139
+ if (!existsSync16(essencePath)) {
3868
4140
  console.error(`${RED4}No decantr.essence.json found. Run \`decantr init\` first.${RESET5}`);
3869
4141
  process.exitCode = 1;
3870
4142
  return;
@@ -3886,7 +4158,7 @@ async function cmdMigrate(projectRoot = process.cwd(), args = []) {
3886
4158
  }
3887
4159
  if (result.essence) {
3888
4160
  const registryClient = new RegistryClient({
3889
- cacheDir: join16(projectRoot, ".decantr", "cache")
4161
+ cacheDir: join17(projectRoot, ".decantr", "cache")
3890
4162
  });
3891
4163
  await refreshDerivedFiles(projectRoot, result.essence, registryClient);
3892
4164
  console.log(`${GREEN5}Derived context and execution packs refreshed.${RESET5}`);
@@ -3897,50 +4169,50 @@ async function cmdMigrate(projectRoot = process.cwd(), args = []) {
3897
4169
 
3898
4170
  // src/commands/new-project.ts
3899
4171
  import { spawnSync } from "child_process";
3900
- import { existsSync as existsSync17, mkdirSync as mkdirSync9 } from "fs";
3901
- import { join as join18, resolve as resolve2 } from "path";
4172
+ import { existsSync as existsSync18, mkdirSync as mkdirSync10 } from "fs";
4173
+ import { join as join19, resolve as resolve2 } from "path";
3902
4174
  import { fileURLToPath } from "url";
3903
4175
 
3904
4176
  // src/offline-content.ts
3905
- import { cpSync, existsSync as existsSync16, mkdirSync as mkdirSync8 } from "fs";
3906
- import { join as join17, resolve } from "path";
4177
+ import { cpSync, existsSync as existsSync17, mkdirSync as mkdirSync9 } from "fs";
4178
+ import { join as join18, resolve } from "path";
3907
4179
  var CONTENT_TYPES2 = ["archetypes", "blueprints", "patterns", "themes", "shells"];
3908
4180
  function copyIfExists(source, target) {
3909
- if (!existsSync16(source)) return false;
4181
+ if (!existsSync17(source)) return false;
3910
4182
  if (resolve(source) === resolve(target)) return true;
3911
4183
  cpSync(source, target, { recursive: true });
3912
4184
  return true;
3913
4185
  }
3914
4186
  function hydrateContentRoot(projectDir, contentRoot) {
3915
- if (!existsSync16(contentRoot)) return false;
3916
- const customRoot = join17(projectDir, ".decantr", "custom");
3917
- const cacheRoot = join17(projectDir, ".decantr", "cache", "@official");
3918
- mkdirSync8(customRoot, { recursive: true });
3919
- mkdirSync8(cacheRoot, { recursive: true });
4187
+ if (!existsSync17(contentRoot)) return false;
4188
+ const customRoot = join18(projectDir, ".decantr", "custom");
4189
+ const cacheRoot = join18(projectDir, ".decantr", "cache", "@official");
4190
+ mkdirSync9(customRoot, { recursive: true });
4191
+ mkdirSync9(cacheRoot, { recursive: true });
3920
4192
  let copiedAny = false;
3921
4193
  for (const type of CONTENT_TYPES2) {
3922
- const sourceDir = join17(contentRoot, type);
3923
- if (!existsSync16(sourceDir)) continue;
3924
- cpSync(sourceDir, join17(customRoot, type), { recursive: true });
3925
- cpSync(sourceDir, join17(cacheRoot, type), { recursive: true });
4194
+ const sourceDir = join18(contentRoot, type);
4195
+ if (!existsSync17(sourceDir)) continue;
4196
+ cpSync(sourceDir, join18(customRoot, type), { recursive: true });
4197
+ cpSync(sourceDir, join18(cacheRoot, type), { recursive: true });
3926
4198
  copiedAny = true;
3927
4199
  }
3928
4200
  return copiedAny;
3929
4201
  }
3930
4202
  function seedOfflineRegistry(projectDir, workspaceRoot) {
3931
- const projectDecantrRoot = join17(projectDir, ".decantr");
3932
- mkdirSync8(projectDecantrRoot, { recursive: true });
4203
+ const projectDecantrRoot = join18(projectDir, ".decantr");
4204
+ mkdirSync9(projectDecantrRoot, { recursive: true });
3933
4205
  const configuredContentRoot = process.env.DECANTR_CONTENT_DIR ? resolve(process.env.DECANTR_CONTENT_DIR) : null;
3934
4206
  if (configuredContentRoot && hydrateContentRoot(projectDir, configuredContentRoot)) {
3935
4207
  return { seeded: true, strategy: "configured-content-root" };
3936
4208
  }
3937
4209
  const copiedCache = copyIfExists(
3938
- join17(workspaceRoot, ".decantr", "cache"),
3939
- join17(projectDecantrRoot, "cache")
4210
+ join18(workspaceRoot, ".decantr", "cache"),
4211
+ join18(projectDecantrRoot, "cache")
3940
4212
  );
3941
4213
  const copiedCustom = copyIfExists(
3942
- join17(workspaceRoot, ".decantr", "custom"),
3943
- join17(projectDecantrRoot, "custom")
4214
+ join18(workspaceRoot, ".decantr", "custom"),
4215
+ join18(projectDecantrRoot, "custom")
3944
4216
  );
3945
4217
  if (copiedCache || copiedCustom) {
3946
4218
  return { seeded: true, strategy: "workspace-cache" };
@@ -4053,7 +4325,7 @@ function runArgvCommand(command, args, cwd) {
4053
4325
  }
4054
4326
  function resolveInitCommand(initFlags) {
4055
4327
  const bundledCliEntrypoint = fileURLToPath(new URL("./bin.js", import.meta.url));
4056
- const cliEntrypoint = existsSync17(bundledCliEntrypoint) ? bundledCliEntrypoint : process.argv[1] && existsSync17(process.argv[1]) ? process.argv[1] : null;
4328
+ const cliEntrypoint = existsSync18(bundledCliEntrypoint) ? bundledCliEntrypoint : process.argv[1] && existsSync18(process.argv[1]) ? process.argv[1] : null;
4057
4329
  if (cliEntrypoint) {
4058
4330
  return {
4059
4331
  command: process.execPath,
@@ -4081,7 +4353,7 @@ async function cmdNewProject(projectName, options) {
4081
4353
  process.exitCode = 1;
4082
4354
  return;
4083
4355
  }
4084
- if (existsSync17(projectDir)) {
4356
+ if (existsSync18(projectDir)) {
4085
4357
  console.error(error2(`Directory "${projectName}" already exists.`));
4086
4358
  process.exitCode = 1;
4087
4359
  return;
@@ -4095,7 +4367,7 @@ async function cmdNewProject(projectName, options) {
4095
4367
  return;
4096
4368
  }
4097
4369
  console.log(heading(`Creating ${projectName}...`));
4098
- mkdirSync9(projectDir, { recursive: true });
4370
+ mkdirSync10(projectDir, { recursive: true });
4099
4371
  console.log(dim2(` Created ${projectName}/`));
4100
4372
  const title = projectName.replace(/[-_]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
4101
4373
  if (shouldBootstrapRuntime && bootstrapAdapter) {
@@ -4194,21 +4466,21 @@ ${YELLOW4}Decantr init encountered issues. Run \`decantr init\` manually inside
4194
4466
  }
4195
4467
  }
4196
4468
  function detectPackageManager() {
4197
- if (existsSync17(join18(process.cwd(), "pnpm-lock.yaml")) || existsSync17(join18(process.cwd(), "pnpm-workspace.yaml"))) {
4469
+ if (existsSync18(join19(process.cwd(), "pnpm-lock.yaml")) || existsSync18(join19(process.cwd(), "pnpm-workspace.yaml"))) {
4198
4470
  return "pnpm";
4199
4471
  }
4200
- if (existsSync17(join18(process.cwd(), "yarn.lock"))) {
4472
+ if (existsSync18(join19(process.cwd(), "yarn.lock"))) {
4201
4473
  return "yarn";
4202
4474
  }
4203
- if (existsSync17(join18(process.cwd(), "bun.lockb")) || existsSync17(join18(process.cwd(), "bun.lock"))) {
4475
+ if (existsSync18(join19(process.cwd(), "bun.lockb")) || existsSync18(join19(process.cwd(), "bun.lock"))) {
4204
4476
  return "bun";
4205
4477
  }
4206
4478
  return "npm";
4207
4479
  }
4208
4480
 
4209
4481
  // src/commands/publish.ts
4210
- import { existsSync as existsSync18, readFileSync as readFileSync12 } from "fs";
4211
- import { join as join19 } from "path";
4482
+ import { existsSync as existsSync19, readFileSync as readFileSync13 } from "fs";
4483
+ import { join as join20 } from "path";
4212
4484
  import {
4213
4485
  API_CONTENT_TYPE_TO_CONTENT_TYPE,
4214
4486
  CONTENT_TYPE_TO_API_CONTENT_TYPE as CONTENT_TYPE_TO_API_CONTENT_TYPE2,
@@ -4224,8 +4496,8 @@ async function cmdPublish(type, name, projectRoot = process.cwd()) {
4224
4496
  }
4225
4497
  const singularType = API_CONTENT_TYPE_TO_CONTENT_TYPE[type] || type;
4226
4498
  const pluralType = CONTENT_TYPE_TO_API_CONTENT_TYPE2[type] || CONTENT_TYPE_TO_API_CONTENT_TYPE2[singularType] || `${type}s`;
4227
- const customPath = join19(projectRoot, ".decantr", "custom", pluralType, `${name}.json`);
4228
- if (!existsSync18(customPath)) {
4499
+ const customPath = join20(projectRoot, ".decantr", "custom", pluralType, `${name}.json`);
4500
+ if (!existsSync19(customPath)) {
4229
4501
  console.error(`Custom ${singularType} "${name}" not found at ${customPath}`);
4230
4502
  console.error(`Create one first: decantr create ${singularType} ${name}`);
4231
4503
  process.exitCode = 1;
@@ -4233,7 +4505,7 @@ async function cmdPublish(type, name, projectRoot = process.cwd()) {
4233
4505
  }
4234
4506
  let data;
4235
4507
  try {
4236
- data = JSON.parse(readFileSync12(customPath, "utf-8"));
4508
+ data = JSON.parse(readFileSync13(customPath, "utf-8"));
4237
4509
  } catch {
4238
4510
  console.error(`Failed to parse ${customPath}`);
4239
4511
  process.exitCode = 1;
@@ -4271,23 +4543,23 @@ async function cmdPublish(type, name, projectRoot = process.cwd()) {
4271
4543
  }
4272
4544
 
4273
4545
  // src/commands/refresh.ts
4274
- import { existsSync as existsSync19, readFileSync as readFileSync13 } from "fs";
4275
- import { join as join20 } from "path";
4546
+ import { existsSync as existsSync20, readFileSync as readFileSync14 } from "fs";
4547
+ import { join as join21 } from "path";
4276
4548
  import { isV4 as isV44 } from "@decantr/essence-spec";
4277
4549
  var GREEN7 = "\x1B[32m";
4278
4550
  var RED6 = "\x1B[31m";
4279
4551
  var DIM7 = "\x1B[2m";
4280
4552
  var RESET7 = "\x1B[0m";
4281
4553
  async function cmdRefresh(projectRoot = process.cwd(), options = {}) {
4282
- const essencePath = join20(projectRoot, "decantr.essence.json");
4283
- if (!existsSync19(essencePath)) {
4554
+ const essencePath = join21(projectRoot, "decantr.essence.json");
4555
+ if (!existsSync20(essencePath)) {
4284
4556
  console.error(`${RED6}No decantr.essence.json found. Run \`decantr init\` first.${RESET7}`);
4285
4557
  process.exitCode = 1;
4286
4558
  return;
4287
4559
  }
4288
4560
  let essence;
4289
4561
  try {
4290
- const raw = readFileSync13(essencePath, "utf-8");
4562
+ const raw = readFileSync14(essencePath, "utf-8");
4291
4563
  const parsed = JSON.parse(raw);
4292
4564
  if (!isV44(parsed)) {
4293
4565
  console.error(
@@ -4303,7 +4575,7 @@ async function cmdRefresh(projectRoot = process.cwd(), options = {}) {
4303
4575
  return;
4304
4576
  }
4305
4577
  const registryClient = new RegistryClient({
4306
- cacheDir: join20(projectRoot, ".decantr", "cache"),
4578
+ cacheDir: join21(projectRoot, ".decantr", "cache"),
4307
4579
  offline: options.offline
4308
4580
  });
4309
4581
  console.log("Regenerating derived files...\n");
@@ -4323,8 +4595,8 @@ async function cmdRefresh(projectRoot = process.cwd(), options = {}) {
4323
4595
  }
4324
4596
 
4325
4597
  // src/commands/registry-mirror.ts
4326
- import { mkdirSync as mkdirSync10, writeFileSync as writeFileSync10 } from "fs";
4327
- import { join as join21 } from "path";
4598
+ import { mkdirSync as mkdirSync11, writeFileSync as writeFileSync11 } from "fs";
4599
+ import { join as join22 } from "path";
4328
4600
  import { API_CONTENT_TYPES, RegistryAPIClient as RegistryAPIClient2 } from "@decantr/registry";
4329
4601
  var GREEN8 = "\x1B[32m";
4330
4602
  var RED7 = "\x1B[31m";
@@ -4352,7 +4624,7 @@ async function cmdRegistryMirror(projectRoot, options = {}) {
4352
4624
  process.exitCode = 1;
4353
4625
  return;
4354
4626
  }
4355
- const cacheDir = join21(projectRoot, ".decantr", "cache");
4627
+ const cacheDir = join22(projectRoot, ".decantr", "cache");
4356
4628
  const counts = {};
4357
4629
  const failed = [];
4358
4630
  console.log(`
@@ -4362,19 +4634,19 @@ Mirroring registry content to ${DIM8}.decantr/cache/${RESET8}
4362
4634
  try {
4363
4635
  const result = await apiClient.listContent(type, { namespace: "@official" });
4364
4636
  const items = result.items;
4365
- const typeDir = join21(cacheDir, "@official", type);
4366
- mkdirSync10(typeDir, { recursive: true });
4367
- writeFileSync10(join21(typeDir, "index.json"), JSON.stringify(result, null, 2));
4637
+ const typeDir = join22(cacheDir, "@official", type);
4638
+ mkdirSync11(typeDir, { recursive: true });
4639
+ writeFileSync11(join22(typeDir, "index.json"), JSON.stringify(result, null, 2));
4368
4640
  let itemCount = 0;
4369
4641
  for (const item of items) {
4370
4642
  const slug = item.slug || item.id;
4371
4643
  if (!slug) continue;
4372
4644
  try {
4373
4645
  const fullItem = await apiClient.getContent(type, "@official", slug);
4374
- writeFileSync10(join21(typeDir, `${slug}.json`), JSON.stringify(fullItem, null, 2));
4646
+ writeFileSync11(join22(typeDir, `${slug}.json`), JSON.stringify(fullItem, null, 2));
4375
4647
  itemCount++;
4376
4648
  } catch {
4377
- writeFileSync10(join21(typeDir, `${slug}.json`), JSON.stringify(item, null, 2));
4649
+ writeFileSync11(join22(typeDir, `${slug}.json`), JSON.stringify(item, null, 2));
4378
4650
  itemCount++;
4379
4651
  }
4380
4652
  }
@@ -4389,8 +4661,8 @@ Mirroring registry content to ${DIM8}.decantr/cache/${RESET8}
4389
4661
  mirrored_at: (/* @__PURE__ */ new Date()).toISOString(),
4390
4662
  counts
4391
4663
  };
4392
- mkdirSync10(join21(cacheDir), { recursive: true });
4393
- writeFileSync10(join21(cacheDir, "mirror-manifest.json"), JSON.stringify(manifest, null, 2));
4664
+ mkdirSync11(join22(cacheDir), { recursive: true });
4665
+ writeFileSync11(join22(cacheDir, "mirror-manifest.json"), JSON.stringify(manifest, null, 2));
4394
4666
  const totalItems = Object.values(counts).reduce((a, b) => a + b, 0);
4395
4667
  console.log("");
4396
4668
  if (failed.length > 0) {
@@ -4407,23 +4679,23 @@ Mirroring registry content to ${DIM8}.decantr/cache/${RESET8}
4407
4679
  }
4408
4680
 
4409
4681
  // src/commands/remove.ts
4410
- import { existsSync as existsSync21, readFileSync as readFileSync14, rmSync as rmSync2, writeFileSync as writeFileSync11 } from "fs";
4411
- import { join as join22 } from "path";
4682
+ import { existsSync as existsSync22, readFileSync as readFileSync15, rmSync as rmSync2, writeFileSync as writeFileSync12 } from "fs";
4683
+ import { join as join23 } from "path";
4412
4684
  import { isV4 as isV45 } from "@decantr/essence-spec";
4413
4685
  var GREEN9 = "\x1B[32m";
4414
4686
  var RED8 = "\x1B[31m";
4415
4687
  var DIM9 = "\x1B[2m";
4416
4688
  var RESET9 = "\x1B[0m";
4417
4689
  function readV4Essence2(projectRoot) {
4418
- const essencePath = join22(projectRoot, "decantr.essence.json");
4419
- if (!existsSync21(essencePath)) {
4690
+ const essencePath = join23(projectRoot, "decantr.essence.json");
4691
+ if (!existsSync22(essencePath)) {
4420
4692
  console.error(`${RED8}No decantr.essence.json found. Run \`decantr init\` first.${RESET9}`);
4421
4693
  process.exitCode = 1;
4422
4694
  return null;
4423
4695
  }
4424
4696
  let parsed;
4425
4697
  try {
4426
- parsed = JSON.parse(readFileSync14(essencePath, "utf-8"));
4698
+ parsed = JSON.parse(readFileSync15(essencePath, "utf-8"));
4427
4699
  } catch (e) {
4428
4700
  console.error(`${RED8}Could not read essence: ${e.message}${RESET9}`);
4429
4701
  process.exitCode = 1;
@@ -4439,7 +4711,7 @@ function readV4Essence2(projectRoot) {
4439
4711
  return { essence: parsed, essencePath };
4440
4712
  }
4441
4713
  function writeEssence2(essencePath, essence) {
4442
- writeFileSync11(essencePath, JSON.stringify(essence, null, 2) + "\n");
4714
+ writeFileSync12(essencePath, JSON.stringify(essence, null, 2) + "\n");
4443
4715
  }
4444
4716
  function recomputeGlobalFeatures(essence) {
4445
4717
  const all = /* @__PURE__ */ new Set();
@@ -4481,14 +4753,14 @@ async function cmdRemoveSection(sectionId, args, projectRoot = process.cwd()) {
4481
4753
  sections.splice(idx, 1);
4482
4754
  recomputeGlobalFeatures(essence);
4483
4755
  removeRoutes(essence, sectionId);
4484
- const contextFile = join22(projectRoot, ".decantr", "context", `${sectionId}.md`);
4485
- if (existsSync21(contextFile)) {
4756
+ const contextFile = join23(projectRoot, ".decantr", "context", `${sectionId}.md`);
4757
+ if (existsSync22(contextFile)) {
4486
4758
  rmSync2(contextFile);
4487
4759
  }
4488
4760
  writeEssence2(essencePath, essence);
4489
4761
  console.log(`${GREEN9}Removed section "${sectionId}".${RESET9}`);
4490
4762
  const registryClient = new RegistryClient({
4491
- cacheDir: join22(projectRoot, ".decantr", "cache")
4763
+ cacheDir: join23(projectRoot, ".decantr", "cache")
4492
4764
  });
4493
4765
  await refreshDerivedFiles(projectRoot, essence, registryClient);
4494
4766
  console.log(`${GREEN9}Derived files refreshed.${RESET9}`);
@@ -4524,7 +4796,7 @@ async function cmdRemovePage(path, args, projectRoot = process.cwd()) {
4524
4796
  writeEssence2(essencePath, essence);
4525
4797
  console.log(`${GREEN9}Removed page "${pageId}" from section "${sectionId}".${RESET9}`);
4526
4798
  const registryClient = new RegistryClient({
4527
- cacheDir: join22(projectRoot, ".decantr", "cache")
4799
+ cacheDir: join23(projectRoot, ".decantr", "cache")
4528
4800
  });
4529
4801
  await refreshDerivedFiles(projectRoot, essence, registryClient);
4530
4802
  console.log(`${GREEN9}Derived files refreshed.${RESET9}`);
@@ -4565,15 +4837,15 @@ async function cmdRemoveFeature(feature, args, projectRoot = process.cwd()) {
4565
4837
  const target = sectionId ? `section "${sectionId}" and global` : "global";
4566
4838
  console.log(`${GREEN9}Removed feature "${feature}" from ${target} features.${RESET9}`);
4567
4839
  const registryClient = new RegistryClient({
4568
- cacheDir: join22(projectRoot, ".decantr", "cache")
4840
+ cacheDir: join23(projectRoot, ".decantr", "cache")
4569
4841
  });
4570
4842
  await refreshDerivedFiles(projectRoot, essence, registryClient);
4571
4843
  console.log(`${GREEN9}Derived files refreshed.${RESET9}`);
4572
4844
  }
4573
4845
 
4574
4846
  // src/commands/sync-drift.ts
4575
- import { existsSync as existsSync22, readFileSync as readFileSync15, writeFileSync as writeFileSync12 } from "fs";
4576
- import { join as join23 } from "path";
4847
+ import { existsSync as existsSync23, readFileSync as readFileSync16, writeFileSync as writeFileSync13 } from "fs";
4848
+ import { join as join24 } from "path";
4577
4849
  var GREEN10 = "\x1B[32m";
4578
4850
  var RED9 = "\x1B[31m";
4579
4851
  var YELLOW6 = "\x1B[33m";
@@ -4582,8 +4854,8 @@ var DIM10 = "\x1B[2m";
4582
4854
  var BOLD4 = "\x1B[1m";
4583
4855
  var CYAN5 = "\x1B[36m";
4584
4856
  async function cmdSyncDrift(projectRoot = process.cwd()) {
4585
- const driftLogPath = join23(projectRoot, ".decantr", "drift-log.json");
4586
- if (!existsSync22(driftLogPath)) {
4857
+ const driftLogPath = join24(projectRoot, ".decantr", "drift-log.json");
4858
+ if (!existsSync23(driftLogPath)) {
4587
4859
  console.log(`${GREEN10}No drift log found \u2014 no drift recorded.${RESET10}`);
4588
4860
  console.log(
4589
4861
  `${DIM10}Drift is logged when guard violations are detected during development.${RESET10}`
@@ -4592,7 +4864,7 @@ async function cmdSyncDrift(projectRoot = process.cwd()) {
4592
4864
  }
4593
4865
  let entries;
4594
4866
  try {
4595
- entries = JSON.parse(readFileSync15(driftLogPath, "utf-8"));
4867
+ entries = JSON.parse(readFileSync16(driftLogPath, "utf-8"));
4596
4868
  } catch {
4597
4869
  console.error(`${RED9}Could not parse drift-log.json${RESET10}`);
4598
4870
  process.exitCode = 1;
@@ -4638,13 +4910,13 @@ ${BOLD4}Unresolved Drift Entries (${unresolved.length})${RESET10}
4638
4910
  console.log("");
4639
4911
  }
4640
4912
  function resolveDriftEntries(projectRoot, options) {
4641
- const driftLogPath = join23(projectRoot, ".decantr", "drift-log.json");
4642
- if (!existsSync22(driftLogPath)) {
4913
+ const driftLogPath = join24(projectRoot, ".decantr", "drift-log.json");
4914
+ if (!existsSync23(driftLogPath)) {
4643
4915
  return { success: true };
4644
4916
  }
4645
4917
  if (options.clear) {
4646
4918
  try {
4647
- writeFileSync12(driftLogPath, "[]");
4919
+ writeFileSync13(driftLogPath, "[]");
4648
4920
  return { success: true };
4649
4921
  } catch (e) {
4650
4922
  return { success: false, error: `Could not clear drift log: ${e.message}` };
@@ -4652,7 +4924,7 @@ function resolveDriftEntries(projectRoot, options) {
4652
4924
  }
4653
4925
  let entries;
4654
4926
  try {
4655
- entries = JSON.parse(readFileSync15(driftLogPath, "utf-8"));
4927
+ entries = JSON.parse(readFileSync16(driftLogPath, "utf-8"));
4656
4928
  } catch {
4657
4929
  return { success: false, error: "Could not parse drift-log.json" };
4658
4930
  }
@@ -4671,7 +4943,7 @@ function resolveDriftEntries(projectRoot, options) {
4671
4943
  }
4672
4944
  }
4673
4945
  try {
4674
- writeFileSync12(driftLogPath, JSON.stringify(entries, null, 2));
4946
+ writeFileSync13(driftLogPath, JSON.stringify(entries, null, 2));
4675
4947
  return { success: true };
4676
4948
  } catch (e) {
4677
4949
  return { success: false, error: `Could not write drift log: ${e.message}` };
@@ -4896,8 +5168,8 @@ function trimTrailingSlashes(value) {
4896
5168
  }
4897
5169
 
4898
5170
  // src/commands/theme-switch.ts
4899
- import { existsSync as existsSync23, readFileSync as readFileSync16, writeFileSync as writeFileSync13 } from "fs";
4900
- import { join as join24 } from "path";
5171
+ import { existsSync as existsSync24, readFileSync as readFileSync17, writeFileSync as writeFileSync14 } from "fs";
5172
+ import { join as join25 } from "path";
4901
5173
  import { isV4 as isV46 } from "@decantr/essence-spec";
4902
5174
  var GREEN12 = "\x1B[32m";
4903
5175
  var RED10 = "\x1B[31m";
@@ -4914,15 +5186,15 @@ async function cmdThemeSwitch(themeName, args, projectRoot = process.cwd()) {
4914
5186
  process.exitCode = 1;
4915
5187
  return;
4916
5188
  }
4917
- const essencePath = join24(projectRoot, "decantr.essence.json");
4918
- if (!existsSync23(essencePath)) {
5189
+ const essencePath = join25(projectRoot, "decantr.essence.json");
5190
+ if (!existsSync24(essencePath)) {
4919
5191
  console.error(`${RED10}No decantr.essence.json found. Run \`decantr init\` first.${RESET12}`);
4920
5192
  process.exitCode = 1;
4921
5193
  return;
4922
5194
  }
4923
5195
  let parsed;
4924
5196
  try {
4925
- parsed = JSON.parse(readFileSync16(essencePath, "utf-8"));
5197
+ parsed = JSON.parse(readFileSync17(essencePath, "utf-8"));
4926
5198
  } catch (e) {
4927
5199
  console.error(`${RED10}Could not read essence: ${e.message}${RESET12}`);
4928
5200
  process.exitCode = 1;
@@ -4973,7 +5245,7 @@ async function cmdThemeSwitch(themeName, args, projectRoot = process.cwd()) {
4973
5245
  essence.dna.theme.mode = mode;
4974
5246
  }
4975
5247
  const registryClient = new RegistryClient({
4976
- cacheDir: join24(projectRoot, ".decantr", "cache")
5248
+ cacheDir: join25(projectRoot, ".decantr", "cache")
4977
5249
  });
4978
5250
  try {
4979
5251
  const themeResult = await registryClient.fetchTheme(themeName);
@@ -4988,7 +5260,7 @@ async function cmdThemeSwitch(themeName, args, projectRoot = process.cwd()) {
4988
5260
  }
4989
5261
  } catch {
4990
5262
  }
4991
- writeFileSync13(essencePath, JSON.stringify(essence, null, 2) + "\n");
5263
+ writeFileSync14(essencePath, JSON.stringify(essence, null, 2) + "\n");
4992
5264
  console.log(`${GREEN12}Switched theme: ${oldThemeId} \u2192 ${themeName}${RESET12}`);
4993
5265
  if (shape) console.log(` ${DIM12}Shape: ${shape}${RESET12}`);
4994
5266
  if (mode) console.log(` ${DIM12}Mode: ${mode}${RESET12}`);
@@ -5296,8 +5568,8 @@ async function runSimplifiedInit(blueprints) {
5296
5568
  }
5297
5569
 
5298
5570
  // src/theme-commands.ts
5299
- import { existsSync as existsSync24, mkdirSync as mkdirSync11, readdirSync as readdirSync4, readFileSync as readFileSync17, rmSync as rmSync3, writeFileSync as writeFileSync14 } from "fs";
5300
- import { join as join25 } from "path";
5571
+ import { existsSync as existsSync25, mkdirSync as mkdirSync12, readdirSync as readdirSync5, readFileSync as readFileSync18, rmSync as rmSync3, writeFileSync as writeFileSync15 } from "fs";
5572
+ import { join as join26 } from "path";
5301
5573
  var REQUIRED_FIELDS = [
5302
5574
  "$schema",
5303
5575
  "id",
@@ -5357,20 +5629,20 @@ function validateCustomTheme(theme) {
5357
5629
  };
5358
5630
  }
5359
5631
  function createTheme(projectRoot, id, name) {
5360
- const customThemesDir = join25(projectRoot, ".decantr", "custom", "themes");
5361
- const themePath = join25(customThemesDir, `${id}.json`);
5362
- const howToPath = join25(customThemesDir, "how-to-theme.md");
5363
- mkdirSync11(customThemesDir, { recursive: true });
5364
- if (existsSync24(themePath)) {
5632
+ const customThemesDir = join26(projectRoot, ".decantr", "custom", "themes");
5633
+ const themePath = join26(customThemesDir, `${id}.json`);
5634
+ const howToPath = join26(customThemesDir, "how-to-theme.md");
5635
+ mkdirSync12(customThemesDir, { recursive: true });
5636
+ if (existsSync25(themePath)) {
5365
5637
  return {
5366
5638
  success: false,
5367
5639
  error: `Theme "${id}" already exists at ${themePath}`
5368
5640
  };
5369
5641
  }
5370
5642
  const skeleton = getThemeSkeleton(id, name);
5371
- writeFileSync14(themePath, JSON.stringify(skeleton, null, 2));
5372
- if (!existsSync24(howToPath)) {
5373
- writeFileSync14(howToPath, getHowToThemeDoc());
5643
+ writeFileSync15(themePath, JSON.stringify(skeleton, null, 2));
5644
+ if (!existsSync25(howToPath)) {
5645
+ writeFileSync15(howToPath, getHowToThemeDoc());
5374
5646
  }
5375
5647
  return {
5376
5648
  success: true,
@@ -5378,17 +5650,17 @@ function createTheme(projectRoot, id, name) {
5378
5650
  };
5379
5651
  }
5380
5652
  function listCustomThemes(projectRoot) {
5381
- const customThemesDir = join25(projectRoot, ".decantr", "custom", "themes");
5382
- if (!existsSync24(customThemesDir)) {
5653
+ const customThemesDir = join26(projectRoot, ".decantr", "custom", "themes");
5654
+ if (!existsSync25(customThemesDir)) {
5383
5655
  return [];
5384
5656
  }
5385
5657
  const themes = [];
5386
5658
  try {
5387
- const files = readdirSync4(customThemesDir).filter((f) => f.endsWith(".json"));
5659
+ const files = readdirSync5(customThemesDir).filter((f) => f.endsWith(".json"));
5388
5660
  for (const file of files) {
5389
- const filePath = join25(customThemesDir, file);
5661
+ const filePath = join26(customThemesDir, file);
5390
5662
  try {
5391
- const data = JSON.parse(readFileSync17(filePath, "utf-8"));
5663
+ const data = JSON.parse(readFileSync18(filePath, "utf-8"));
5392
5664
  themes.push({
5393
5665
  id: data.id || file.replace(".json", ""),
5394
5666
  name: data.name || data.id,
@@ -5403,8 +5675,8 @@ function listCustomThemes(projectRoot) {
5403
5675
  return themes;
5404
5676
  }
5405
5677
  function deleteTheme(projectRoot, id) {
5406
- const themePath = join25(projectRoot, ".decantr", "custom", "themes", `${id}.json`);
5407
- if (!existsSync24(themePath)) {
5678
+ const themePath = join26(projectRoot, ".decantr", "custom", "themes", `${id}.json`);
5679
+ if (!existsSync25(themePath)) {
5408
5680
  return {
5409
5681
  success: false,
5410
5682
  error: `Theme "${id}" not found at ${themePath}`
@@ -5421,7 +5693,7 @@ function deleteTheme(projectRoot, id) {
5421
5693
  }
5422
5694
  }
5423
5695
  function importTheme(projectRoot, sourcePath) {
5424
- if (!existsSync24(sourcePath)) {
5696
+ if (!existsSync25(sourcePath)) {
5425
5697
  return {
5426
5698
  success: false,
5427
5699
  errors: [`Source file not found: ${sourcePath}`]
@@ -5429,7 +5701,7 @@ function importTheme(projectRoot, sourcePath) {
5429
5701
  }
5430
5702
  let theme;
5431
5703
  try {
5432
- theme = JSON.parse(readFileSync17(sourcePath, "utf-8"));
5704
+ theme = JSON.parse(readFileSync18(sourcePath, "utf-8"));
5433
5705
  } catch (e) {
5434
5706
  return {
5435
5707
  success: false,
@@ -5445,14 +5717,14 @@ function importTheme(projectRoot, sourcePath) {
5445
5717
  }
5446
5718
  theme.source = "custom";
5447
5719
  const id = theme.id;
5448
- const customThemesDir = join25(projectRoot, ".decantr", "custom", "themes");
5449
- const destPath = join25(customThemesDir, `${id}.json`);
5450
- mkdirSync11(customThemesDir, { recursive: true });
5451
- const howToPath = join25(customThemesDir, "how-to-theme.md");
5452
- if (!existsSync24(howToPath)) {
5453
- writeFileSync14(howToPath, getHowToThemeDoc());
5454
- }
5455
- writeFileSync14(destPath, JSON.stringify(theme, null, 2));
5720
+ const customThemesDir = join26(projectRoot, ".decantr", "custom", "themes");
5721
+ const destPath = join26(customThemesDir, `${id}.json`);
5722
+ mkdirSync12(customThemesDir, { recursive: true });
5723
+ const howToPath = join26(customThemesDir, "how-to-theme.md");
5724
+ if (!existsSync25(howToPath)) {
5725
+ writeFileSync15(howToPath, getHowToThemeDoc());
5726
+ }
5727
+ writeFileSync15(destPath, JSON.stringify(theme, null, 2));
5456
5728
  return {
5457
5729
  success: true,
5458
5730
  path: destPath
@@ -5460,19 +5732,19 @@ function importTheme(projectRoot, sourcePath) {
5460
5732
  }
5461
5733
 
5462
5734
  // src/workspace.ts
5463
- import { existsSync as existsSync25, readdirSync as readdirSync5, readFileSync as readFileSync18 } from "fs";
5464
- import { dirname as dirname3, join as join26, resolve as resolve3 } from "path";
5735
+ import { existsSync as existsSync26, readdirSync as readdirSync6, readFileSync as readFileSync19 } from "fs";
5736
+ import { dirname as dirname3, join as join27, resolve as resolve3 } from "path";
5465
5737
  function readPackageJson(dir) {
5466
- const path = join26(dir, "package.json");
5467
- if (!existsSync25(path)) return null;
5738
+ const path = join27(dir, "package.json");
5739
+ if (!existsSync26(path)) return null;
5468
5740
  try {
5469
- return JSON.parse(readFileSync18(path, "utf-8"));
5741
+ return JSON.parse(readFileSync19(path, "utf-8"));
5470
5742
  } catch {
5471
5743
  return null;
5472
5744
  }
5473
5745
  }
5474
5746
  function hasWorkspaceMarker(dir) {
5475
- if (existsSync25(join26(dir, "pnpm-workspace.yaml")) || existsSync25(join26(dir, "turbo.json")) || existsSync25(join26(dir, "nx.json"))) {
5747
+ if (existsSync26(join27(dir, "pnpm-workspace.yaml")) || existsSync26(join27(dir, "turbo.json")) || existsSync26(join27(dir, "nx.json"))) {
5476
5748
  return true;
5477
5749
  }
5478
5750
  const pkg = readPackageJson(dir);
@@ -5488,7 +5760,7 @@ function findWorkspaceRoot(startDir) {
5488
5760
  }
5489
5761
  }
5490
5762
  function looksLikeApp(dir) {
5491
- if (existsSync25(join26(dir, "next.config.js")) || existsSync25(join26(dir, "next.config.ts")) || existsSync25(join26(dir, "next.config.mjs")) || existsSync25(join26(dir, "vite.config.ts")) || existsSync25(join26(dir, "vite.config.js")) || existsSync25(join26(dir, "angular.json")) || existsSync25(join26(dir, "svelte.config.js")) || existsSync25(join26(dir, "svelte.config.ts")) || existsSync25(join26(dir, "astro.config.mjs")) || existsSync25(join26(dir, "src")) || existsSync25(join26(dir, "app")) || existsSync25(join26(dir, "pages"))) {
5763
+ if (existsSync26(join27(dir, "next.config.js")) || existsSync26(join27(dir, "next.config.ts")) || existsSync26(join27(dir, "next.config.mjs")) || existsSync26(join27(dir, "vite.config.ts")) || existsSync26(join27(dir, "vite.config.js")) || existsSync26(join27(dir, "angular.json")) || existsSync26(join27(dir, "svelte.config.js")) || existsSync26(join27(dir, "svelte.config.ts")) || existsSync26(join27(dir, "astro.config.mjs")) || existsSync26(join27(dir, "src")) || existsSync26(join27(dir, "app")) || existsSync26(join27(dir, "pages"))) {
5492
5764
  return true;
5493
5765
  }
5494
5766
  const pkg = readPackageJson(dir);
@@ -5500,11 +5772,11 @@ function looksLikeApp(dir) {
5500
5772
  function listWorkspaceApps(workspaceRoot) {
5501
5773
  const candidates = [];
5502
5774
  for (const base of ["apps", "packages"]) {
5503
- const baseDir = join26(workspaceRoot, base);
5504
- if (!existsSync25(baseDir)) continue;
5505
- for (const entry of readdirSync5(baseDir, { withFileTypes: true })) {
5775
+ const baseDir = join27(workspaceRoot, base);
5776
+ if (!existsSync26(baseDir)) continue;
5777
+ for (const entry of readdirSync6(baseDir, { withFileTypes: true })) {
5506
5778
  if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
5507
- const candidate = join26(baseDir, entry.name);
5779
+ const candidate = join27(baseDir, entry.name);
5508
5780
  if (looksLikeApp(candidate)) {
5509
5781
  candidates.push(`${base}/${entry.name}`);
5510
5782
  }
@@ -6069,18 +6341,18 @@ function extractHostedAssetPaths(indexHtml) {
6069
6341
  return [...assetPaths];
6070
6342
  }
6071
6343
  function readHostedDistSnapshot(distPath) {
6072
- const resolvedDistPath = distPath ? resolveUserPath(distPath) : join27(process.cwd(), "dist");
6073
- const indexPath = join27(resolvedDistPath, "index.html");
6074
- if (!existsSync26(indexPath)) {
6344
+ const resolvedDistPath = distPath ? resolveUserPath(distPath) : join28(process.cwd(), "dist");
6345
+ const indexPath = join28(resolvedDistPath, "index.html");
6346
+ if (!existsSync27(indexPath)) {
6075
6347
  return void 0;
6076
6348
  }
6077
- const indexHtml = readFileSync19(indexPath, "utf-8");
6349
+ const indexHtml = readFileSync20(indexPath, "utf-8");
6078
6350
  const assetPaths = extractHostedAssetPaths(indexHtml);
6079
6351
  const assets = {};
6080
6352
  for (const assetPath of assetPaths) {
6081
- const assetFilePath = join27(resolvedDistPath, assetPath.replace(/^[/\\]+/, ""));
6082
- if (existsSync26(assetFilePath)) {
6083
- assets[assetPath] = readFileSync19(assetFilePath, "utf-8");
6353
+ const assetFilePath = join28(resolvedDistPath, assetPath.replace(/^[/\\]+/, ""));
6354
+ if (existsSync27(assetFilePath)) {
6355
+ assets[assetPath] = readFileSync20(assetFilePath, "utf-8");
6084
6356
  }
6085
6357
  }
6086
6358
  return {
@@ -6095,7 +6367,7 @@ function isHostedSourceSnapshotFile(path) {
6095
6367
  function readHostedSourceSnapshot(sourcePath) {
6096
6368
  if (!sourcePath) return void 0;
6097
6369
  const resolvedSourcePath = resolveUserPath(sourcePath);
6098
- if (!existsSync26(resolvedSourcePath)) {
6370
+ if (!existsSync27(resolvedSourcePath)) {
6099
6371
  return void 0;
6100
6372
  }
6101
6373
  const files = {};
@@ -6109,17 +6381,17 @@ function readHostedSourceSnapshot(sourcePath) {
6109
6381
  ]);
6110
6382
  const rootPrefix = basename2(resolvedSourcePath);
6111
6383
  const walk = (absoluteDir, relativeDir) => {
6112
- for (const entry of readdirSync6(absoluteDir, { withFileTypes: true })) {
6384
+ for (const entry of readdirSync7(absoluteDir, { withFileTypes: true })) {
6113
6385
  if (ignoredDirNames.has(entry.name)) continue;
6114
- const absolutePath = join27(absoluteDir, entry.name);
6115
- const relativePath = join27(relativeDir, entry.name).replace(/\\/g, "/");
6386
+ const absolutePath = join28(absoluteDir, entry.name);
6387
+ const relativePath = join28(relativeDir, entry.name).replace(/\\/g, "/");
6116
6388
  if (entry.isDirectory()) {
6117
6389
  walk(absolutePath, relativePath);
6118
6390
  continue;
6119
6391
  }
6120
6392
  if (!entry.isFile()) continue;
6121
6393
  if (!isHostedSourceSnapshotFile(relativePath)) continue;
6122
- files[relativePath] = readFileSync19(absolutePath, "utf-8");
6394
+ files[relativePath] = readFileSync20(absolutePath, "utf-8");
6123
6395
  }
6124
6396
  };
6125
6397
  walk(resolvedSourcePath, rootPrefix);
@@ -6270,16 +6542,16 @@ async function printRegistryIntelligenceSummary(namespace, jsonOutput = false) {
6270
6542
  }
6271
6543
  async function printHostedExecutionPackBundle(essencePath, namespace, jsonOutput = false, writeContext = false) {
6272
6544
  const client = getPublicAPIClient();
6273
- const resolvedPath = essencePath ? resolveUserPath(essencePath) : join27(process.cwd(), "decantr.essence.json");
6274
- if (!existsSync26(resolvedPath)) {
6545
+ const resolvedPath = essencePath ? resolveUserPath(essencePath) : join28(process.cwd(), "decantr.essence.json");
6546
+ if (!existsSync27(resolvedPath)) {
6275
6547
  throw new Error(`Essence file not found at ${resolvedPath}`);
6276
6548
  }
6277
- const essence = JSON.parse(readFileSync19(resolvedPath, "utf-8"));
6549
+ const essence = JSON.parse(readFileSync20(resolvedPath, "utf-8"));
6278
6550
  const bundle = await client.compileExecutionPacks(essence, namespace ? { namespace } : void 0);
6279
6551
  let writtenContextPaths = [];
6280
6552
  if (writeContext) {
6281
- const contextDir = join27(process.cwd(), ".decantr", "context");
6282
- mkdirSync12(contextDir, { recursive: true });
6553
+ const contextDir = join28(process.cwd(), ".decantr", "context");
6554
+ mkdirSync13(contextDir, { recursive: true });
6283
6555
  const written = writeExecutionPackBundleArtifacts(
6284
6556
  contextDir,
6285
6557
  bundle
@@ -6304,7 +6576,7 @@ async function printHostedExecutionPackBundle(essencePath, namespace, jsonOutput
6304
6576
  console.log(` Sections: ${typedBundle.sections.length}`);
6305
6577
  console.log(` Mutations: ${typedBundle.mutations.length}`);
6306
6578
  if (writeContext) {
6307
- console.log(` Context bundle: ${join27(process.cwd(), ".decantr", "context")}`);
6579
+ console.log(` Context bundle: ${join28(process.cwd(), ".decantr", "context")}`);
6308
6580
  console.log(` Files written: ${writtenContextPaths.length}`);
6309
6581
  }
6310
6582
  console.log("");
@@ -6315,16 +6587,33 @@ async function printHostedExecutionPackBundle(essencePath, namespace, jsonOutput
6315
6587
  console.log(` ${cyan3(route.path)} -> ${pageLabel} [${patterns}]`);
6316
6588
  }
6317
6589
  }
6590
+ function resolvePagePackIdForRoute(essencePath, route) {
6591
+ if (!existsSync27(essencePath)) {
6592
+ throw new Error(`Essence file not found at ${essencePath}`);
6593
+ }
6594
+ const essence = JSON.parse(readFileSync20(essencePath, "utf-8"));
6595
+ if (!isV47(essence)) {
6596
+ throw new Error("Route-based pack resolution requires Essence v4.0.0.");
6597
+ }
6598
+ const target = essence.blueprint.routes?.[route];
6599
+ if (!target) {
6600
+ const known = Object.keys(essence.blueprint.routes ?? {}).sort();
6601
+ throw new Error(
6602
+ `Route "${route}" was not found in blueprint.routes. Known routes: ${known.join(", ") || "none"}.`
6603
+ );
6604
+ }
6605
+ return target.page;
6606
+ }
6318
6607
  async function printHostedSelectedExecutionPack(packType, id, essencePath, namespace, jsonOutput = false, writeContext = false) {
6319
6608
  const client = getPublicAPIClient();
6320
- const resolvedPath = essencePath ? resolveUserPath(essencePath) : join27(process.cwd(), "decantr.essence.json");
6321
- if (!existsSync26(resolvedPath)) {
6609
+ const resolvedPath = essencePath ? resolveUserPath(essencePath) : join28(process.cwd(), "decantr.essence.json");
6610
+ if (!existsSync27(resolvedPath)) {
6322
6611
  throw new Error(`Essence file not found at ${resolvedPath}`);
6323
6612
  }
6324
6613
  if ((packType === "section" || packType === "page" || packType === "mutation") && !id) {
6325
6614
  throw new Error(`Pack type "${packType}" requires an id.`);
6326
6615
  }
6327
- const essence = JSON.parse(readFileSync19(resolvedPath, "utf-8"));
6616
+ const essence = JSON.parse(readFileSync20(resolvedPath, "utf-8"));
6328
6617
  const selected = await client.selectExecutionPack(
6329
6618
  {
6330
6619
  essence,
@@ -6335,17 +6624,17 @@ async function printHostedSelectedExecutionPack(packType, id, essencePath, names
6335
6624
  );
6336
6625
  let writtenContextDir = null;
6337
6626
  if (writeContext) {
6338
- const contextDir = join27(process.cwd(), ".decantr", "context");
6339
- mkdirSync12(contextDir, { recursive: true });
6340
- writeFileSync15(
6341
- join27(contextDir, "pack-manifest.json"),
6627
+ const contextDir = join28(process.cwd(), ".decantr", "context");
6628
+ mkdirSync13(contextDir, { recursive: true });
6629
+ writeFileSync16(
6630
+ join28(contextDir, "pack-manifest.json"),
6342
6631
  JSON.stringify(selected.manifest, null, 2) + "\n"
6343
6632
  );
6344
6633
  const manifestEntry = selected.selector.packType === "scaffold" ? selected.manifest.scaffold : selected.selector.packType === "review" ? selected.manifest.review : selected.selector.packType === "section" ? selected.manifest.sections.find((entry) => entry.id === selected.selector.id) : selected.selector.packType === "page" ? selected.manifest.pages.find((entry) => entry.id === selected.selector.id) : selected.manifest.mutations.find((entry) => entry.id === selected.selector.id);
6345
6634
  const markdownFile = manifestEntry?.markdown ?? `${selected.selector.packType}${selected.selector.id ? `-${selected.selector.id}` : ""}-pack.md`;
6346
6635
  const jsonFile = manifestEntry?.json ?? `${selected.selector.packType}${selected.selector.id ? `-${selected.selector.id}` : ""}-pack.json`;
6347
- writeFileSync15(join27(contextDir, markdownFile), selected.pack.renderedMarkdown);
6348
- writeFileSync15(join27(contextDir, jsonFile), JSON.stringify(selected.pack, null, 2) + "\n");
6636
+ writeFileSync16(join28(contextDir, markdownFile), selected.pack.renderedMarkdown);
6637
+ writeFileSync16(join28(contextDir, jsonFile), JSON.stringify(selected.pack, null, 2) + "\n");
6349
6638
  writtenContextDir = contextDir;
6350
6639
  }
6351
6640
  if (jsonOutput) {
@@ -6370,20 +6659,20 @@ async function printHostedSelectedExecutionPack(packType, id, essencePath, names
6370
6659
  }
6371
6660
  async function printHostedExecutionPackManifest(essencePath, namespace, jsonOutput = false, writeContext = false) {
6372
6661
  const client = getPublicAPIClient();
6373
- const resolvedPath = essencePath ? resolveUserPath(essencePath) : join27(process.cwd(), "decantr.essence.json");
6374
- if (!existsSync26(resolvedPath)) {
6662
+ const resolvedPath = essencePath ? resolveUserPath(essencePath) : join28(process.cwd(), "decantr.essence.json");
6663
+ if (!existsSync27(resolvedPath)) {
6375
6664
  throw new Error(`Essence file not found at ${resolvedPath}`);
6376
6665
  }
6377
- const essence = JSON.parse(readFileSync19(resolvedPath, "utf-8"));
6666
+ const essence = JSON.parse(readFileSync20(resolvedPath, "utf-8"));
6378
6667
  const manifest = await client.getExecutionPackManifest(
6379
6668
  essence,
6380
6669
  namespace ? { namespace } : void 0
6381
6670
  );
6382
6671
  let writtenContextDir = null;
6383
6672
  if (writeContext) {
6384
- const contextDir = join27(process.cwd(), ".decantr", "context");
6385
- mkdirSync12(contextDir, { recursive: true });
6386
- writeFileSync15(join27(contextDir, "pack-manifest.json"), JSON.stringify(manifest, null, 2) + "\n");
6673
+ const contextDir = join28(process.cwd(), ".decantr", "context");
6674
+ mkdirSync13(contextDir, { recursive: true });
6675
+ writeFileSync16(join28(contextDir, "pack-manifest.json"), JSON.stringify(manifest, null, 2) + "\n");
6387
6676
  writtenContextDir = contextDir;
6388
6677
  }
6389
6678
  if (jsonOutput) {
@@ -6404,14 +6693,14 @@ async function printHostedExecutionPackManifest(essencePath, namespace, jsonOutp
6404
6693
  }
6405
6694
  }
6406
6695
  async function hydrateHostedExecutionPacksIfMissing(projectRoot, namespace = "@official") {
6407
- const contextDir = join27(projectRoot, ".decantr", "context");
6408
- const reviewPackPath = join27(contextDir, "review-pack.json");
6409
- const manifestPath = join27(contextDir, "pack-manifest.json");
6410
- if (existsSync26(reviewPackPath) && existsSync26(manifestPath)) {
6696
+ const contextDir = join28(projectRoot, ".decantr", "context");
6697
+ const reviewPackPath = join28(contextDir, "review-pack.json");
6698
+ const manifestPath = join28(contextDir, "pack-manifest.json");
6699
+ if (existsSync27(reviewPackPath) && existsSync27(manifestPath)) {
6411
6700
  return { attempted: false, hydrated: false };
6412
6701
  }
6413
- const essencePath = join27(projectRoot, "decantr.essence.json");
6414
- if (!existsSync26(essencePath)) {
6702
+ const essencePath = join28(projectRoot, "decantr.essence.json");
6703
+ if (!existsSync27(essencePath)) {
6415
6704
  return { attempted: false, hydrated: false };
6416
6705
  }
6417
6706
  const reviewHydration = await hydrateHostedReviewPackIfMissing(projectRoot, namespace);
@@ -6420,9 +6709,9 @@ async function hydrateHostedExecutionPacksIfMissing(projectRoot, namespace = "@o
6420
6709
  }
6421
6710
  try {
6422
6711
  const client = getPublicAPIClient();
6423
- const essence = JSON.parse(readFileSync19(essencePath, "utf-8"));
6712
+ const essence = JSON.parse(readFileSync20(essencePath, "utf-8"));
6424
6713
  const bundle = await client.compileExecutionPacks(essence, { namespace });
6425
- mkdirSync12(contextDir, { recursive: true });
6714
+ mkdirSync13(contextDir, { recursive: true });
6426
6715
  writeExecutionPackBundleArtifacts(contextDir, bundle);
6427
6716
  return { attempted: true, hydrated: true, scope: "bundle" };
6428
6717
  } catch {
@@ -6430,19 +6719,19 @@ async function hydrateHostedExecutionPacksIfMissing(projectRoot, namespace = "@o
6430
6719
  }
6431
6720
  }
6432
6721
  async function hydrateHostedReviewPackIfMissing(projectRoot, namespace = "@official") {
6433
- const contextDir = join27(projectRoot, ".decantr", "context");
6434
- const reviewPackPath = join27(contextDir, "review-pack.json");
6435
- const manifestPath = join27(contextDir, "pack-manifest.json");
6436
- if (existsSync26(reviewPackPath) && existsSync26(manifestPath)) {
6722
+ const contextDir = join28(projectRoot, ".decantr", "context");
6723
+ const reviewPackPath = join28(contextDir, "review-pack.json");
6724
+ const manifestPath = join28(contextDir, "pack-manifest.json");
6725
+ if (existsSync27(reviewPackPath) && existsSync27(manifestPath)) {
6437
6726
  return { attempted: false, hydrated: false };
6438
6727
  }
6439
- const essencePath = join27(projectRoot, "decantr.essence.json");
6440
- if (!existsSync26(essencePath)) {
6728
+ const essencePath = join28(projectRoot, "decantr.essence.json");
6729
+ if (!existsSync27(essencePath)) {
6441
6730
  return { attempted: false, hydrated: false };
6442
6731
  }
6443
6732
  try {
6444
6733
  const client = getPublicAPIClient();
6445
- const essence = JSON.parse(readFileSync19(essencePath, "utf-8"));
6734
+ const essence = JSON.parse(readFileSync20(essencePath, "utf-8"));
6446
6735
  const selected = await client.selectExecutionPack(
6447
6736
  {
6448
6737
  essence,
@@ -6450,14 +6739,14 @@ async function hydrateHostedReviewPackIfMissing(projectRoot, namespace = "@offic
6450
6739
  },
6451
6740
  { namespace }
6452
6741
  );
6453
- mkdirSync12(contextDir, { recursive: true });
6454
- writeFileSync15(join27(contextDir, "review-pack.md"), selected.pack.renderedMarkdown);
6455
- writeFileSync15(
6456
- join27(contextDir, "review-pack.json"),
6742
+ mkdirSync13(contextDir, { recursive: true });
6743
+ writeFileSync16(join28(contextDir, "review-pack.md"), selected.pack.renderedMarkdown);
6744
+ writeFileSync16(
6745
+ join28(contextDir, "review-pack.json"),
6457
6746
  JSON.stringify(selected.pack, null, 2) + "\n"
6458
6747
  );
6459
- if (!existsSync26(manifestPath)) {
6460
- writeFileSync15(manifestPath, JSON.stringify(selected.manifest, null, 2) + "\n");
6748
+ if (!existsSync27(manifestPath)) {
6749
+ writeFileSync16(manifestPath, JSON.stringify(selected.manifest, null, 2) + "\n");
6461
6750
  }
6462
6751
  return { attempted: true, hydrated: true, scope: "review" };
6463
6752
  } catch {
@@ -6467,17 +6756,17 @@ async function hydrateHostedReviewPackIfMissing(projectRoot, namespace = "@offic
6467
6756
  async function printHostedFileCritique(sourcePath, namespace, jsonOutput = false, essencePath, treatmentsPath) {
6468
6757
  const client = getPublicAPIClient();
6469
6758
  const resolvedSourcePath = resolveUserPath(sourcePath);
6470
- const resolvedEssencePath = essencePath ? resolveUserPath(essencePath) : join27(process.cwd(), "decantr.essence.json");
6471
- const resolvedTreatmentsPath = treatmentsPath ? resolveUserPath(treatmentsPath) : join27(process.cwd(), "src", "styles", "treatments.css");
6472
- if (!existsSync26(resolvedSourcePath)) {
6759
+ const resolvedEssencePath = essencePath ? resolveUserPath(essencePath) : join28(process.cwd(), "decantr.essence.json");
6760
+ const resolvedTreatmentsPath = treatmentsPath ? resolveUserPath(treatmentsPath) : join28(process.cwd(), "src", "styles", "treatments.css");
6761
+ if (!existsSync27(resolvedSourcePath)) {
6473
6762
  throw new Error(`Source file not found at ${resolvedSourcePath}`);
6474
6763
  }
6475
- if (!existsSync26(resolvedEssencePath)) {
6764
+ if (!existsSync27(resolvedEssencePath)) {
6476
6765
  throw new Error(`Essence file not found at ${resolvedEssencePath}`);
6477
6766
  }
6478
- const code = readFileSync19(resolvedSourcePath, "utf-8");
6479
- const essence = JSON.parse(readFileSync19(resolvedEssencePath, "utf-8"));
6480
- const treatmentsCss = existsSync26(resolvedTreatmentsPath) ? readFileSync19(resolvedTreatmentsPath, "utf-8") : void 0;
6767
+ const code = readFileSync20(resolvedSourcePath, "utf-8");
6768
+ const essence = JSON.parse(readFileSync20(resolvedEssencePath, "utf-8"));
6769
+ const treatmentsCss = existsSync27(resolvedTreatmentsPath) ? readFileSync20(resolvedTreatmentsPath, "utf-8") : void 0;
6481
6770
  const report = await client.critiqueFile(
6482
6771
  {
6483
6772
  essence,
@@ -6501,11 +6790,11 @@ async function printHostedFileCritique(sourcePath, namespace, jsonOutput = false
6501
6790
  }
6502
6791
  async function printHostedProjectAudit(namespace, jsonOutput = false, essencePath, distPath, sourcesPath) {
6503
6792
  const client = getPublicAPIClient();
6504
- const resolvedEssencePath = essencePath ? resolveUserPath(essencePath) : join27(process.cwd(), "decantr.essence.json");
6505
- if (!existsSync26(resolvedEssencePath)) {
6793
+ const resolvedEssencePath = essencePath ? resolveUserPath(essencePath) : join28(process.cwd(), "decantr.essence.json");
6794
+ if (!existsSync27(resolvedEssencePath)) {
6506
6795
  throw new Error(`Essence file not found at ${resolvedEssencePath}`);
6507
6796
  }
6508
- const essence = JSON.parse(readFileSync19(resolvedEssencePath, "utf-8"));
6797
+ const essence = JSON.parse(readFileSync20(resolvedEssencePath, "utf-8"));
6509
6798
  const dist = readHostedDistSnapshot(distPath);
6510
6799
  const sources = readHostedSourceSnapshot(sourcesPath);
6511
6800
  const report = await client.auditProject(
@@ -6523,7 +6812,7 @@ async function printHostedProjectAudit(namespace, jsonOutput = false, essencePat
6523
6812
  console.log(heading2("Hosted Project Audit"));
6524
6813
  console.log(` Essence: ${resolvedEssencePath}`);
6525
6814
  console.log(
6526
- ` Dist snapshot: ${dist ? distPath ? resolveUserPath(distPath) : join27(process.cwd(), "dist") : "none"}`
6815
+ ` Dist snapshot: ${dist ? distPath ? resolveUserPath(distPath) : join28(process.cwd(), "dist") : "none"}`
6527
6816
  );
6528
6817
  console.log(
6529
6818
  ` Source snapshot: ${sources && sourcesPath ? resolveUserPath(sourcesPath) : "none"}`
@@ -6605,42 +6894,151 @@ async function cmdSearch(query, type, sort, recommended, intelligenceSource, blu
6605
6894
  console.log(dim3(`Search failed. API may be unavailable.`));
6606
6895
  }
6607
6896
  }
6608
- async function cmdSuggest(query, type) {
6609
- const apiClient = getAPIClient();
6610
- const searchType = type || "pattern";
6611
- try {
6612
- const response = await apiClient.search({ q: query, type: searchType });
6613
- const results = response.results;
6614
- if (results.length === 0) {
6615
- console.log(dim3(`No suggestions for "${query}"`));
6616
- console.log("");
6617
- console.log("Try:");
6618
- console.log(` ${cyan3("decantr list patterns")} - see all patterns`);
6619
- console.log(` ${cyan3("decantr search <broader-term>")} - broaden your search`);
6620
- return;
6897
+ function isRecord(value) {
6898
+ return typeof value === "object" && value !== null && !Array.isArray(value);
6899
+ }
6900
+ function patternCandidateFromRegistryItem(item, source) {
6901
+ const record = item;
6902
+ const data = isRecord(record.data) ? record.data : record;
6903
+ const slug = typeof record.slug === "string" && record.slug || typeof data.slug === "string" && data.slug || typeof data.id === "string" && data.id || typeof record.id === "string" && record.id || "pattern";
6904
+ return patternToDiscoveryCandidate(
6905
+ {
6906
+ ...data,
6907
+ id: typeof data.id === "string" ? data.id : slug,
6908
+ slug,
6909
+ name: typeof data.name === "string" ? data.name : typeof record.name === "string" ? record.name : slug,
6910
+ description: typeof data.description === "string" ? data.description : typeof record.description === "string" ? record.description : void 0
6911
+ },
6912
+ { source, slug }
6913
+ );
6914
+ }
6915
+ function readSuggestCodeContext(route, file) {
6916
+ const pieces = [];
6917
+ if (file) {
6918
+ const resolved = isAbsolute(file) ? file : join28(process.cwd(), file);
6919
+ if (existsSync27(resolved)) {
6920
+ pieces.push(readFileSync20(resolved, "utf-8"));
6621
6921
  }
6622
- console.log(heading2(`Suggestions for "${query}"`));
6623
- const queryLower = query.toLowerCase();
6624
- const exact = results.filter((r) => r.slug.toLowerCase().includes(queryLower));
6625
- const related = results.filter((r) => !r.slug.toLowerCase().includes(queryLower));
6626
- if (exact.length > 0) {
6627
- console.log(`${BOLD7}Direct matches:${RESET14}`);
6628
- for (const r of exact.slice(0, 3)) {
6629
- console.log(` ${cyan3(r.slug)} - ${r.description || ""}`);
6922
+ }
6923
+ if (route) {
6924
+ const analysisPath = join28(process.cwd(), ".decantr", "analysis.json");
6925
+ if (existsSync27(analysisPath)) {
6926
+ try {
6927
+ const analysis = JSON.parse(readFileSync20(analysisPath, "utf-8"));
6928
+ const routeEntry = analysis.routes?.routes?.find((entry) => entry.path === route);
6929
+ if (routeEntry?.file) {
6930
+ const resolved = join28(process.cwd(), routeEntry.file);
6931
+ if (existsSync27(resolved)) {
6932
+ pieces.push(readFileSync20(resolved, "utf-8"));
6933
+ }
6934
+ }
6935
+ } catch {
6630
6936
  }
6631
- console.log("");
6632
6937
  }
6633
- if (related.length > 0) {
6634
- console.log(`${BOLD7}Related:${RESET14}`);
6635
- for (const r of related.slice(0, 5)) {
6636
- console.log(` ${cyan3(r.slug)} - ${r.description || ""}`);
6637
- }
6638
- console.log("");
6938
+ }
6939
+ return pieces.join("\n\n").slice(0, 2e4);
6940
+ }
6941
+ async function loadPatternDiscoveryCandidates(registryClient) {
6942
+ const candidates = [];
6943
+ const seen = /* @__PURE__ */ new Set();
6944
+ const add = (candidate) => {
6945
+ const key = candidate.slug || candidate.id;
6946
+ if (seen.has(key)) return;
6947
+ seen.add(key);
6948
+ candidates.push(candidate);
6949
+ };
6950
+ const bundledPatterns = loadBundledContentList("patterns");
6951
+ for (const entry of bundledPatterns) {
6952
+ add(patternToDiscoveryCandidate(entry.data, { source: "bundled", slug: entry.id }));
6953
+ }
6954
+ try {
6955
+ const result = await registryClient.fetchContentList("patterns");
6956
+ for (const item of result.data.items) {
6957
+ const source = result.source.type === "api" ? "hosted" : result.source.type;
6958
+ add(patternCandidateFromRegistryItem(item, source));
6639
6959
  }
6640
- console.log(dim3(`Use "decantr get pattern <id>" for full details`));
6641
6960
  } catch {
6642
- console.log(dim3(`Suggestion search failed. API may be unavailable.`));
6643
6961
  }
6962
+ for (const item of registryClient.listCustomContent("patterns")) {
6963
+ add(patternCandidateFromRegistryItem(item, "custom"));
6964
+ }
6965
+ return candidates;
6966
+ }
6967
+ async function cmdSuggest(query, options = {}) {
6968
+ const searchType = options.type || "pattern";
6969
+ if (searchType !== "pattern" && searchType !== "patterns") {
6970
+ const apiClient = getAPIClient();
6971
+ try {
6972
+ const response = await apiClient.search({ q: query, type: searchType });
6973
+ const results = response.results;
6974
+ if (results.length === 0) {
6975
+ console.log(dim3(`No suggestions for "${query}"`));
6976
+ return;
6977
+ }
6978
+ console.log(heading2(`Suggestions for "${query}"`));
6979
+ for (const r of results.slice(0, 8)) {
6980
+ console.log(` ${cyan3(r.slug)} - ${r.description || r.name || ""}`);
6981
+ }
6982
+ return;
6983
+ } catch {
6984
+ console.log(dim3(`Suggestion search failed. API may be unavailable.`));
6985
+ return;
6986
+ }
6987
+ }
6988
+ const registryClient = new RegistryClient({
6989
+ cacheDir: join28(process.cwd(), ".decantr", "cache")
6990
+ });
6991
+ const code = options.fromCode || options.file ? readSuggestCodeContext(options.route, options.file) : "";
6992
+ const candidates = await loadPatternDiscoveryCandidates(registryClient);
6993
+ const matches = rankPatternCandidates(
6994
+ {
6995
+ query,
6996
+ route: options.route,
6997
+ code,
6998
+ limit: 10
6999
+ },
7000
+ candidates
7001
+ );
7002
+ if (matches.length === 0) {
7003
+ console.log(dim3(`No pattern suggestions for "${query}"`));
7004
+ console.log("");
7005
+ console.log("Try:");
7006
+ console.log(` ${cyan3("decantr list patterns")} - browse slug, name, domain, and source`);
7007
+ console.log(
7008
+ ` ${cyan3('decantr suggest "<broader description>" --from-code --route <route>')} - rank from observed code`
7009
+ );
7010
+ return;
7011
+ }
7012
+ const contextBits = [
7013
+ options.route ? `route ${options.route}` : null,
7014
+ options.file ? `file ${options.file}` : null,
7015
+ code ? "code context" : null
7016
+ ].filter((entry) => Boolean(entry));
7017
+ console.log(
7018
+ heading2(
7019
+ `Pattern suggestions for "${query}"${contextBits.length > 0 ? ` (${contextBits.join(", ")})` : ""}`
7020
+ )
7021
+ );
7022
+ for (const match of matches.slice(0, 8)) {
7023
+ const candidate = match.candidate;
7024
+ const slug = candidate.slug || candidate.id;
7025
+ const details = [
7026
+ candidate.name && candidate.name !== slug ? candidate.name : null,
7027
+ candidate.domain || candidate.category || null,
7028
+ candidate.source || null
7029
+ ].filter(Boolean);
7030
+ console.log(
7031
+ ` ${cyan3(slug)} score ${match.score}${details.length > 0 ? ` ${dim3(details.join(" | "))}` : ""}`
7032
+ );
7033
+ if (candidate.description) {
7034
+ console.log(` ${dim3(candidate.description)}`);
7035
+ }
7036
+ if (match.reasons.length > 0) {
7037
+ console.log(` ${dim3(`why: ${match.reasons.slice(0, 2).join("; ")}`)}`);
7038
+ }
7039
+ }
7040
+ console.log("");
7041
+ console.log(dim3('Use "decantr get pattern <slug>" for full details.'));
6644
7042
  }
6645
7043
  async function cmdGet(type, id) {
6646
7044
  if (!isGetContentType(type)) {
@@ -6650,26 +7048,16 @@ async function cmdGet(type, id) {
6650
7048
  }
6651
7049
  const apiType = CONTENT_TYPE_TO_API_CONTENT_TYPE3[type];
6652
7050
  const registryClient = new RegistryClient({
6653
- cacheDir: join27(process.cwd(), ".decantr", "cache")
7051
+ cacheDir: join28(process.cwd(), ".decantr", "cache")
6654
7052
  });
6655
7053
  const result = await registryClient.fetchContentItem(apiType, id);
6656
7054
  if (result) {
6657
7055
  console.log(JSON.stringify(result.data, null, 2));
6658
7056
  return;
6659
7057
  }
6660
- const currentDir = dirname4(fileURLToPath2(import.meta.url));
6661
- const bundledCandidates = [
6662
- join27(currentDir, "bundled", apiType, `${id}.json`),
6663
- // Running from src/
6664
- join27(currentDir, "..", "src", "bundled", apiType, `${id}.json`),
6665
- // Running from dist/
6666
- join27(currentDir, "..", "bundled", apiType, `${id}.json`)
6667
- // Alternative dist layout
6668
- ];
6669
- const bundledPath = bundledCandidates.find((p) => existsSync26(p)) || null;
6670
- if (bundledPath) {
6671
- const data = JSON.parse(readFileSync19(bundledPath, "utf-8"));
6672
- console.log(JSON.stringify(data, null, 2));
7058
+ const bundled = loadBundledContentItem(apiType, id);
7059
+ if (bundled) {
7060
+ console.log(JSON.stringify(bundled.data, null, 2));
6673
7061
  return;
6674
7062
  }
6675
7063
  console.error(error3(`${type} "${id}" not found.`));
@@ -6677,10 +7065,10 @@ async function cmdGet(type, id) {
6677
7065
  return;
6678
7066
  }
6679
7067
  async function cmdValidate(path) {
6680
- const essencePath = path || join27(process.cwd(), "decantr.essence.json");
7068
+ const essencePath = path || join28(process.cwd(), "decantr.essence.json");
6681
7069
  let raw;
6682
7070
  try {
6683
- raw = readFileSync19(essencePath, "utf-8");
7071
+ raw = readFileSync20(essencePath, "utf-8");
6684
7072
  } catch {
6685
7073
  console.error(error3(`Could not read ${essencePath}`));
6686
7074
  process.exitCode = 1;
@@ -6747,7 +7135,7 @@ async function cmdList(type, sort, recommended, intelligenceSource, blueprintSet
6747
7135
  return;
6748
7136
  }
6749
7137
  const registryClient = new RegistryClient({
6750
- cacheDir: join27(process.cwd(), ".decantr", "cache")
7138
+ cacheDir: join28(process.cwd(), ".decantr", "cache")
6751
7139
  });
6752
7140
  const result = await registryClient.fetchContentList(
6753
7141
  type,
@@ -6757,7 +7145,13 @@ async function cmdList(type, sort, recommended, intelligenceSource, blueprintSet
6757
7145
  intelligenceSource,
6758
7146
  blueprintSet
6759
7147
  );
6760
- const items = result.data.items;
7148
+ const bundledPatternItems = type === "patterns" ? loadBundledContentList("patterns").map((entry) => ({
7149
+ ...entry.data,
7150
+ id: entry.data.id || entry.id,
7151
+ slug: entry.data.slug || entry.id,
7152
+ source: "bundled"
7153
+ })) : [];
7154
+ const items = type === "patterns" ? [...bundledPatternItems, ...result.data.items] : result.data.items;
6761
7155
  if (items.length === 0) {
6762
7156
  console.log(dim3(`No ${type} found.`));
6763
7157
  return;
@@ -6784,9 +7178,21 @@ async function cmdList(type, sort, recommended, intelligenceSource, blueprintSet
6784
7178
  } else {
6785
7179
  console.log(heading2(`${items.length} ${type} found`));
6786
7180
  for (const item of items) {
6787
- console.log(
6788
- ` ${cyan3(formatRegistryListIdentifier(item))} ${dim3(item.description || item.name || "")}`
6789
- );
7181
+ if (type === "patterns") {
7182
+ const pattern = item;
7183
+ const slug = pattern.slug || pattern.id;
7184
+ const domain = pattern.domain || pattern.category || pattern.tags?.[0] || "general";
7185
+ const source = pattern.source || (result.source.type === "api" ? "hosted" : result.source.type);
7186
+ const label = [pattern.name && pattern.name !== slug ? pattern.name : null, domain, source].filter(Boolean).join(" | ");
7187
+ console.log(` ${cyan3(slug)} ${dim3(label)}`);
7188
+ if (pattern.description) {
7189
+ console.log(` ${dim3(pattern.description)}`);
7190
+ }
7191
+ } else {
7192
+ console.log(
7193
+ ` ${cyan3(formatRegistryListIdentifier(item))} ${dim3(item.description || item.name || "")}`
7194
+ );
7195
+ }
6790
7196
  const intelligenceSummary = formatIntelligenceSummary(
6791
7197
  item.intelligence
6792
7198
  );
@@ -6812,10 +7218,10 @@ ${CYAN8}Telemetry enabled.${RESET14} Decantr will send privacy-filtered CLI prod
6812
7218
  }
6813
7219
  function readCliPackageVersion() {
6814
7220
  const here = dirname4(fileURLToPath2(import.meta.url));
6815
- const candidates = [join27(here, "..", "package.json"), join27(here, "..", "..", "package.json")];
7221
+ const candidates = [join28(here, "..", "package.json"), join28(here, "..", "..", "package.json")];
6816
7222
  for (const candidate of candidates) {
6817
7223
  try {
6818
- const pkg = JSON.parse(readFileSync19(candidate, "utf-8"));
7224
+ const pkg = JSON.parse(readFileSync20(candidate, "utf-8"));
6819
7225
  if (pkg.version) return pkg.version;
6820
7226
  } catch {
6821
7227
  }
@@ -6826,19 +7232,19 @@ function timestampForFile() {
6826
7232
  return (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
6827
7233
  }
6828
7234
  function backupExistingEssence(projectRoot, label) {
6829
- const essencePath = join27(projectRoot, "decantr.essence.json");
6830
- if (!existsSync26(essencePath)) return null;
6831
- const backupPath = join27(
7235
+ const essencePath = join28(projectRoot, "decantr.essence.json");
7236
+ if (!existsSync27(essencePath)) return null;
7237
+ const backupPath = join28(
6832
7238
  projectRoot,
6833
7239
  `decantr.essence.${label}.${timestampForFile()}.backup.json`
6834
7240
  );
6835
- writeFileSync15(backupPath, readFileSync19(essencePath, "utf-8"), "utf-8");
7241
+ writeFileSync16(backupPath, readFileSync20(essencePath, "utf-8"), "utf-8");
6836
7242
  return backupPath;
6837
7243
  }
6838
7244
  function writeBrownfieldProjectJson(input) {
6839
- const decantrDir = join27(input.projectRoot, ".decantr");
6840
- mkdirSync12(join27(decantrDir, "context"), { recursive: true });
6841
- mkdirSync12(join27(decantrDir, "cache"), { recursive: true });
7245
+ const decantrDir = join28(input.projectRoot, ".decantr");
7246
+ mkdirSync13(join28(decantrDir, "context"), { recursive: true });
7247
+ mkdirSync13(join28(decantrDir, "cache"), { recursive: true });
6842
7248
  const now = (/* @__PURE__ */ new Date()).toISOString();
6843
7249
  const projectJson = {
6844
7250
  detected: {
@@ -6879,7 +7285,7 @@ function writeBrownfieldProjectJson(input) {
6879
7285
  }
6880
7286
  }
6881
7287
  };
6882
- writeFileSync15(join27(decantrDir, "project.json"), JSON.stringify(projectJson, null, 2) + "\n");
7288
+ writeFileSync16(join28(decantrDir, "project.json"), JSON.stringify(projectJson, null, 2) + "\n");
6883
7289
  }
6884
7290
  async function applyAcceptedBrownfieldProposal(input) {
6885
7291
  const proposal = readBrownfieldProposal(input.projectRoot);
@@ -6895,8 +7301,8 @@ async function applyAcceptedBrownfieldProposal(input) {
6895
7301
  process.exitCode = 1;
6896
7302
  return;
6897
7303
  }
6898
- const essencePath = join27(input.projectRoot, "decantr.essence.json");
6899
- const hasEssence = existsSync26(essencePath);
7304
+ const essencePath = join28(input.projectRoot, "decantr.essence.json");
7305
+ const hasEssence = existsSync27(essencePath);
6900
7306
  let essence;
6901
7307
  let backupPath = null;
6902
7308
  if (input.mode === "accept" && hasEssence) {
@@ -6910,7 +7316,7 @@ async function applyAcceptedBrownfieldProposal(input) {
6910
7316
  return;
6911
7317
  }
6912
7318
  if (input.mode === "merge" && hasEssence) {
6913
- const existing = JSON.parse(readFileSync19(essencePath, "utf-8"));
7319
+ const existing = JSON.parse(readFileSync20(essencePath, "utf-8"));
6914
7320
  if (!isV47(existing)) {
6915
7321
  console.log(
6916
7322
  error3(
@@ -6947,9 +7353,9 @@ async function applyAcceptedBrownfieldProposal(input) {
6947
7353
  assistantBridge: input.assistantBridge,
6948
7354
  mode: input.mode
6949
7355
  });
6950
- writeFileSync15(essencePath, JSON.stringify(essence, null, 2) + "\n", "utf-8");
7356
+ writeFileSync16(essencePath, JSON.stringify(essence, null, 2) + "\n", "utf-8");
6951
7357
  const registryClient = new RegistryClient({
6952
- cacheDir: join27(input.projectRoot, ".decantr", "cache"),
7358
+ cacheDir: join28(input.projectRoot, ".decantr", "cache"),
6953
7359
  offline: true,
6954
7360
  projectRoot: input.projectRoot
6955
7361
  });
@@ -7103,7 +7509,7 @@ async function cmdInit(args) {
7103
7509
  }
7104
7510
  }
7105
7511
  const registryClient = new RegistryClient({
7106
- cacheDir: join27(projectRoot, ".decantr", "cache"),
7512
+ cacheDir: join28(projectRoot, ".decantr", "cache"),
7107
7513
  apiUrl: args.registry,
7108
7514
  offline: args.offline,
7109
7515
  projectRoot
@@ -7433,7 +7839,7 @@ ${YELLOW9}You're offline. Scaffolding Decantr default.${RESET14}`);
7433
7839
  if (appliedRuleFiles.length > 0) {
7434
7840
  console.log(` ${dim3(`Rule bridge applied: ${appliedRuleFiles.join(", ")}`)}`);
7435
7841
  }
7436
- if (!existsSync26(join27(projectRoot, "package.json"))) {
7842
+ if (!existsSync27(join28(projectRoot, "package.json"))) {
7437
7843
  console.log("");
7438
7844
  console.log(
7439
7845
  dim3(` Note: ${cyan3("decantr init")} created Decantr contract/context files only.`)
@@ -7444,7 +7850,7 @@ ${YELLOW9}You're offline. Scaffolding Decantr default.${RESET14}`);
7444
7850
  )
7445
7851
  );
7446
7852
  }
7447
- const hasCompiledPacks = existsSync26(join27(projectRoot, ".decantr", "context", "scaffold-pack.md"));
7853
+ const hasCompiledPacks = existsSync27(join28(projectRoot, ".decantr", "context", "scaffold-pack.md"));
7448
7854
  console.log("");
7449
7855
  console.log(" Next steps:");
7450
7856
  if (hasCompiledPacks) {
@@ -7484,7 +7890,7 @@ ${YELLOW9}You're offline. Scaffolding Decantr default.${RESET14}`);
7484
7890
  console.log(` ${cyan3("decantr upgrade")} Update to latest patterns`);
7485
7891
  console.log(` ${cyan3("decantr check")} Detect drift issues`);
7486
7892
  console.log(` ${cyan3("decantr migrate --to v4")} Migrate older essence files to v4`);
7487
- const essenceContent = readFileSync19(result.essencePath, "utf-8");
7893
+ const essenceContent = readFileSync20(result.essencePath, "utf-8");
7488
7894
  const essence = JSON.parse(essenceContent);
7489
7895
  const validation = validateEssence2(essence);
7490
7896
  if (!validation.valid) {
@@ -7540,16 +7946,16 @@ Validation warnings: ${validation.errors.join(", ")}`));
7540
7946
  }
7541
7947
  async function cmdStatus() {
7542
7948
  const projectRoot = process.cwd();
7543
- const essencePath = join27(projectRoot, "decantr.essence.json");
7544
- const projectJsonPath = join27(projectRoot, ".decantr", "project.json");
7949
+ const essencePath = join28(projectRoot, "decantr.essence.json");
7950
+ const projectJsonPath = join28(projectRoot, ".decantr", "project.json");
7545
7951
  console.log(heading2("Decantr Project Status"));
7546
- if (!existsSync26(essencePath)) {
7952
+ if (!existsSync27(essencePath)) {
7547
7953
  console.log(`${RED11}No decantr.essence.json found.${RESET14}`);
7548
7954
  console.log(dim3('Run "decantr init" to create one.'));
7549
7955
  return;
7550
7956
  }
7551
7957
  try {
7552
- const essence = JSON.parse(readFileSync19(essencePath, "utf-8"));
7958
+ const essence = JSON.parse(readFileSync20(essencePath, "utf-8"));
7553
7959
  const validation = validateEssence2(essence);
7554
7960
  const essenceVersion = isV47(essence) ? "v4" : "legacy";
7555
7961
  console.log(`${BOLD7}Essence:${RESET14}`);
@@ -7597,9 +8003,9 @@ async function cmdStatus() {
7597
8003
  }
7598
8004
  console.log("");
7599
8005
  console.log(`${BOLD7}Sync Status:${RESET14}`);
7600
- if (existsSync26(projectJsonPath)) {
8006
+ if (existsSync27(projectJsonPath)) {
7601
8007
  try {
7602
- const projectJson = JSON.parse(readFileSync19(projectJsonPath, "utf-8"));
8008
+ const projectJson = JSON.parse(readFileSync20(projectJsonPath, "utf-8"));
7603
8009
  const syncStatus = projectJson.sync?.status || "unknown";
7604
8010
  const lastSync = projectJson.sync?.lastSync || "never";
7605
8011
  const source = projectJson.sync?.registrySource || "unknown";
@@ -7617,7 +8023,7 @@ async function cmdStatus() {
7617
8023
  }
7618
8024
  async function cmdSync() {
7619
8025
  const projectRoot = process.cwd();
7620
- const cacheDir = join27(projectRoot, ".decantr", "cache");
8026
+ const cacheDir = join28(projectRoot, ".decantr", "cache");
7621
8027
  console.log(heading2("Syncing registry content..."));
7622
8028
  const result = await syncRegistry(cacheDir);
7623
8029
  if (result.synced.length > 0) {
@@ -7812,14 +8218,14 @@ ${BOLD7}Examples:${RESET14}
7812
8218
  process.exitCode = 1;
7813
8219
  return;
7814
8220
  }
7815
- const themePath = join27(projectRoot, ".decantr", "custom", "themes", `${name}.json`);
7816
- if (!existsSync26(themePath)) {
8221
+ const themePath = join28(projectRoot, ".decantr", "custom", "themes", `${name}.json`);
8222
+ if (!existsSync27(themePath)) {
7817
8223
  console.error(error3(`Theme "${name}" not found at ${themePath}`));
7818
8224
  process.exitCode = 1;
7819
8225
  return;
7820
8226
  }
7821
8227
  try {
7822
- const theme = JSON.parse(readFileSync19(themePath, "utf-8"));
8228
+ const theme = JSON.parse(readFileSync20(themePath, "utf-8"));
7823
8229
  const result = validateCustomTheme(theme);
7824
8230
  if (result.valid) {
7825
8231
  console.log(success3(`Custom theme "${name}" is valid`));
@@ -7887,14 +8293,483 @@ ${BOLD7}Examples:${RESET14}
7887
8293
  process.exitCode = 1;
7888
8294
  }
7889
8295
  }
8296
+ function parseLooseArgs(args, startIndex = 1) {
8297
+ const flags = {};
8298
+ const positional = [];
8299
+ for (let index = startIndex; index < args.length; index += 1) {
8300
+ const arg = args[index];
8301
+ if (arg === "-y") {
8302
+ flags.yes = true;
8303
+ continue;
8304
+ }
8305
+ if (arg.startsWith("--no-")) {
8306
+ flags[arg.slice(5)] = false;
8307
+ continue;
8308
+ }
8309
+ if (arg.startsWith("--")) {
8310
+ const body = arg.slice(2);
8311
+ const equalsIndex = body.indexOf("=");
8312
+ if (equalsIndex !== -1) {
8313
+ flags[body.slice(0, equalsIndex)] = body.slice(equalsIndex + 1);
8314
+ continue;
8315
+ }
8316
+ if (args[index + 1] && !args[index + 1].startsWith("-")) {
8317
+ flags[body] = args[++index];
8318
+ } else {
8319
+ flags[body] = true;
8320
+ }
8321
+ continue;
8322
+ }
8323
+ positional.push(arg);
8324
+ }
8325
+ return { flags, positional };
8326
+ }
8327
+ function flagString(flags, key) {
8328
+ const value = flags[key];
8329
+ return typeof value === "string" ? value : void 0;
8330
+ }
8331
+ function flagBoolean(flags, key, defaultValue = false) {
8332
+ const value = flags[key];
8333
+ if (typeof value === "boolean") return value;
8334
+ if (typeof value === "string") return value !== "false";
8335
+ return defaultValue;
8336
+ }
8337
+ function withoutWorkflowOnlyFlags(args) {
8338
+ const stripped = [];
8339
+ const flagsWithValues = /* @__PURE__ */ new Set(["--project"]);
8340
+ for (let index = 1; index < args.length; index += 1) {
8341
+ const arg = args[index];
8342
+ if (arg === "--brownfield" || arg === "--local-patterns" || arg === "--workspace" || arg === "--baseline") {
8343
+ continue;
8344
+ }
8345
+ if (arg.startsWith("--project=")) {
8346
+ continue;
8347
+ }
8348
+ if (flagsWithValues.has(arg)) {
8349
+ index += 1;
8350
+ continue;
8351
+ }
8352
+ stripped.push(arg);
8353
+ }
8354
+ return stripped;
8355
+ }
8356
+ function resolveWorkflowProject(flags) {
8357
+ const projectArg = flagString(flags, "project");
8358
+ const workspaceInfo = resolveWorkspaceInfo(process.cwd(), projectArg);
8359
+ if (workspaceInfo.requiresProjectSelection) {
8360
+ console.log(error3("This looks like a workspace root with multiple app candidates."));
8361
+ console.log(dim3(`Use --project=<path>. Candidates: ${workspaceInfo.appCandidates.join(", ")}`));
8362
+ process.exitCode = 1;
8363
+ return null;
8364
+ }
8365
+ return workspaceInfo;
8366
+ }
8367
+ function printWorkflowPlan(title, steps) {
8368
+ console.log(heading2(title));
8369
+ console.log(" Decantr will run this workflow:");
8370
+ for (const step of steps) {
8371
+ console.log(` ${cyan3(step)}`);
8372
+ }
8373
+ console.log("");
8374
+ }
8375
+ async function cmdSetupWorkflow(args) {
8376
+ const { flags } = parseLooseArgs(args);
8377
+ const workspaceInfo = resolveWorkflowProject(flags);
8378
+ if (!workspaceInfo) return;
8379
+ const detected = detectProject(workspaceInfo.appRoot);
8380
+ const hasFootprint = detected.framework !== "unknown" || detected.packageManager !== "unknown" || detected.hasTypeScript || detected.hasTailwind || detected.existingRuleFiles.length > 0;
8381
+ console.log(heading2("Decantr Setup"));
8382
+ console.log(` Project: ${workspaceInfo.appRoot}`);
8383
+ console.log(` Detected: ${formatDetection(detected)}`);
8384
+ console.log("");
8385
+ if (detected.existingEssence) {
8386
+ console.log(`${BOLD7}Recommended path:${RESET14} maintain an attached Decantr project`);
8387
+ console.log(` ${cyan3('decantr task <route> "<change>"')} Prepare LLM context before edits`);
8388
+ console.log(` ${cyan3("decantr verify")} Run local health and drift checks`);
8389
+ console.log(` ${cyan3("decantr codify")} Propose project-owned UI patterns`);
8390
+ return;
8391
+ }
8392
+ if (hasFootprint) {
8393
+ console.log(`${BOLD7}Recommended path:${RESET14} brownfield adoption`);
8394
+ console.log(` ${cyan3("decantr adopt --yes")} Analyze, attach, and verify`);
8395
+ console.log(
8396
+ ` ${cyan3("decantr adopt --base-url http://localhost:3000 --evidence --yes")} Include visual evidence`
8397
+ );
8398
+ console.log(` ${cyan3("decantr codify")} Propose local UI law`);
8399
+ return;
8400
+ }
8401
+ console.log(`${BOLD7}Recommended path:${RESET14} greenfield start`);
8402
+ console.log(` ${cyan3("decantr new my-app --blueprint=<slug>")}`);
8403
+ console.log(` ${cyan3("decantr init --workflow=greenfield --adoption=contract-only")}`);
8404
+ }
8405
+ async function cmdAdoptWorkflow(args) {
8406
+ const { flags } = parseLooseArgs(args);
8407
+ const workspaceInfo = resolveWorkflowProject(flags);
8408
+ if (!workspaceInfo) return;
8409
+ const projectRoot = workspaceInfo.appRoot;
8410
+ const dryRun = flagBoolean(flags, "dry-run");
8411
+ const yes = flagBoolean(flags, "yes") || flagBoolean(flags, "y");
8412
+ const baseUrl = flagString(flags, "base-url");
8413
+ const runVerify = flagBoolean(flags, "verify", true);
8414
+ const runBrowser = flagBoolean(flags, "browser") || Boolean(baseUrl);
8415
+ const evidence = flagBoolean(flags, "evidence") || runBrowser;
8416
+ const saveBaseline = flagBoolean(flags, "baseline", true) || flagBoolean(flags, "save-baseline");
8417
+ const initCi = flagBoolean(flags, "ci") || flagBoolean(flags, "init-ci");
8418
+ const assistantBridge = flagString(flags, "assistant-bridge");
8419
+ const hasEssence = existsSync27(join28(projectRoot, "decantr.essence.json"));
8420
+ const proposalFlag = flagBoolean(flags, "replace-essence") ? "--replace-essence" : flagBoolean(flags, "merge-proposal") || hasEssence ? "--merge-proposal" : "--accept-proposal";
8421
+ const steps = [
8422
+ "analyze current app and write .decantr/brownfield intelligence",
8423
+ `init --existing ${proposalFlag} as contract-only Brownfield`
8424
+ ];
8425
+ if (runVerify) {
8426
+ steps.push(
8427
+ runBrowser ? "verify with Project Health, browser evidence, visual manifest, and baseline" : "verify with Project Health and baseline"
8428
+ );
8429
+ }
8430
+ if (initCi) {
8431
+ steps.push("install Project Health CI gate");
8432
+ }
8433
+ printWorkflowPlan("Decantr Adopt", steps);
8434
+ if (dryRun) {
8435
+ console.log(dim3("Dry run only. No files were written."));
8436
+ return;
8437
+ }
8438
+ if (!yes) {
8439
+ const ok = await confirm("Run this Brownfield adoption workflow?", false);
8440
+ if (!ok) {
8441
+ console.log(dim3("Cancelled."));
8442
+ return;
8443
+ }
8444
+ }
8445
+ await cmdAnalyze(projectRoot, workspaceInfo);
8446
+ if (process.exitCode && process.exitCode !== 0) return;
8447
+ await cmdInit({
8448
+ existing: true,
8449
+ yes: true,
8450
+ project: flagString(flags, "project"),
8451
+ "accept-proposal": proposalFlag === "--accept-proposal",
8452
+ "merge-proposal": proposalFlag === "--merge-proposal",
8453
+ "replace-essence": proposalFlag === "--replace-essence",
8454
+ "assistant-bridge": assistantBridge,
8455
+ telemetry: flagBoolean(flags, "telemetry")
8456
+ });
8457
+ if (process.exitCode && process.exitCode !== 0) return;
8458
+ if (runVerify) {
8459
+ const { cmdHealth } = await import("./health-ETZXWGTW.js");
8460
+ await cmdHealth(projectRoot, {
8461
+ browser: runBrowser,
8462
+ browserBaseUrl: baseUrl,
8463
+ evidence,
8464
+ output: evidence ? ".decantr/evidence/latest.json" : void 0,
8465
+ saveBaseline
8466
+ });
8467
+ }
8468
+ if (initCi) {
8469
+ const { cmdHealth } = await import("./health-ETZXWGTW.js");
8470
+ const ciRoot = flagString(flags, "project") ? process.cwd() : projectRoot;
8471
+ await cmdHealth(ciRoot, {
8472
+ initCi: {
8473
+ projectPath: flagString(flags, "project"),
8474
+ failOn: "error"
8475
+ }
8476
+ });
8477
+ }
8478
+ console.log("");
8479
+ console.log(`${BOLD7}Next useful commands:${RESET14}`);
8480
+ console.log(` ${cyan3('decantr task <route> "<change>"')} Give your LLM route-specific context`);
8481
+ console.log(` ${cyan3("decantr codify")} Propose project-owned UI patterns`);
8482
+ console.log(` ${cyan3("decantr verify --since-baseline")} Compare future work against this baseline`);
8483
+ }
8484
+ async function cmdVerifyWorkflow(args) {
8485
+ const { flags } = parseLooseArgs(args);
8486
+ const workspaceMode = flagBoolean(flags, "workspace");
8487
+ if (args[1] === "init-ci") {
8488
+ const { cmdHealth: cmdHealth2, parseHealthArgs: parseHealthArgs2 } = await import("./health-ETZXWGTW.js");
8489
+ await cmdHealth2(process.cwd(), parseHealthArgs2(["health", ...args.slice(1)]));
8490
+ return;
8491
+ }
8492
+ if (workspaceMode) {
8493
+ const { cmdWorkspace } = await import("./workspace-KSFWRZEX.js");
8494
+ await cmdWorkspace(process.cwd(), ["workspace", "health", ...withoutWorkflowOnlyFlags(args)]);
8495
+ return;
8496
+ }
8497
+ const workspaceInfo = resolveWorkflowProject(flags);
8498
+ if (!workspaceInfo) return;
8499
+ const brownfield = flagBoolean(flags, "brownfield");
8500
+ const localPatterns = flagBoolean(flags, "local-patterns");
8501
+ const evidence = flagBoolean(flags, "evidence");
8502
+ const baseUrl = flagString(flags, "base-url");
8503
+ const healthArgs = ["health", ...withoutWorkflowOnlyFlags(args)];
8504
+ if (flagBoolean(flags, "baseline") && !healthArgs.includes("--save-baseline")) {
8505
+ healthArgs.push("--save-baseline");
8506
+ }
8507
+ if (evidence && !flagString(flags, "output")) {
8508
+ healthArgs.push("--output", ".decantr/evidence/latest.json");
8509
+ }
8510
+ if (baseUrl && !healthArgs.includes("--browser")) {
8511
+ healthArgs.push("--browser");
8512
+ }
8513
+ const quietOutput = flagBoolean(flags, "json") || flagBoolean(flags, "ci") || Boolean(flagString(flags, "output"));
8514
+ if (!quietOutput) {
8515
+ console.log(heading2("Decantr Verify"));
8516
+ console.log(
8517
+ dim3(
8518
+ brownfield ? "Running Brownfield guard validation before Project Health." : "Running Project Health as the canonical reliability gate."
8519
+ )
8520
+ );
8521
+ console.log("");
8522
+ }
8523
+ let guardExitCode;
8524
+ if (brownfield) {
8525
+ const { cmdHeal, collectCheckIssues } = await import("./heal-ZYD6NVGE.js");
8526
+ if (quietOutput) {
8527
+ const result = collectCheckIssues(workspaceInfo.appRoot, { brownfield: true });
8528
+ guardExitCode = result.issues.some((issue) => issue.type === "error") ? 1 : void 0;
8529
+ } else {
8530
+ await cmdHeal(workspaceInfo.appRoot, { brownfield: true });
8531
+ guardExitCode = process.exitCode;
8532
+ process.exitCode = void 0;
8533
+ }
8534
+ }
8535
+ const { cmdHealth, parseHealthArgs } = await import("./health-ETZXWGTW.js");
8536
+ await cmdHealth(workspaceInfo.appRoot, parseHealthArgs(healthArgs));
8537
+ if (localPatterns) {
8538
+ const localPatternsPath = join28(workspaceInfo.appRoot, ".decantr", "local-patterns.json");
8539
+ if (!existsSync27(localPatternsPath)) {
8540
+ console.log("");
8541
+ console.log(
8542
+ `${YELLOW9}Local pattern pack missing.${RESET14} Run ${cyan3("decantr codify --accept")} after reviewing the proposal.`
8543
+ );
8544
+ process.exitCode = process.exitCode || 1;
8545
+ } else {
8546
+ console.log("");
8547
+ console.log(`${GREEN14}Local pattern pack found:${RESET14} ${localPatternsPath}`);
8548
+ }
8549
+ }
8550
+ if (guardExitCode && guardExitCode !== 0 && (!process.exitCode || process.exitCode === 0)) {
8551
+ process.exitCode = guardExitCode;
8552
+ }
8553
+ }
8554
+ function readJsonIfPresent(path) {
8555
+ if (!existsSync27(path)) return null;
8556
+ try {
8557
+ return JSON.parse(readFileSync20(path, "utf-8"));
8558
+ } catch {
8559
+ return null;
8560
+ }
8561
+ }
8562
+ async function cmdTaskWorkflow(args) {
8563
+ const { flags, positional } = parseLooseArgs(args);
8564
+ const workspaceInfo = resolveWorkflowProject(flags);
8565
+ if (!workspaceInfo) return;
8566
+ const routeInput = positional[0];
8567
+ if (!routeInput) {
8568
+ console.error(error3('Usage: decantr task <route> ["task summary"] [--project <path>] [--json]'));
8569
+ process.exitCode = 1;
8570
+ return;
8571
+ }
8572
+ const route = routeInput.startsWith("/") ? routeInput : `/${routeInput}`;
8573
+ const taskSummary = positional.slice(1).join(" ").trim();
8574
+ const essencePath = join28(workspaceInfo.appRoot, "decantr.essence.json");
8575
+ const essence = readJsonIfPresent(essencePath);
8576
+ if (!essence) {
8577
+ console.error(error3("No decantr.essence.json found. Run `decantr adopt` or `decantr init` first."));
8578
+ process.exitCode = 1;
8579
+ return;
8580
+ }
8581
+ if (!isV47(essence)) {
8582
+ console.error(error3("Task context requires Essence v4. Run `decantr migrate --to v4` first."));
8583
+ process.exitCode = 1;
8584
+ return;
8585
+ }
8586
+ const target = essence.blueprint.routes?.[route];
8587
+ if (!target) {
8588
+ const knownRoutes = Object.keys(essence.blueprint.routes ?? {}).sort();
8589
+ console.error(error3(`Route not found in Decantr contract: ${route}`));
8590
+ console.error(dim3(`Known routes: ${knownRoutes.join(", ") || "none"}`));
8591
+ process.exitCode = 1;
8592
+ return;
8593
+ }
8594
+ const section = essence.blueprint.sections.find((entry) => entry.id === target.section);
8595
+ const page = section?.pages.find((entry) => entry.id === target.page);
8596
+ const contextDir = join28(workspaceInfo.appRoot, ".decantr", "context");
8597
+ const manifest = readJsonIfPresent(join28(contextDir, "pack-manifest.json"));
8598
+ const pagePack = manifest?.pages?.find((entry) => entry.id === target.page);
8599
+ const sectionPack = manifest?.sections?.find((entry) => entry.id === target.section);
8600
+ const visualManifest = readJsonIfPresent(join28(workspaceInfo.appRoot, ".decantr", "evidence", "visual-manifest.json"));
8601
+ const screenshot = visualManifest?.routes?.find((entry) => entry.route === route)?.screenshot;
8602
+ const localPatternsPath = join28(workspaceInfo.appRoot, ".decantr", "local-patterns.json");
8603
+ const context = {
8604
+ route,
8605
+ task: taskSummary || null,
8606
+ section: target.section,
8607
+ page: target.page,
8608
+ shell: page?.shell ?? section?.shell ?? null,
8609
+ patterns: page?.layout?.map(extractPatternName) ?? [],
8610
+ read: [
8611
+ pagePack ? join28(".decantr/context", pagePack.markdown) : null,
8612
+ sectionPack ? join28(".decantr/context", sectionPack.markdown) : null,
8613
+ manifest?.scaffold?.markdown ? join28(".decantr/context", manifest.scaffold.markdown) : null,
8614
+ ".decantr/context/scaffold.md",
8615
+ "DECANTR.md",
8616
+ existsSync27(localPatternsPath) ? ".decantr/local-patterns.json" : null
8617
+ ].filter(Boolean),
8618
+ screenshot: screenshot ?? null
8619
+ };
8620
+ if (flagBoolean(flags, "json")) {
8621
+ console.log(JSON.stringify(context, null, 2));
8622
+ return;
8623
+ }
8624
+ console.log(heading2("Decantr Task Context"));
8625
+ console.log(` Route: ${cyan3(context.route)}`);
8626
+ console.log(` Section/page: ${context.section}/${context.page}`);
8627
+ if (context.shell) console.log(` Shell: ${context.shell}`);
8628
+ if (context.patterns.length > 0) console.log(` Patterns: ${context.patterns.join(", ")}`);
8629
+ if (taskSummary) console.log(` Task: ${taskSummary}`);
8630
+ console.log("");
8631
+ console.log(`${BOLD7}Read before editing:${RESET14}`);
8632
+ for (const path of context.read) {
8633
+ console.log(` ${cyan3(path)}`);
8634
+ }
8635
+ if (context.screenshot) {
8636
+ console.log("");
8637
+ console.log(`${BOLD7}Visual evidence:${RESET14}`);
8638
+ console.log(` ${cyan3(context.screenshot)}`);
8639
+ }
8640
+ console.log("");
8641
+ console.log(`${BOLD7}LLM instruction:${RESET14}`);
8642
+ console.log(
8643
+ " Preserve the existing runtime and styling system. Use the route pack, section context, local patterns, and visual evidence above as the task contract before changing code."
8644
+ );
8645
+ }
8646
+ async function cmdCodifyWorkflow(args) {
8647
+ const { flags } = parseLooseArgs(args);
8648
+ const workspaceInfo = resolveWorkflowProject(flags);
8649
+ if (!workspaceInfo) return;
8650
+ const decantrDir = join28(workspaceInfo.appRoot, ".decantr");
8651
+ const proposalPathLocal = join28(decantrDir, "local-patterns.proposal.json");
8652
+ const acceptedPath = join28(decantrDir, "local-patterns.json");
8653
+ if (flagBoolean(flags, "accept")) {
8654
+ if (!existsSync27(proposalPathLocal)) {
8655
+ console.error(error3("No .decantr/local-patterns.proposal.json found. Run `decantr codify` first."));
8656
+ process.exitCode = 1;
8657
+ return;
8658
+ }
8659
+ writeFileSync16(acceptedPath, readFileSync20(proposalPathLocal, "utf-8"), "utf-8");
8660
+ console.log(success3(`Accepted local pattern pack: ${acceptedPath}`));
8661
+ console.log(dim3("Run `decantr verify --local-patterns` to require the pack during verification."));
8662
+ return;
8663
+ }
8664
+ mkdirSync13(decantrDir, { recursive: true });
8665
+ const detected = detectProject(workspaceInfo.appRoot);
8666
+ const essence = readJsonIfPresent(join28(workspaceInfo.appRoot, "decantr.essence.json"));
8667
+ const routes = essence && isV47(essence) ? Object.keys(essence.blueprint.routes ?? {}).sort() : [];
8668
+ const proposal = {
8669
+ version: 1,
8670
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
8671
+ status: "proposal",
8672
+ source: "decantr codify",
8673
+ project: {
8674
+ framework: detected.framework,
8675
+ packageManager: detected.packageManager,
8676
+ hasTailwind: detected.hasTailwind,
8677
+ ruleFiles: detected.existingRuleFiles,
8678
+ routeCount: routes.length
8679
+ },
8680
+ purpose: "Project-owned Brownfield UI law. Review and edit before accepting; Decantr does not treat this as authoritative until copied to .decantr/local-patterns.json.",
8681
+ patterns: [
8682
+ {
8683
+ id: "button",
8684
+ role: "Actions and command triggers",
8685
+ decide: "Define primary, secondary, tertiary, destructive, icon-only, and loading button variants from this app.",
8686
+ evidenceToCollect: ["component wrapper path", "allowed classes/tokens", "forbidden raw <button> usage"]
8687
+ },
8688
+ {
8689
+ id: "surface-card",
8690
+ role: "Cards, panels, and content surfaces",
8691
+ decide: "Define the canonical card background, border, radius, shadow, padding, and hover treatment.",
8692
+ evidenceToCollect: ["shared card component", "token/class recipe", "allowed density variants"]
8693
+ },
8694
+ {
8695
+ id: "page-shell",
8696
+ role: "Route shell, nav, spacing, and scroll ownership",
8697
+ decide: "Define which layout owns max width, gutters, sticky chrome, and scroll containers.",
8698
+ evidenceToCollect: ["root layout path", "page template path", "responsive breakpoints"]
8699
+ },
8700
+ {
8701
+ id: "form-control",
8702
+ role: "Inputs, labels, validation, and form actions",
8703
+ decide: "Define input height, label placement, error copy, disabled state, and focus treatment.",
8704
+ evidenceToCollect: ["form field wrapper", "validation pattern", "accessibility expectations"]
8705
+ }
8706
+ ],
8707
+ starterRules: [
8708
+ "Prefer project-owned wrappers for repeated primitives once they exist.",
8709
+ "Avoid raw hex/rgb values in component templates unless explicitly documented as dynamic data.",
8710
+ "Avoid static inline styles for reusable visual treatment.",
8711
+ "When adding a new route, map it to an existing local pattern before inventing a new visual variant."
8712
+ ],
8713
+ nextSteps: [
8714
+ "Edit this proposal with real component paths and token/class recipes.",
8715
+ "Run decantr codify --accept after review.",
8716
+ "Use decantr task <route> before LLM edits so local patterns appear in the task context.",
8717
+ "Wire mechanical enforcement through ESLint/Biome/project tests for rules Decantr cannot reliably infer."
8718
+ ]
8719
+ };
8720
+ writeFileSync16(proposalPathLocal, JSON.stringify(proposal, null, 2) + "\n", "utf-8");
8721
+ console.log(success3(`Wrote local pattern proposal: ${proposalPathLocal}`));
8722
+ console.log(dim3("Review it, add real component paths/token recipes, then run `decantr codify --accept`."));
8723
+ }
8724
+ async function cmdContentWorkflow(args) {
8725
+ const subcommand = args[1] ?? "check";
8726
+ if (subcommand === "check" || subcommand === "health") {
8727
+ const { cmdContentHealth, parseContentHealthArgs } = await import("./content-health-QQHBR6XG.js");
8728
+ await cmdContentHealth(process.cwd(), parseContentHealthArgs(["content-health", ...args.slice(2)]));
8729
+ return;
8730
+ }
8731
+ if (subcommand === "create") {
8732
+ const type = args[2];
8733
+ const name = args[3];
8734
+ if (!type || !name) {
8735
+ console.error(error3("Usage: decantr content create <type> <name>"));
8736
+ process.exitCode = 1;
8737
+ return;
8738
+ }
8739
+ cmdCreate(type, name);
8740
+ return;
8741
+ }
8742
+ if (subcommand === "publish") {
8743
+ const type = args[2];
8744
+ const name = args[3];
8745
+ if (!type || !name) {
8746
+ console.error(error3("Usage: decantr content publish <type> <name>"));
8747
+ process.exitCode = 1;
8748
+ return;
8749
+ }
8750
+ await cmdPublish(type, name);
8751
+ return;
8752
+ }
8753
+ console.error(error3("Usage: decantr content <check|create|publish>"));
8754
+ process.exitCode = 1;
8755
+ }
7890
8756
  function cmdHelp() {
7891
8757
  console.log(`
7892
8758
  ${BOLD7}decantr${RESET14} \u2014 Design intelligence for AI-generated UI
7893
8759
 
7894
8760
  ${BOLD7}Usage:${RESET14}
8761
+ decantr setup [--project <path>]
7895
8762
  decantr new <name> [--blueprint=X] [--archetype=X] [--theme=X] [--workflow=greenfield] [--adoption=decantr-css] [--telemetry]
7896
- decantr magic <prompt> [--dry-run]
8763
+ decantr adopt [--project <path>] [--base-url <url>] [--evidence] [--ci] [--yes]
8764
+ decantr task <route> ["task summary"] [--project <path>] [--json]
8765
+ decantr verify [--project <path>] [--brownfield] [--local-patterns] [health options]
8766
+ decantr codify [--accept] [--project <path>]
8767
+ decantr studio [--port 4319] [--host 127.0.0.1] [--report decantr-health.json] [--workspace]
8768
+
8769
+ ${BOLD7}Advanced primitives:${RESET14}
7897
8770
  decantr init [options]
8771
+ decantr analyze
8772
+ decantr magic <prompt> [--dry-run]
7898
8773
  decantr status
7899
8774
  decantr sync
7900
8775
  decantr audit [file]
@@ -7903,7 +8778,7 @@ ${BOLD7}Usage:${RESET14}
7903
8778
  decantr check --brownfield
7904
8779
  decantr sync-drift
7905
8780
  decantr search <query> [--type <type>] [--sort <recommended|recent|name>] [--recommended] [--source <authored|benchmark|hybrid>]
7906
- decantr suggest <query> [--type <type>]
8781
+ decantr suggest <query> [--type <type>] [--route <route>] [--file <path>] [--from-code]
7907
8782
  decantr get <type> <id>
7908
8783
  decantr list <type> [--sort <recommended|recent|name>] [--recommended] [--source <authored|benchmark|hybrid>]
7909
8784
  decantr showcase [manifest|shortlist|verification] [--json]
@@ -7913,12 +8788,13 @@ ${BOLD7}Usage:${RESET14}
7913
8788
  decantr registry critique-file <file> [--namespace <namespace>] [--json] [--essence <path>] [--treatments <path>]
7914
8789
  decantr registry audit-project [--namespace <namespace>] [--json] [--essence <path>] [--dist <path>] [--sources <dir>]
7915
8790
  decantr health [--format text|json|markdown] [--ci] [--fail-on error|warn|none]
7916
- decantr health --evidence [--browser] [--design-tokens <path>]
8791
+ decantr health --evidence [--browser] [--base-url <url>] [--design-tokens <path>]
8792
+ decantr health --save-baseline | --since-baseline
7917
8793
  decantr health init-ci [--force] [--project <path>] [--workspace] [--fail-on <error|warn|none>] [--cli-version <version|latest>]
7918
8794
  decantr workspace list [--json]
7919
8795
  decantr workspace health [--json] [--changed --since origin/main]
8796
+ decantr content check [--json] [--markdown] [--ci]
7920
8797
  decantr content-health [--json] [--markdown] [--ci]
7921
- decantr studio [--port 4319] [--host 127.0.0.1] [--report decantr-health.json] [--workspace]
7922
8798
  decantr telemetry status [--json]
7923
8799
  decantr telemetry explain [--json]
7924
8800
  decantr telemetry link [--enable] [--org <slug>]
@@ -7928,7 +8804,6 @@ ${BOLD7}Usage:${RESET14}
7928
8804
  decantr theme <subcommand>
7929
8805
  decantr create <type> <name>
7930
8806
  decantr publish <type> <name>
7931
- decantr analyze
7932
8807
  decantr login
7933
8808
  decantr logout
7934
8809
  decantr help
@@ -7956,14 +8831,22 @@ ${BOLD7}Init Options:${RESET14}
7956
8831
  --telemetry Opt this project into privacy-filtered CLI product telemetry
7957
8832
 
7958
8833
  ${BOLD7}Commands:${RESET14}
8834
+ ${cyan3("setup")} Detect project state and recommend the right Decantr workflow
7959
8835
  ${cyan3("new")} Create a new greenfield workspace and bootstrap the available starter adapter
8836
+ ${cyan3("adopt")} Brownfield one-liner: analyze, attach, verify, and show next steps
8837
+ ${cyan3("task")} Prepare route/task context for an AI coding assistant
8838
+ ${cyan3("verify")} One reliability gate over Project Health, Brownfield checks, baselines, and evidence
8839
+ ${cyan3("codify")} Propose or accept project-owned Brownfield UI patterns
8840
+ ${cyan3("studio")} Open a local Project Health dashboard backed by the same report
8841
+ ${cyan3("content")} Content-author namespace: check, create, publish
8842
+
8843
+ ${BOLD7}Advanced commands:${RESET14}
7960
8844
  ${cyan3("magic")} Greenfield-first intent flow; steers existing apps into analyze + init
7961
8845
  ${cyan3("init")} Attach Decantr contract/context files to an existing project or empty workspace
7962
8846
  ${cyan3("status")} Show project status, DNA axioms, and blueprint info
7963
8847
  ${cyan3("health")} Generate a local Project Health report [--json] [--markdown] [--ci]; use health init-ci to install a GitHub Actions gate
7964
8848
  ${cyan3("workspace")} Discover and aggregate health across Decantr projects in a monorepo
7965
8849
  ${cyan3("content-health")} Generate a local registry content health report [--json] [--markdown] [--ci]
7966
- ${cyan3("studio")} Open a local Project Health dashboard backed by the same report
7967
8850
  ${cyan3("sync")} Sync registry content from API
7968
8851
  ${cyan3("audit")} Audit the project or critique a specific file against compiled packs
7969
8852
  ${cyan3("migrate")} Migrate older essence files to v4 format (with .pre-v4.backup.json backup)
@@ -7989,7 +8872,15 @@ ${BOLD7}Commands:${RESET14}
7989
8872
  ${cyan3("help")} Show this help
7990
8873
 
7991
8874
  ${BOLD7}Examples:${RESET14}
8875
+ decantr setup
7992
8876
  decantr new my-app --blueprint=carbon-ai-portal
8877
+ decantr adopt --base-url http://localhost:3000 --evidence --yes
8878
+ decantr task /feed "add saved recipe actions"
8879
+ decantr verify --brownfield --local-patterns
8880
+ decantr verify --since-baseline
8881
+ decantr codify
8882
+ decantr codify --accept
8883
+ decantr content check --ci --fail-on error
7993
8884
  decantr magic "AI chatbot with dark cyber theme \u2014 bold and futuristic"
7994
8885
  decantr init
7995
8886
  decantr analyze
@@ -8002,13 +8893,13 @@ ${BOLD7}Examples:${RESET14}
8002
8893
  decantr rules apply
8003
8894
  decantr status
8004
8895
  decantr health
8005
- decantr health init-ci
8006
- decantr health init-ci --project apps/web
8007
- decantr health --ci --fail-on error
8896
+ decantr verify init-ci
8897
+ decantr verify init-ci --project apps/web
8898
+ decantr verify --ci --fail-on error
8008
8899
  decantr health --evidence --output .decantr/evidence/latest.json
8009
8900
  decantr workspace list
8010
- decantr workspace health --changed --since origin/main
8011
- decantr content-health --ci --fail-on error
8901
+ decantr verify --workspace --changed --since origin/main
8902
+ decantr content check --ci --fail-on error
8012
8903
  decantr studio
8013
8904
  decantr studio --report decantr-health.json
8014
8905
  decantr telemetry status
@@ -8020,7 +8911,7 @@ ${BOLD7}Examples:${RESET14}
8020
8911
  decantr check --brownfield
8021
8912
  decantr sync-drift
8022
8913
  decantr search dashboard
8023
- decantr suggest leaderboard
8914
+ decantr suggest "recipe feed with infinite scroll" --route /feed --from-code
8024
8915
  decantr list patterns
8025
8916
  decantr showcase shortlist
8026
8917
  decantr showcase verification --json
@@ -8037,7 +8928,9 @@ ${BOLD7}Examples:${RESET14}
8037
8928
  ${BOLD7}Workflow Model:${RESET14}
8038
8929
  ${cyan3("Greenfield blueprint")} decantr new my-app --blueprint=X --workflow=greenfield --adoption=decantr-css
8039
8930
  ${cyan3("Greenfield contract")} decantr init --workflow=greenfield --adoption=contract-only
8040
- ${cyan3("Brownfield adoption")} decantr analyze -> decantr init --existing --accept-proposal -> decantr check --brownfield
8931
+ ${cyan3("Brownfield adoption")} decantr adopt --base-url <url> --evidence --yes
8932
+ ${cyan3("Daily LLM work")} decantr task <route> "<change>" -> decantr verify
8933
+ ${cyan3("Project-owned law")} decantr codify -> edit proposal -> decantr codify --accept
8041
8934
  ${cyan3("Hybrid composition")} decantr add/remove, decantr theme switch, decantr registry, decantr upgrade
8042
8935
 
8043
8936
  ${BOLD7}Bootstrap adapters:${RESET14}
@@ -8077,6 +8970,9 @@ ${BOLD7}Usage:${RESET14}
8077
8970
  decantr health --ci [--fail-on error|warn|none]
8078
8971
  decantr health --prompt <finding-id>
8079
8972
  decantr health --evidence [--browser] [--design-tokens <path>]
8973
+ decantr health --browser --base-url <url> --evidence
8974
+ decantr health --save-baseline
8975
+ decantr health --since-baseline
8080
8976
  decantr health init-ci [--force] [--project <path>] [--workspace] [--fail-on error|warn|none] [--cli-version <version|latest>]
8081
8977
 
8082
8978
  ${BOLD7}Options:${RESET14}
@@ -8089,6 +8985,9 @@ ${BOLD7}Options:${RESET14}
8089
8985
  --prompt Print an AI-ready remediation prompt for a finding
8090
8986
  --evidence Emit a local Evidence Bundle JSON artifact
8091
8987
  --browser Include optional rendered-browser setup/evidence checks
8988
+ --base-url Base URL for rendered route checks when --browser is enabled
8989
+ --save-baseline Save the current health state for later comparison
8990
+ --since-baseline Compare this run to .decantr/health-baseline.json
8092
8991
  --design-tokens Compare against a Figma/Tokens Studio JSON export
8093
8992
 
8094
8993
  ${BOLD7}Examples:${RESET14}
@@ -8172,6 +9071,179 @@ ${BOLD7}Examples:${RESET14}
8172
9071
  decantr studio --workspace
8173
9072
  `);
8174
9073
  }
9074
+ function cmdRegistryHelp() {
9075
+ console.log(`
9076
+ ${BOLD7}decantr registry${RESET14} \u2014 Read hosted execution packs and registry intelligence
9077
+
9078
+ ${BOLD7}Usage:${RESET14}
9079
+ decantr registry summary [--namespace <namespace>] [--json]
9080
+ decantr registry compile-packs [path] [--namespace <namespace>] [--json] [--write-context]
9081
+ decantr registry get-pack <manifest|scaffold|review|section|page|mutation> [id] [--namespace <namespace>] [--json] [--essence <path>] [--write-context]
9082
+ decantr registry get-pack page --route <route> [--namespace <namespace>] [--json] [--essence <path>]
9083
+ decantr registry critique-file <file> [--namespace <namespace>] [--json] [--essence <path>] [--treatments <path>]
9084
+ decantr registry audit-project [--namespace <namespace>] [--json] [--essence <path>] [--dist <path>] [--sources <dir>]
9085
+ `);
9086
+ }
9087
+ function cmdThemeHelp() {
9088
+ console.log(`
9089
+ ${BOLD7}decantr theme${RESET14} \u2014 Manage custom themes
9090
+
9091
+ ${BOLD7}Usage:${RESET14}
9092
+ decantr theme create <name>
9093
+ decantr theme create <name> --guided
9094
+ decantr theme list
9095
+ decantr theme validate <name>
9096
+ decantr theme delete <name>
9097
+ decantr theme import <path>
9098
+ `);
9099
+ }
9100
+ function cmdSetupHelp() {
9101
+ console.log(`
9102
+ ${BOLD7}decantr setup${RESET14} \u2014 Detect the project state and recommend the right Decantr path
9103
+
9104
+ ${BOLD7}Usage:${RESET14}
9105
+ decantr setup [--project <path>]
9106
+
9107
+ ${BOLD7}Examples:${RESET14}
9108
+ decantr setup
9109
+ decantr setup --project apps/web
9110
+ `);
9111
+ }
9112
+ function cmdAdoptHelp() {
9113
+ console.log(`
9114
+ ${BOLD7}decantr adopt${RESET14} \u2014 Brownfield one-liner: analyze, attach, verify, and show the next step
9115
+
9116
+ ${BOLD7}Usage:${RESET14}
9117
+ decantr adopt [--project <path>] [--yes] [--dry-run]
9118
+ decantr adopt --base-url <url> [--evidence] [--ci] [--yes]
9119
+
9120
+ ${BOLD7}Options:${RESET14}
9121
+ --project App path inside a workspace/monorepo
9122
+ --yes, -y Run without confirmation
9123
+ --dry-run Show the workflow without writing files
9124
+ --base-url Include browser evidence against this dev server URL
9125
+ --evidence Write .decantr/evidence/latest.json
9126
+ --baseline Save a health baseline (default)
9127
+ --no-baseline Skip baseline save
9128
+ --no-verify Skip the verification step
9129
+ --ci, --init-ci Install the Project Health CI gate after adoption
9130
+ --telemetry Opt this project into privacy-filtered CLI product telemetry
9131
+ --merge-proposal Merge the observed proposal into an existing essence
9132
+ --replace-essence Replace an existing essence with backup
9133
+
9134
+ ${BOLD7}Examples:${RESET14}
9135
+ decantr adopt --yes
9136
+ decantr adopt --base-url http://localhost:3000 --evidence --yes
9137
+ decantr adopt --project apps/web --ci --yes
9138
+ `);
9139
+ }
9140
+ function cmdVerifyHelp() {
9141
+ console.log(`
9142
+ ${BOLD7}decantr verify${RESET14} \u2014 One reliability command for local work, CI, and LLM agent loops
9143
+
9144
+ ${BOLD7}Usage:${RESET14}
9145
+ decantr verify [--project <path>] [--brownfield] [--local-patterns]
9146
+ decantr verify --base-url <url> --evidence
9147
+ decantr verify --since-baseline
9148
+ decantr verify --workspace [--changed --since origin/main]
9149
+ decantr verify init-ci [health init-ci options]
9150
+
9151
+ ${BOLD7}Examples:${RESET14}
9152
+ decantr verify
9153
+ decantr verify --brownfield --local-patterns
9154
+ decantr verify --base-url http://localhost:3000 --evidence
9155
+ decantr verify --workspace --changed --since origin/main
9156
+ decantr verify init-ci --project apps/web
9157
+ `);
9158
+ }
9159
+ function cmdTaskHelp() {
9160
+ console.log(`
9161
+ ${BOLD7}decantr task${RESET14} \u2014 Prepare compact route/task context for an AI coding assistant
9162
+
9163
+ ${BOLD7}Usage:${RESET14}
9164
+ decantr task <route> ["task summary"] [--project <path>] [--json]
9165
+
9166
+ ${BOLD7}Examples:${RESET14}
9167
+ decantr task /feed "add saved recipe actions"
9168
+ decantr task /profile --json
9169
+ `);
9170
+ }
9171
+ function cmdCodifyHelp() {
9172
+ console.log(`
9173
+ ${BOLD7}decantr codify${RESET14} \u2014 Propose or accept project-owned Brownfield UI patterns
9174
+
9175
+ ${BOLD7}Usage:${RESET14}
9176
+ decantr codify [--project <path>]
9177
+ decantr codify --accept [--project <path>]
9178
+
9179
+ ${BOLD7}Examples:${RESET14}
9180
+ decantr codify
9181
+ decantr codify --accept
9182
+ decantr verify --local-patterns
9183
+ `);
9184
+ }
9185
+ function cmdContentHelp() {
9186
+ console.log(`
9187
+ ${BOLD7}decantr content${RESET14} \u2014 Content-author namespace for registry content repositories
9188
+
9189
+ ${BOLD7}Usage:${RESET14}
9190
+ decantr content check [content-health options]
9191
+ decantr content create <type> <name>
9192
+ decantr content publish <type> <name>
9193
+
9194
+ ${BOLD7}Examples:${RESET14}
9195
+ decantr content check --ci --fail-on error
9196
+ decantr content create pattern my-card
9197
+ decantr content publish pattern my-card
9198
+ `);
9199
+ }
9200
+ function printCommandHelp(command, args) {
9201
+ if (!isCommandHelpRequest(args)) return false;
9202
+ switch (command) {
9203
+ case "setup":
9204
+ cmdSetupHelp();
9205
+ return true;
9206
+ case "adopt":
9207
+ cmdAdoptHelp();
9208
+ return true;
9209
+ case "verify":
9210
+ cmdVerifyHelp();
9211
+ return true;
9212
+ case "task":
9213
+ cmdTaskHelp();
9214
+ return true;
9215
+ case "codify":
9216
+ cmdCodifyHelp();
9217
+ return true;
9218
+ case "content":
9219
+ cmdContentHelp();
9220
+ return true;
9221
+ case "health":
9222
+ cmdHealthHelp();
9223
+ return true;
9224
+ case "content-health":
9225
+ cmdContentHealthHelp();
9226
+ return true;
9227
+ case "studio":
9228
+ cmdStudioHelp();
9229
+ return true;
9230
+ case "workspace":
9231
+ cmdWorkspaceHelp();
9232
+ return true;
9233
+ case "rules":
9234
+ cmdRulesHelp();
9235
+ return true;
9236
+ case "registry":
9237
+ cmdRegistryHelp();
9238
+ return true;
9239
+ case "theme":
9240
+ cmdThemeHelp();
9241
+ return true;
9242
+ default:
9243
+ cmdHelp();
9244
+ return true;
9245
+ }
9246
+ }
8175
9247
  async function main() {
8176
9248
  const args = process.argv.slice(2);
8177
9249
  const command = args[0];
@@ -8182,10 +9254,10 @@ async function main() {
8182
9254
  if (command === "--version" || command === "-v" || command === "version") {
8183
9255
  try {
8184
9256
  const here = dirname4(fileURLToPath2(import.meta.url));
8185
- const candidates = [join27(here, "..", "package.json"), join27(here, "..", "..", "package.json")];
9257
+ const candidates = [join28(here, "..", "package.json"), join28(here, "..", "..", "package.json")];
8186
9258
  for (const candidate of candidates) {
8187
- if (existsSync26(candidate)) {
8188
- const pkg = JSON.parse(readFileSync19(candidate, "utf-8"));
9259
+ if (existsSync27(candidate)) {
9260
+ const pkg = JSON.parse(readFileSync20(candidate, "utf-8"));
8189
9261
  if (pkg.version) {
8190
9262
  console.log(pkg.version);
8191
9263
  return;
@@ -8200,7 +9272,34 @@ async function main() {
8200
9272
  }
8201
9273
  return;
8202
9274
  }
9275
+ if (printCommandHelp(command, args)) {
9276
+ return;
9277
+ }
8203
9278
  switch (command) {
9279
+ case "setup": {
9280
+ await cmdSetupWorkflow(args);
9281
+ break;
9282
+ }
9283
+ case "adopt": {
9284
+ await cmdAdoptWorkflow(args);
9285
+ break;
9286
+ }
9287
+ case "task": {
9288
+ await cmdTaskWorkflow(args);
9289
+ break;
9290
+ }
9291
+ case "verify": {
9292
+ await cmdVerifyWorkflow(args);
9293
+ break;
9294
+ }
9295
+ case "codify": {
9296
+ await cmdCodifyWorkflow(args);
9297
+ break;
9298
+ }
9299
+ case "content": {
9300
+ await cmdContentWorkflow(args);
9301
+ break;
9302
+ }
8204
9303
  case "new": {
8205
9304
  const newName = args[1];
8206
9305
  if (!newName) {
@@ -8297,7 +9396,7 @@ async function main() {
8297
9396
  `${YELLOW9}Note: \`decantr heal\` is deprecated. Use \`decantr check\` instead.${RESET14}`
8298
9397
  );
8299
9398
  }
8300
- const { cmdHeal } = await import("./heal-M6PRCIIF.js");
9399
+ const { cmdHeal } = await import("./heal-ZYD6NVGE.js");
8301
9400
  const telemetryFlag = args.includes("--telemetry");
8302
9401
  const brownfieldFlag = args.includes("--brownfield");
8303
9402
  await cmdHeal(process.cwd(), { telemetry: telemetryFlag, brownfield: brownfieldFlag });
@@ -8309,7 +9408,7 @@ async function main() {
8309
9408
  cmdHealthHelp();
8310
9409
  break;
8311
9410
  }
8312
- const { cmdHealth, parseHealthArgs } = await import("./health-ZXOPGNBZ.js");
9411
+ const { cmdHealth, parseHealthArgs } = await import("./health-ETZXWGTW.js");
8313
9412
  await cmdHealth(process.cwd(), parseHealthArgs(args));
8314
9413
  } catch (e) {
8315
9414
  console.error(error3(e.message));
@@ -8337,7 +9436,7 @@ async function main() {
8337
9436
  cmdStudioHelp();
8338
9437
  break;
8339
9438
  }
8340
- const { cmdStudio, parseStudioArgs } = await import("./studio-LHQXHBE7.js");
9439
+ const { cmdStudio, parseStudioArgs } = await import("./studio-MKLBUC3A.js");
8341
9440
  await cmdStudio(process.cwd(), parseStudioArgs(args));
8342
9441
  } catch (e) {
8343
9442
  console.error(error3(e.message));
@@ -8351,7 +9450,7 @@ async function main() {
8351
9450
  cmdWorkspaceHelp();
8352
9451
  break;
8353
9452
  }
8354
- const { cmdWorkspace } = await import("./workspace-MOLAGT2B.js");
9453
+ const { cmdWorkspace } = await import("./workspace-KSFWRZEX.js");
8355
9454
  await cmdWorkspace(process.cwd(), args);
8356
9455
  } catch (e) {
8357
9456
  console.error(error3(e.message));
@@ -8434,13 +9533,22 @@ async function main() {
8434
9533
  case "suggest": {
8435
9534
  const query = args[1];
8436
9535
  if (!query) {
8437
- console.error(error3("Usage: decantr suggest <query> [--type <type>]"));
9536
+ console.error(
9537
+ error3(
9538
+ "Usage: decantr suggest <query> [--type <type>] [--route <route>] [--file <path>] [--from-code]"
9539
+ )
9540
+ );
8438
9541
  process.exitCode = 1;
8439
9542
  return;
8440
9543
  }
8441
9544
  const typeIdx = args.indexOf("--type");
8442
9545
  const type = typeIdx !== -1 ? args[typeIdx + 1] : void 0;
8443
- await cmdSuggest(query, type);
9546
+ const routeIdx = args.indexOf("--route");
9547
+ const route = routeIdx !== -1 ? args[routeIdx + 1] : void 0;
9548
+ const fileIdx = args.indexOf("--file");
9549
+ const file = fileIdx !== -1 ? args[fileIdx + 1] : void 0;
9550
+ const fromCode = args.includes("--from-code");
9551
+ await cmdSuggest(query, { type, route, file, fromCode });
8444
9552
  break;
8445
9553
  }
8446
9554
  case "get": {
@@ -8607,7 +9715,9 @@ async function main() {
8607
9715
  const essenceIdx = args.indexOf("--essence");
8608
9716
  const essencePath = essenceIdx !== -1 ? args[essenceIdx + 1] : void 0;
8609
9717
  const packType = args[2] && !args[2].startsWith("--") ? args[2] : void 0;
8610
- const id = args[3] && !args[3].startsWith("--") ? args[3] : void 0;
9718
+ const routeIdx = args.indexOf("--route");
9719
+ const route = routeIdx !== -1 ? args[routeIdx + 1] : void 0;
9720
+ let id = args[3] && !args[3].startsWith("--") ? args[3] : void 0;
8611
9721
  if (!packType || !["manifest", "scaffold", "review", "section", "page", "mutation"].includes(packType)) {
8612
9722
  console.error(
8613
9723
  `${RED11}Usage: decantr registry get-pack <manifest|scaffold|review|section|page|mutation> [id] [--namespace <namespace>] [--json] [--essence <path>] [--write-context]${RESET14}`
@@ -8619,6 +9729,10 @@ async function main() {
8619
9729
  await printHostedExecutionPackManifest(essencePath, namespace, jsonOutput, writeContext);
8620
9730
  break;
8621
9731
  }
9732
+ if (packType === "page" && route && !id) {
9733
+ const resolvedPath = essencePath ? resolveUserPath(essencePath) : join28(process.cwd(), "decantr.essence.json");
9734
+ id = resolvePagePackIdForRoute(resolvedPath, route);
9735
+ }
8622
9736
  await printHostedSelectedExecutionPack(
8623
9737
  packType,
8624
9738
  id,