@decantr/cli 1.5.0 → 1.5.2

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.
@@ -9,14 +9,14 @@ import {
9
9
  scaffoldMinimal,
10
10
  scaffoldProject,
11
11
  syncRegistry
12
- } from "./chunk-6K6ZPDT4.js";
12
+ } from "./chunk-6RJSFLT4.js";
13
13
 
14
14
  // src/index.ts
15
- import { readFileSync as readFileSync14, existsSync as existsSync19, readdirSync as readdirSync6 } from "fs";
16
- import { join as join19, dirname } from "path";
15
+ import { readFileSync as readFileSync15, existsSync as existsSync23, readdirSync as readdirSync6 } from "fs";
16
+ import { join as join23, dirname as dirname2 } from "path";
17
17
  import { fileURLToPath } from "url";
18
18
  import { validateEssence as validateEssence2, evaluateGuard, isV3 as isV36 } from "@decantr/essence-spec";
19
- import { RegistryAPIClient as RegistryAPIClient2 } from "@decantr/registry";
19
+ import { RegistryAPIClient as RegistryAPIClient3 } from "@decantr/registry";
20
20
 
21
21
  // src/detect.ts
22
22
  import { existsSync, readFileSync } from "fs";
@@ -165,10 +165,10 @@ var CYAN = "\x1B[36m";
165
165
  function ask(question, defaultValue) {
166
166
  const rl = createInterface({ input: process.stdin, output: process.stdout });
167
167
  const prompt = defaultValue ? `${question} ${DIM}(${defaultValue})${RESET}: ` : `${question}: `;
168
- return new Promise((resolve) => {
168
+ return new Promise((resolve2) => {
169
169
  rl.question(prompt, (answer) => {
170
170
  rl.close();
171
- resolve(answer.trim() || defaultValue || "");
171
+ resolve2(answer.trim() || defaultValue || "");
172
172
  });
173
173
  });
174
174
  }
@@ -361,7 +361,7 @@ function mergeWithDefaults(flags, detected) {
361
361
  }
362
362
  async function runSimplifiedInit(blueprints) {
363
363
  const rl = createInterface({ input: process.stdin, output: process.stdout });
364
- const question = (q) => new Promise((resolve) => rl.question(q, resolve));
364
+ const question = (q) => new Promise((resolve2) => rl.question(q, resolve2));
365
365
  console.log("\n? What blueprint would you like to scaffold?\n");
366
366
  console.log(" 1. Decantr default (recommended)");
367
367
  console.log(" 2. Search registry...\n");
@@ -962,7 +962,7 @@ var GREEN4 = "\x1B[32m";
962
962
  var RED3 = "\x1B[31m";
963
963
  var DIM4 = "\x1B[2m";
964
964
  var RESET4 = "\x1B[0m";
965
- async function cmdRefresh(projectRoot = process.cwd()) {
965
+ async function cmdRefresh(projectRoot = process.cwd(), options = {}) {
966
966
  const essencePath = join8(projectRoot, "decantr.essence.json");
967
967
  if (!existsSync8(essencePath)) {
968
968
  console.error(`${RED3}No decantr.essence.json found. Run \`decantr init\` first.${RESET4}`);
@@ -985,7 +985,8 @@ async function cmdRefresh(projectRoot = process.cwd()) {
985
985
  return;
986
986
  }
987
987
  const registryClient = new RegistryClient({
988
- cacheDir: join8(projectRoot, ".decantr", "cache")
988
+ cacheDir: join8(projectRoot, ".decantr", "cache"),
989
+ offline: options.offline
989
990
  });
990
991
  console.log("Regenerating derived files...\n");
991
992
  const result = await refreshDerivedFiles(projectRoot, essence, registryClient);
@@ -2200,7 +2201,9 @@ ${YELLOW5}Next step:${RESET8} Ask your AI assistant to read ${BOLD3}.decantr/ana
2200
2201
  `);
2201
2202
  }
2202
2203
 
2203
- // src/index.ts
2204
+ // src/commands/magic.ts
2205
+ import { join as join19 } from "path";
2206
+ import { existsSync as existsSync19 } from "fs";
2204
2207
  var BOLD4 = "\x1B[1m";
2205
2208
  var DIM9 = "\x1B[2m";
2206
2209
  var RESET9 = "\x1B[0m";
@@ -2208,11 +2211,7 @@ var RED7 = "\x1B[31m";
2208
2211
  var GREEN9 = "\x1B[32m";
2209
2212
  var CYAN4 = "\x1B[36m";
2210
2213
  var YELLOW6 = "\x1B[33m";
2211
- function heading(text) {
2212
- return `
2213
- ${BOLD4}${text}${RESET9}
2214
- `;
2215
- }
2214
+ var MAGENTA = "\x1B[35m";
2216
2215
  function success(text) {
2217
2216
  return `${GREEN9}${text}${RESET9}`;
2218
2217
  }
@@ -2225,6 +2224,1022 @@ function dim(text) {
2225
2224
  function cyan(text) {
2226
2225
  return `${CYAN4}${text}${RESET9}`;
2227
2226
  }
2227
+ var THEME_KEYWORDS = {
2228
+ dark: ["dark", "noir", "midnight"],
2229
+ light: ["light", "bright", "white"],
2230
+ neon: ["neon", "cyber", "cyberpunk", "synthwave"],
2231
+ glass: ["glass", "glassmorphic", "frosted", "translucent"],
2232
+ minimal: ["minimal", "minimalist", "clean", "simple"],
2233
+ warm: ["warm", "cozy", "earthy", "organic"],
2234
+ cool: ["cool", "cold", "icy", "arctic"],
2235
+ corporate: ["corporate", "enterprise", "business", "professional"],
2236
+ playful: ["playful", "fun", "vibrant", "colorful"],
2237
+ brutalist: ["brutalist", "brutal", "raw"],
2238
+ elegant: ["elegant", "luxury", "premium", "refined"],
2239
+ retro: ["retro", "vintage", "nostalgic"]
2240
+ };
2241
+ var ARCHETYPE_KEYWORDS = {
2242
+ "ai-chatbot": ["chat", "chatbot", "conversational", "ai-chat", "messaging"],
2243
+ "dashboard-analytics": ["dashboard", "analytics", "metrics", "monitoring", "overview"],
2244
+ "marketplace-platform": ["marketplace", "store", "shop", "ecommerce", "e-commerce"],
2245
+ "portfolio-creative": ["portfolio", "showcase", "gallery"],
2246
+ "blog-editorial": ["blog", "editorial", "journal", "magazine", "news"],
2247
+ "docs-knowledge": ["docs", "documentation", "knowledge", "wiki", "help-center"],
2248
+ "admin-panel": ["admin", "panel", "backoffice", "back-office", "management"],
2249
+ "saas-platform": ["saas", "platform", "subscription", "service"],
2250
+ "marketing-saas": ["landing", "marketing", "homepage", "launch"],
2251
+ "social-feed": ["social", "feed", "community", "forum"],
2252
+ "agent-orchestrator": ["agent", "orchestrator", "workflow", "automation", "pipeline"]
2253
+ };
2254
+ var CONSTRAINT_KEYWORDS = [
2255
+ "mobile-first",
2256
+ "mobile first",
2257
+ "accessible",
2258
+ "accessibility",
2259
+ "a11y",
2260
+ "wcag",
2261
+ "offline",
2262
+ "offline-first",
2263
+ "real-time",
2264
+ "realtime",
2265
+ "real time",
2266
+ "responsive",
2267
+ "high-contrast",
2268
+ "performance",
2269
+ "fast",
2270
+ "seo"
2271
+ ];
2272
+ function parseMagicPrompt(prompt) {
2273
+ const lower = prompt.toLowerCase();
2274
+ const tokens = lower.split(/[\s,;—–\-]+/).filter(Boolean);
2275
+ const themeHints = [];
2276
+ for (const [hint, keywords] of Object.entries(THEME_KEYWORDS)) {
2277
+ if (keywords.some((kw) => tokens.includes(kw) || lower.includes(kw))) {
2278
+ themeHints.push(hint);
2279
+ }
2280
+ }
2281
+ let archetype;
2282
+ let bestArchetypeScore = 0;
2283
+ for (const [archetypeId, keywords] of Object.entries(ARCHETYPE_KEYWORDS)) {
2284
+ const score = keywords.filter((kw) => tokens.includes(kw) || lower.includes(kw)).length;
2285
+ if (score > bestArchetypeScore) {
2286
+ bestArchetypeScore = score;
2287
+ archetype = archetypeId;
2288
+ }
2289
+ }
2290
+ const constraints = [];
2291
+ for (const kw of CONSTRAINT_KEYWORDS) {
2292
+ if (lower.includes(kw)) {
2293
+ constraints.push(kw.replace(/\s+/g, "-"));
2294
+ }
2295
+ }
2296
+ const personalityWords = [
2297
+ "confident",
2298
+ "bold",
2299
+ "sleek",
2300
+ "futuristic",
2301
+ "modern",
2302
+ "classic",
2303
+ "edgy",
2304
+ "sharp",
2305
+ "soft",
2306
+ "rounded",
2307
+ "angular",
2308
+ "geometric",
2309
+ "organic",
2310
+ "fluid",
2311
+ "rigid",
2312
+ "dense",
2313
+ "airy",
2314
+ "spacious",
2315
+ "technical",
2316
+ "creative",
2317
+ "artistic",
2318
+ "industrial",
2319
+ "natural",
2320
+ "techy",
2321
+ "hacker",
2322
+ "startup",
2323
+ "enterprise",
2324
+ "friendly",
2325
+ "serious",
2326
+ "formal",
2327
+ "casual",
2328
+ "approachable",
2329
+ "luxurious",
2330
+ "premium",
2331
+ "polished",
2332
+ "rough",
2333
+ "gritty"
2334
+ ];
2335
+ const personalityHints = personalityWords.filter((w) => tokens.includes(w));
2336
+ const allRecognized = /* @__PURE__ */ new Set([
2337
+ ...Object.values(THEME_KEYWORDS).flat(),
2338
+ ...Object.values(ARCHETYPE_KEYWORDS).flat(),
2339
+ ...CONSTRAINT_KEYWORDS.flatMap((c) => c.split(/\s+/)),
2340
+ ...personalityWords
2341
+ ]);
2342
+ const descTokens = tokens.filter(
2343
+ (t) => !allRecognized.has(t) && t.length > 2
2344
+ );
2345
+ const description = descTokens.length > 0 ? descTokens.join(" ") : prompt.trim();
2346
+ return {
2347
+ description,
2348
+ themeHints,
2349
+ personalityHints,
2350
+ constraints,
2351
+ archetype
2352
+ };
2353
+ }
2354
+ function resolveTheme(hints) {
2355
+ let mode = "dark";
2356
+ if (hints.includes("light")) mode = "light";
2357
+ if (hints.includes("neon") || hints.includes("glass")) return { style: "obsidianite", mode };
2358
+ if (hints.includes("warm") || hints.includes("elegant")) return { style: "aurealis", mode };
2359
+ if (hints.includes("cool") || hints.includes("minimal")) return { style: "glacialis", mode };
2360
+ if (hints.includes("brutalist")) return { style: "ferrocrete", mode };
2361
+ if (hints.includes("corporate")) return { style: "luminarum", mode };
2362
+ if (hints.includes("playful")) return { style: "solstice", mode };
2363
+ if (hints.includes("retro")) return { style: "oxidian", mode };
2364
+ return { style: "luminarum", mode };
2365
+ }
2366
+ function buildPersonality(intent) {
2367
+ if (intent.personalityHints.length > 0) {
2368
+ return intent.personalityHints;
2369
+ }
2370
+ if (intent.themeHints.includes("neon")) return ["bold", "futuristic"];
2371
+ if (intent.themeHints.includes("minimal")) return ["clean", "focused"];
2372
+ if (intent.themeHints.includes("corporate")) return ["professional", "reliable"];
2373
+ if (intent.themeHints.includes("playful")) return ["friendly", "energetic"];
2374
+ return ["professional"];
2375
+ }
2376
+ async function cmdMagic(prompt, projectRoot, options) {
2377
+ console.log("");
2378
+ console.log(`${MAGENTA}${BOLD4} Decantr Magic${RESET9}`);
2379
+ console.log("");
2380
+ const intent = parseMagicPrompt(prompt);
2381
+ console.log(`${BOLD4} Parsed intent:${RESET9}`);
2382
+ console.log(` Description: ${intent.description}`);
2383
+ if (intent.themeHints.length > 0) {
2384
+ console.log(` Theme: ${intent.themeHints.join(", ")}`);
2385
+ }
2386
+ if (intent.personalityHints.length > 0) {
2387
+ console.log(` Personality: ${intent.personalityHints.join(", ")}`);
2388
+ }
2389
+ if (intent.constraints.length > 0) {
2390
+ console.log(` Constraints: ${intent.constraints.join(", ")}`);
2391
+ }
2392
+ if (intent.archetype) {
2393
+ console.log(` Archetype: ${intent.archetype}`);
2394
+ }
2395
+ console.log("");
2396
+ const essencePath = join19(projectRoot, "decantr.essence.json");
2397
+ if (existsSync19(essencePath)) {
2398
+ console.log(error(" decantr.essence.json already exists in this directory."));
2399
+ console.log(dim(" Remove it first or use a different directory."));
2400
+ process.exitCode = 1;
2401
+ return;
2402
+ }
2403
+ const registryClient = new RegistryClient({
2404
+ cacheDir: join19(projectRoot, ".decantr", "cache"),
2405
+ apiUrl: options.registry,
2406
+ offline: options.offline
2407
+ });
2408
+ const apiAvailable = await registryClient.checkApiAvailability();
2409
+ let matchedBlueprint;
2410
+ let blueprintData;
2411
+ if (apiAvailable) {
2412
+ console.log(dim(" Searching registry for matching blueprints..."));
2413
+ const blueprintsResult = await registryClient.fetchBlueprints();
2414
+ const blueprints = blueprintsResult.data.items;
2415
+ const scored = blueprints.map((bp) => {
2416
+ const bpLower = `${bp.id} ${bp.name || ""} ${bp.description || ""}`.toLowerCase();
2417
+ let score = 0;
2418
+ if (intent.archetype) {
2419
+ const archetypeTokens = intent.archetype.split("-");
2420
+ for (const token of archetypeTokens) {
2421
+ if (bpLower.includes(token)) score += 3;
2422
+ }
2423
+ }
2424
+ const descTokens = intent.description.toLowerCase().split(/\s+/);
2425
+ for (const token of descTokens) {
2426
+ if (token.length > 2 && bpLower.includes(token)) score += 2;
2427
+ }
2428
+ for (const hint of intent.themeHints) {
2429
+ if (bpLower.includes(hint)) score += 1;
2430
+ }
2431
+ return { id: bp.id, name: bp.name, description: bp.description, score };
2432
+ });
2433
+ scored.sort((a, b) => b.score - a.score);
2434
+ const best = scored[0];
2435
+ if (best && best.score >= 4) {
2436
+ matchedBlueprint = best.id;
2437
+ console.log("");
2438
+ console.log(`${BOLD4} Matched blueprint:${RESET9} ${cyan(best.id)}`);
2439
+ if (best.description) {
2440
+ console.log(` ${dim(best.description)}`);
2441
+ }
2442
+ const bpResult = await registryClient.fetchBlueprint(best.id);
2443
+ if (bpResult) {
2444
+ const rawBp = bpResult.data;
2445
+ blueprintData = rawBp.data ?? rawBp;
2446
+ }
2447
+ } else {
2448
+ console.log(dim(" No strong blueprint match found. Using archetype-based scaffold."));
2449
+ }
2450
+ } else {
2451
+ console.log(dim(" Offline mode \u2014 using defaults."));
2452
+ }
2453
+ const themeResolved = resolveTheme(intent.themeHints);
2454
+ const personality = buildPersonality(intent);
2455
+ const initOptions = {
2456
+ blueprint: matchedBlueprint,
2457
+ archetype: intent.archetype || blueprintData?.compose?.[0]?.archetype || blueprintData?.compose?.[0] || "dashboard-analytics",
2458
+ theme: themeResolved.style,
2459
+ mode: themeResolved.mode,
2460
+ shape: "rounded",
2461
+ target: "react",
2462
+ guard: "guided",
2463
+ density: intent.constraints.includes("mobile-first") ? "compact" : "comfortable",
2464
+ shell: "sidebar-main",
2465
+ personality,
2466
+ features: [],
2467
+ existing: false
2468
+ };
2469
+ if (blueprintData) {
2470
+ if (blueprintData.theme?.style) initOptions.theme = blueprintData.theme.style;
2471
+ if (blueprintData.theme?.mode) initOptions.mode = blueprintData.theme.mode;
2472
+ if (blueprintData.theme?.shape) initOptions.shape = blueprintData.theme.shape;
2473
+ if (blueprintData.personality) {
2474
+ initOptions.personality = typeof blueprintData.personality === "string" ? [blueprintData.personality] : blueprintData.personality;
2475
+ }
2476
+ if (intent.personalityHints.length > 0) {
2477
+ const merged = /* @__PURE__ */ new Set([...initOptions.personality, ...intent.personalityHints]);
2478
+ initOptions.personality = [...merged];
2479
+ }
2480
+ }
2481
+ if (options.dryRun) {
2482
+ console.log("");
2483
+ console.log(`${YELLOW6}${BOLD4} Dry run \u2014 no files written${RESET9}`);
2484
+ console.log("");
2485
+ console.log(` Blueprint: ${matchedBlueprint || dim("(none \u2014 archetype-based)")}`);
2486
+ console.log(` Theme: ${initOptions.theme} (${initOptions.mode})`);
2487
+ console.log(` Personality: ${initOptions.personality.join(", ")}`);
2488
+ console.log(` Archetype: ${initOptions.archetype}`);
2489
+ console.log(` Guard: ${initOptions.guard}`);
2490
+ console.log(` Density: ${initOptions.density}`);
2491
+ console.log("");
2492
+ return;
2493
+ }
2494
+ console.log("");
2495
+ const detected = detectProject(projectRoot);
2496
+ let archetypeData;
2497
+ let composedSections;
2498
+ let routeMap;
2499
+ let patternSpecs;
2500
+ let topologyMarkdown = "";
2501
+ let themeData;
2502
+ let recipeData;
2503
+ let blueprintRecipeName;
2504
+ let registrySource = apiAvailable ? "api" : "cache";
2505
+ if (blueprintData?.compose && blueprintData.compose.length > 0) {
2506
+ const entries = blueprintData.compose;
2507
+ const archetypeMap = /* @__PURE__ */ new Map();
2508
+ for (const entry of entries) {
2509
+ const id = typeof entry === "string" ? entry : entry.archetype;
2510
+ const result2 = await registryClient.fetchArchetype(id);
2511
+ if (result2) {
2512
+ const raw = result2.data;
2513
+ archetypeMap.set(id, raw.data ?? raw);
2514
+ } else {
2515
+ archetypeMap.set(id, null);
2516
+ }
2517
+ }
2518
+ composedSections = composeSections(entries, archetypeMap, blueprintData.overrides);
2519
+ const primaryId = typeof entries[0] === "string" ? entries[0] : entries[0].archetype;
2520
+ initOptions.archetype = primaryId;
2521
+ if (composedSections.sections[0]?.shell) {
2522
+ initOptions.shell = composedSections.sections[0].shell;
2523
+ }
2524
+ const allPages = composedSections.sections.flatMap(
2525
+ (s) => s.pages.map((p) => ({
2526
+ id: p.id,
2527
+ shell: p.shell_override || s.shell,
2528
+ default_layout: p.layout
2529
+ }))
2530
+ );
2531
+ archetypeData = {
2532
+ id: primaryId,
2533
+ pages: allPages,
2534
+ features: composedSections.features
2535
+ };
2536
+ routeMap = {};
2537
+ if (blueprintData.routes) {
2538
+ for (const [path, entry] of Object.entries(blueprintData.routes)) {
2539
+ if (entry.archetype && entry.page) {
2540
+ routeMap[path] = { section: entry.archetype, page: entry.page };
2541
+ const section = composedSections.sections.find((s) => s.id === entry.archetype);
2542
+ const page = section?.pages.find((p) => p.id === entry.page);
2543
+ if (page) page.route = path;
2544
+ }
2545
+ }
2546
+ }
2547
+ const allPatternIds = /* @__PURE__ */ new Set();
2548
+ for (const section of composedSections.sections) {
2549
+ for (const page of section.pages) {
2550
+ if (page.patterns) {
2551
+ for (const ref of page.patterns) allPatternIds.add(ref.pattern);
2552
+ }
2553
+ for (const item of page.layout) {
2554
+ if (typeof item === "string") allPatternIds.add(item);
2555
+ }
2556
+ }
2557
+ }
2558
+ patternSpecs = {};
2559
+ for (const pid of allPatternIds) {
2560
+ try {
2561
+ const result2 = await registryClient.fetchPattern(pid);
2562
+ if (result2) {
2563
+ const raw = result2.data;
2564
+ const inner = raw.data ?? raw;
2565
+ const defaultPreset = inner.default_preset || "standard";
2566
+ const preset = inner.presets?.[defaultPreset];
2567
+ patternSpecs[pid] = {
2568
+ description: inner.description || "",
2569
+ components: inner.components || [],
2570
+ slots: preset?.layout?.slots || {}
2571
+ };
2572
+ }
2573
+ } catch {
2574
+ }
2575
+ }
2576
+ const zoneInputs = [];
2577
+ for (const entry of entries) {
2578
+ const arcId = typeof entry === "string" ? entry : entry.archetype;
2579
+ const archData = archetypeMap.get(arcId);
2580
+ if (archData) {
2581
+ const explicitRole = typeof entry === "object" && "role" in entry ? entry.role : void 0;
2582
+ zoneInputs.push({
2583
+ archetypeId: arcId,
2584
+ role: explicitRole || archData.role || "auxiliary",
2585
+ shell: archData.pages?.[0]?.shell || initOptions.shell,
2586
+ features: archData.features || [],
2587
+ description: archData.description || ""
2588
+ });
2589
+ }
2590
+ }
2591
+ const zones = deriveZones(zoneInputs);
2592
+ const transitions = deriveTransitions(zones);
2593
+ if (zones.length > 0) {
2594
+ topologyMarkdown = generateTopologySection(
2595
+ {
2596
+ intent: blueprintData.description || initOptions.archetype || "Application",
2597
+ zones,
2598
+ transitions,
2599
+ entryPoints: {
2600
+ anonymous: "/",
2601
+ authenticated: `/${archetypeData.pages?.[0]?.id || "home"}`
2602
+ }
2603
+ },
2604
+ initOptions.personality
2605
+ );
2606
+ }
2607
+ blueprintRecipeName = blueprintData.theme?.recipe;
2608
+ console.log(`${BOLD4} Composition:${RESET9}`);
2609
+ console.log(` Sections: ${composedSections.sections.length} (${composedSections.sections.map((s) => s.id).join(", ")})`);
2610
+ const totalRoutes = Object.keys(routeMap).length;
2611
+ if (totalRoutes > 0) console.log(` Routes: ${totalRoutes}`);
2612
+ if (composedSections.features.length > 0) {
2613
+ console.log(` Features: ${composedSections.features.join(", ")}`);
2614
+ }
2615
+ console.log("");
2616
+ } else if (intent.archetype && apiAvailable) {
2617
+ const archResult = await registryClient.fetchArchetype(initOptions.archetype);
2618
+ if (archResult) {
2619
+ const raw = archResult.data;
2620
+ archetypeData = raw.data ?? raw;
2621
+ }
2622
+ }
2623
+ if (apiAvailable && initOptions.theme) {
2624
+ const themeResult = await registryClient.fetchTheme(initOptions.theme);
2625
+ if (themeResult) {
2626
+ const rawTheme = themeResult.data;
2627
+ const theme = rawTheme.data ?? rawTheme;
2628
+ themeData = {
2629
+ seed: theme.seed,
2630
+ palette: theme.palette,
2631
+ tokens: theme.tokens,
2632
+ cvd_support: theme.cvd_support,
2633
+ typography_hints: theme.typography_hints,
2634
+ motion_hints: theme.motion_hints
2635
+ };
2636
+ if (theme.decorators) {
2637
+ recipeData = { decorators: theme.decorators };
2638
+ }
2639
+ }
2640
+ const recipeName = blueprintRecipeName || initOptions.theme;
2641
+ const recipeResult = await registryClient.fetchRecipe(recipeName);
2642
+ if (recipeResult) {
2643
+ const rawRecipe = recipeResult.data;
2644
+ const recipe = rawRecipe.data ?? rawRecipe;
2645
+ recipeData = {
2646
+ decorators: recipe.decorators || recipeData?.decorators,
2647
+ spatial_hints: recipe.spatial_hints,
2648
+ radius_hints: recipe.radius_hints
2649
+ };
2650
+ }
2651
+ }
2652
+ console.log(`${BOLD4} Scaffolding...${RESET9}`);
2653
+ const result = await scaffoldProject(
2654
+ projectRoot,
2655
+ initOptions,
2656
+ detected,
2657
+ registryClient,
2658
+ archetypeData,
2659
+ registrySource,
2660
+ themeData,
2661
+ recipeData,
2662
+ topologyMarkdown,
2663
+ composedSections,
2664
+ routeMap,
2665
+ patternSpecs,
2666
+ blueprintData
2667
+ );
2668
+ console.log(` ${success("Created")} decantr.essence.json (V3.1)`);
2669
+ console.log(` ${success("Created")} DECANTR.md`);
2670
+ if (result.cssFiles && result.cssFiles.length > 0) {
2671
+ for (const cssFile of result.cssFiles) {
2672
+ const name = cssFile.split("/").pop();
2673
+ console.log(` ${success("Created")} src/styles/${name}`);
2674
+ }
2675
+ }
2676
+ if (result.contextFiles && result.contextFiles.length > 0) {
2677
+ const sectionContexts = result.contextFiles.filter((f) => f.includes("section-"));
2678
+ const otherContexts = result.contextFiles.filter((f) => !f.includes("section-"));
2679
+ if (sectionContexts.length > 0) {
2680
+ console.log(` ${success("Created")} ${sectionContexts.length} section context(s)`);
2681
+ }
2682
+ for (const f of otherContexts) {
2683
+ const name = f.split("/").pop();
2684
+ if (name && !name.startsWith("task-") && !name.startsWith("essence-summary")) {
2685
+ console.log(` ${success("Created")} ${name}`);
2686
+ }
2687
+ }
2688
+ }
2689
+ if (result.gitignoreUpdated) {
2690
+ console.log(` ${dim(".gitignore updated")}`);
2691
+ }
2692
+ console.log("");
2693
+ console.log(`${BOLD4} Ready!${RESET9} Next steps:`);
2694
+ console.log(` 1. Read ${cyan("DECANTR.md")} to understand the design system`);
2695
+ console.log(` 2. Read ${cyan(".decantr/context/scaffold.md")} for the full app overview`);
2696
+ console.log(` 3. Start building pages from the route map`);
2697
+ console.log("");
2698
+ }
2699
+
2700
+ // src/commands/export.ts
2701
+ import { readFileSync as readFileSync14, writeFileSync as writeFileSync10, existsSync as existsSync20, mkdirSync as mkdirSync5 } from "fs";
2702
+ import { join as join20, dirname } from "path";
2703
+ var GREEN10 = "\x1B[32m";
2704
+ var RED8 = "\x1B[31m";
2705
+ var DIM10 = "\x1B[2m";
2706
+ var RESET10 = "\x1B[0m";
2707
+ var SHADCN_MAP = {
2708
+ "--d-bg": "--background",
2709
+ "--d-text": "--foreground",
2710
+ "--d-surface": "--card",
2711
+ "--d-surface-raised": "--popover",
2712
+ "--d-primary": "--primary",
2713
+ "--d-secondary": "--secondary",
2714
+ "--d-accent": "--accent",
2715
+ "--d-border": "--border",
2716
+ "--d-text-muted": "--muted-foreground",
2717
+ "--d-error": "--destructive",
2718
+ "--d-radius": "--radius"
2719
+ };
2720
+ var TAILWIND_COLOR_MAP = {
2721
+ "--d-primary": "primary",
2722
+ "--d-secondary": "secondary",
2723
+ "--d-accent": "accent",
2724
+ "--d-bg": "background",
2725
+ "--d-surface": "surface",
2726
+ "--d-surface-raised": "surface-raised",
2727
+ "--d-border": "border",
2728
+ "--d-text": "foreground",
2729
+ "--d-text-muted": "muted",
2730
+ "--d-success": "success",
2731
+ "--d-error": "error",
2732
+ "--d-warning": "warning",
2733
+ "--d-info": "info"
2734
+ };
2735
+ function parseTokensCSS(css) {
2736
+ const tokens = /* @__PURE__ */ new Map();
2737
+ const re = /(--d-[\w-]+)\s*:\s*([^;]+);/g;
2738
+ let match;
2739
+ while ((match = re.exec(css)) !== null) {
2740
+ tokens.set(match[1], match[2].trim());
2741
+ }
2742
+ return tokens;
2743
+ }
2744
+ function generateShadcnCSS(tokens) {
2745
+ const lines = ["/* Exported by decantr export --to shadcn */", "@layer base {", " :root {"];
2746
+ for (const [decantrVar, shadcnVar] of Object.entries(SHADCN_MAP)) {
2747
+ const value = tokens.get(decantrVar);
2748
+ if (value) {
2749
+ lines.push(` ${shadcnVar}: ${value};`);
2750
+ }
2751
+ }
2752
+ const textValue = tokens.get("--d-text");
2753
+ if (textValue) {
2754
+ lines.push(` --card-foreground: ${textValue};`);
2755
+ lines.push(` --popover-foreground: ${textValue};`);
2756
+ }
2757
+ const surfaceValue = tokens.get("--d-surface");
2758
+ if (surfaceValue) {
2759
+ lines.push(` --muted: ${surfaceValue};`);
2760
+ }
2761
+ const accentFg = tokens.get("--d-text");
2762
+ if (accentFg) {
2763
+ lines.push(` --accent-foreground: ${accentFg};`);
2764
+ }
2765
+ lines.push(` --destructive-foreground: #FAFAFA;`);
2766
+ lines.push(" }", "}", "");
2767
+ return lines.join("\n");
2768
+ }
2769
+ function generateShadcnComponentsJSON() {
2770
+ const config = {
2771
+ $schema: "https://ui.shadcn.com/schema.json",
2772
+ style: "default",
2773
+ rsc: false,
2774
+ tsx: true,
2775
+ tailwind: {
2776
+ config: "tailwind.config.ts",
2777
+ css: "src/styles/shadcn-theme.css",
2778
+ baseColor: "zinc"
2779
+ },
2780
+ aliases: {
2781
+ components: "@/components",
2782
+ utils: "@/lib/utils"
2783
+ }
2784
+ };
2785
+ return JSON.stringify(config, null, 2) + "\n";
2786
+ }
2787
+ function generateTailwindConfig(tokens) {
2788
+ const colors = {};
2789
+ for (const [decantrVar, twName] of Object.entries(TAILWIND_COLOR_MAP)) {
2790
+ const value = tokens.get(decantrVar);
2791
+ if (value) {
2792
+ colors[twName] = value;
2793
+ }
2794
+ }
2795
+ const borderRadius = {};
2796
+ for (const suffix of ["", "-sm", "-lg", "-xl", "-full"]) {
2797
+ const key = `--d-radius${suffix}`;
2798
+ const value = tokens.get(key);
2799
+ if (value) {
2800
+ const name = suffix ? suffix.slice(1) : "DEFAULT";
2801
+ borderRadius[name] = value;
2802
+ }
2803
+ }
2804
+ const boxShadow = {};
2805
+ for (const suffix of ["-sm", "", "-md", "-lg"]) {
2806
+ const key = `--d-shadow${suffix}`;
2807
+ const value = tokens.get(key);
2808
+ if (value) {
2809
+ const name = suffix ? suffix.slice(1) : "DEFAULT";
2810
+ boxShadow[name] = value;
2811
+ }
2812
+ }
2813
+ const lines = [
2814
+ "// Generated by decantr export --to tailwind",
2815
+ "import type { Config } from 'tailwindcss';",
2816
+ "",
2817
+ "export default {",
2818
+ " theme: {",
2819
+ " extend: {"
2820
+ ];
2821
+ lines.push(" colors: {");
2822
+ for (const [name, value] of Object.entries(colors)) {
2823
+ lines.push(` '${name}': '${value}',`);
2824
+ }
2825
+ lines.push(" },");
2826
+ lines.push(" borderRadius: {");
2827
+ for (const [name, value] of Object.entries(borderRadius)) {
2828
+ lines.push(` '${name}': '${value}',`);
2829
+ }
2830
+ lines.push(" },");
2831
+ lines.push(" boxShadow: {");
2832
+ for (const [name, value] of Object.entries(boxShadow)) {
2833
+ lines.push(` '${name}': '${value}',`);
2834
+ }
2835
+ lines.push(" },");
2836
+ lines.push(" },", " },", "} satisfies Partial<Config>;", "");
2837
+ return lines.join("\n");
2838
+ }
2839
+ function generateCSSVars(tokens) {
2840
+ const lines = ["/* Exported by decantr export --to css-vars */", ":root {"];
2841
+ for (const [key, value] of tokens) {
2842
+ lines.push(` ${key}: ${value};`);
2843
+ }
2844
+ lines.push("}", "");
2845
+ return lines.join("\n");
2846
+ }
2847
+ async function cmdExport(target, projectRoot, options = {}) {
2848
+ const essencePath = join20(projectRoot, "decantr.essence.json");
2849
+ const tokensPath = join20(projectRoot, "src", "styles", "tokens.css");
2850
+ if (!existsSync20(essencePath)) {
2851
+ console.error(`${RED8}No decantr.essence.json found. Run \`decantr init\` first.${RESET10}`);
2852
+ process.exitCode = 1;
2853
+ return;
2854
+ }
2855
+ if (!existsSync20(tokensPath)) {
2856
+ console.error(`${RED8}No src/styles/tokens.css found. Run \`decantr refresh\` to generate tokens.${RESET10}`);
2857
+ process.exitCode = 1;
2858
+ return;
2859
+ }
2860
+ const tokensCSS = readFileSync14(tokensPath, "utf-8");
2861
+ const tokens = parseTokensCSS(tokensCSS);
2862
+ if (tokens.size === 0) {
2863
+ console.error(`${RED8}No --d-* tokens found in tokens.css.${RESET10}`);
2864
+ process.exitCode = 1;
2865
+ return;
2866
+ }
2867
+ switch (target) {
2868
+ case "shadcn": {
2869
+ const cssOut = options.output ?? join20(projectRoot, "src", "styles", "shadcn-theme.css");
2870
+ const jsonOut = join20(projectRoot, "components.json");
2871
+ ensureDir(cssOut);
2872
+ writeFileSync10(cssOut, generateShadcnCSS(tokens), "utf-8");
2873
+ writeFileSync10(jsonOut, generateShadcnComponentsJSON(), "utf-8");
2874
+ console.log(`${GREEN10}Exported shadcn theme:${RESET10}`);
2875
+ console.log(` ${DIM10}CSS:${RESET10} ${cssOut}`);
2876
+ console.log(` ${DIM10}JSON:${RESET10} ${jsonOut}`);
2877
+ break;
2878
+ }
2879
+ case "tailwind": {
2880
+ const out = options.output ?? join20(projectRoot, "tailwind.decantr.config.ts");
2881
+ ensureDir(out);
2882
+ writeFileSync10(out, generateTailwindConfig(tokens), "utf-8");
2883
+ console.log(`${GREEN10}Exported Tailwind config:${RESET10}`);
2884
+ console.log(` ${DIM10}File:${RESET10} ${out}`);
2885
+ break;
2886
+ }
2887
+ case "css-vars": {
2888
+ const out = options.output ?? join20(projectRoot, "decantr-tokens.css");
2889
+ ensureDir(out);
2890
+ writeFileSync10(out, generateCSSVars(tokens), "utf-8");
2891
+ console.log(`${GREEN10}Exported CSS variables:${RESET10}`);
2892
+ console.log(` ${DIM10}File:${RESET10} ${out}`);
2893
+ break;
2894
+ }
2895
+ }
2896
+ }
2897
+ function ensureDir(filePath) {
2898
+ const dir = dirname(filePath);
2899
+ if (!existsSync20(dir)) {
2900
+ mkdirSync5(dir, { recursive: true });
2901
+ }
2902
+ }
2903
+
2904
+ // src/commands/registry-mirror.ts
2905
+ import { mkdirSync as mkdirSync6, writeFileSync as writeFileSync11 } from "fs";
2906
+ import { join as join21 } from "path";
2907
+ import { RegistryAPIClient as RegistryAPIClient2 } from "@decantr/registry";
2908
+ var GREEN11 = "\x1B[32m";
2909
+ var RED9 = "\x1B[31m";
2910
+ var DIM11 = "\x1B[2m";
2911
+ var CYAN5 = "\x1B[36m";
2912
+ var YELLOW7 = "\x1B[33m";
2913
+ var RESET11 = "\x1B[0m";
2914
+ var ALL_CONTENT_TYPES = [
2915
+ "patterns",
2916
+ "archetypes",
2917
+ "themes",
2918
+ "recipes",
2919
+ "blueprints",
2920
+ "shells"
2921
+ ];
2922
+ async function cmdRegistryMirror(projectRoot, options = {}) {
2923
+ const apiUrl = process.env.DECANTR_API_URL || "https://api.decantr.ai/v1";
2924
+ const apiClient = new RegistryAPIClient2({
2925
+ baseUrl: apiUrl,
2926
+ apiKey: process.env.DECANTR_API_KEY || void 0
2927
+ });
2928
+ const healthy = await apiClient.checkHealth();
2929
+ if (!healthy) {
2930
+ console.error(`${RED9}Registry API is unavailable. Check your connection.${RESET11}`);
2931
+ process.exitCode = 1;
2932
+ return;
2933
+ }
2934
+ const types = options.type ? [options.type] : ALL_CONTENT_TYPES;
2935
+ if (options.type && !ALL_CONTENT_TYPES.includes(options.type)) {
2936
+ console.error(`${RED9}Unknown content type: ${options.type}${RESET11}`);
2937
+ console.error(`${DIM11}Valid types: ${ALL_CONTENT_TYPES.join(", ")}${RESET11}`);
2938
+ process.exitCode = 1;
2939
+ return;
2940
+ }
2941
+ const cacheDir = join21(projectRoot, ".decantr", "cache");
2942
+ const counts = {};
2943
+ const failed = [];
2944
+ console.log(`
2945
+ Mirroring registry content to ${DIM11}.decantr/cache/${RESET11}
2946
+ `);
2947
+ for (const type of types) {
2948
+ try {
2949
+ const result = await apiClient.listContent(type, { namespace: "@official" });
2950
+ const items = result.items;
2951
+ const typeDir = join21(cacheDir, "@official", type);
2952
+ mkdirSync6(typeDir, { recursive: true });
2953
+ writeFileSync11(join21(typeDir, "index.json"), JSON.stringify(result, null, 2));
2954
+ let itemCount = 0;
2955
+ for (const item of items) {
2956
+ const slug = item.slug || item.id;
2957
+ if (!slug) continue;
2958
+ try {
2959
+ const fullItem = await apiClient.getContent(type, "@official", slug);
2960
+ writeFileSync11(join21(typeDir, `${slug}.json`), JSON.stringify(fullItem, null, 2));
2961
+ itemCount++;
2962
+ } catch {
2963
+ writeFileSync11(join21(typeDir, `${slug}.json`), JSON.stringify(item, null, 2));
2964
+ itemCount++;
2965
+ }
2966
+ }
2967
+ counts[type] = itemCount;
2968
+ console.log(` ${GREEN11}\u2713${RESET11} ${type}: ${CYAN5}${itemCount}${RESET11} items`);
2969
+ } catch (e) {
2970
+ failed.push(type);
2971
+ console.log(` ${RED9}\u2717${RESET11} ${type}: ${e.message}`);
2972
+ }
2973
+ }
2974
+ const manifest = {
2975
+ mirrored_at: (/* @__PURE__ */ new Date()).toISOString(),
2976
+ counts
2977
+ };
2978
+ mkdirSync6(join21(cacheDir), { recursive: true });
2979
+ writeFileSync11(join21(cacheDir, "mirror-manifest.json"), JSON.stringify(manifest, null, 2));
2980
+ const totalItems = Object.values(counts).reduce((a, b) => a + b, 0);
2981
+ console.log("");
2982
+ if (failed.length > 0) {
2983
+ console.log(`${YELLOW7}Mirrored ${totalItems} items (${failed.length} type(s) failed)${RESET11}`);
2984
+ } else {
2985
+ console.log(`${GREEN11}Mirrored ${totalItems} items across ${Object.keys(counts).length} types${RESET11}`);
2986
+ }
2987
+ console.log(`${DIM11}Use \`decantr init --offline\` or \`decantr refresh --offline\` to work without API.${RESET11}
2988
+ `);
2989
+ }
2990
+
2991
+ // src/commands/new-project.ts
2992
+ import { existsSync as existsSync22, mkdirSync as mkdirSync7, writeFileSync as writeFileSync12 } from "fs";
2993
+ import { join as join22, resolve } from "path";
2994
+ import { execSync } from "child_process";
2995
+ var BOLD5 = "\x1B[1m";
2996
+ var DIM12 = "\x1B[2m";
2997
+ var RESET12 = "\x1B[0m";
2998
+ var RED10 = "\x1B[31m";
2999
+ var GREEN12 = "\x1B[32m";
3000
+ var CYAN6 = "\x1B[36m";
3001
+ var YELLOW8 = "\x1B[33m";
3002
+ function heading(text) {
3003
+ return `
3004
+ ${BOLD5}${text}${RESET12}
3005
+ `;
3006
+ }
3007
+ function success2(text) {
3008
+ return `${GREEN12}${text}${RESET12}`;
3009
+ }
3010
+ function error2(text) {
3011
+ return `${RED10}${text}${RESET12}`;
3012
+ }
3013
+ function dim2(text) {
3014
+ return `${DIM12}${text}${RESET12}`;
3015
+ }
3016
+ function cyan2(text) {
3017
+ return `${CYAN6}${text}${RESET12}`;
3018
+ }
3019
+ async function cmdNewProject(projectName, options) {
3020
+ const projectDir = resolve(process.cwd(), projectName);
3021
+ if (!/^[a-z0-9][a-z0-9._-]*$/i.test(projectName)) {
3022
+ console.error(error2("Invalid project name. Use alphanumeric characters, hyphens, dots, or underscores."));
3023
+ process.exitCode = 1;
3024
+ return;
3025
+ }
3026
+ if (existsSync22(projectDir)) {
3027
+ console.error(error2(`Directory "${projectName}" already exists.`));
3028
+ process.exitCode = 1;
3029
+ return;
3030
+ }
3031
+ console.log(heading(`Creating ${projectName}...`));
3032
+ mkdirSync7(projectDir, { recursive: true });
3033
+ console.log(dim2(` Created ${projectName}/`));
3034
+ const packageJson = {
3035
+ name: projectName,
3036
+ private: true,
3037
+ version: "0.0.0",
3038
+ type: "module",
3039
+ scripts: {
3040
+ dev: "vite",
3041
+ build: "tsc -b && vite build",
3042
+ preview: "vite preview"
3043
+ },
3044
+ dependencies: {
3045
+ "react": "^19.0.0",
3046
+ "react-dom": "^19.0.0",
3047
+ "react-router-dom": "^7.0.0",
3048
+ "@decantr/css": "^1.0.0"
3049
+ },
3050
+ devDependencies: {
3051
+ "@types/react": "^19.0.0",
3052
+ "@types/react-dom": "^19.0.0",
3053
+ "@vitejs/plugin-react": "^4.0.0",
3054
+ "typescript": "^5.7.0",
3055
+ "vite": "^6.0.0"
3056
+ }
3057
+ };
3058
+ writeFileSync12(join22(projectDir, "package.json"), JSON.stringify(packageJson, null, 2) + "\n");
3059
+ console.log(dim2(" Created package.json"));
3060
+ const viteConfig = `import { defineConfig } from 'vite';
3061
+ import react from '@vitejs/plugin-react';
3062
+
3063
+ export default defineConfig({
3064
+ plugins: [react()],
3065
+ });
3066
+ `;
3067
+ writeFileSync12(join22(projectDir, "vite.config.ts"), viteConfig);
3068
+ console.log(dim2(" Created vite.config.ts"));
3069
+ const tsconfig = {
3070
+ compilerOptions: {
3071
+ target: "ES2020",
3072
+ useDefineForClassFields: true,
3073
+ lib: ["ES2020", "DOM", "DOM.Iterable"],
3074
+ module: "ESNext",
3075
+ skipLibCheck: true,
3076
+ moduleResolution: "bundler",
3077
+ allowImportingTsExtensions: true,
3078
+ isolatedModules: true,
3079
+ moduleDetection: "force",
3080
+ noEmit: true,
3081
+ jsx: "react-jsx",
3082
+ strict: true,
3083
+ noUnusedLocals: true,
3084
+ noUnusedParameters: true,
3085
+ noFallthroughCasesInSwitch: true,
3086
+ noUncheckedSideEffectImports: true
3087
+ },
3088
+ include: ["src"]
3089
+ };
3090
+ writeFileSync12(join22(projectDir, "tsconfig.json"), JSON.stringify(tsconfig, null, 2) + "\n");
3091
+ const tsconfigApp = {
3092
+ compilerOptions: {
3093
+ tsBuildInfoFile: "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
3094
+ target: "ES2020",
3095
+ useDefineForClassFields: true,
3096
+ lib: ["ES2020", "DOM", "DOM.Iterable"],
3097
+ module: "ESNext",
3098
+ skipLibCheck: true,
3099
+ moduleResolution: "bundler",
3100
+ allowImportingTsExtensions: true,
3101
+ isolatedModules: true,
3102
+ moduleDetection: "force",
3103
+ noEmit: true,
3104
+ jsx: "react-jsx",
3105
+ strict: true,
3106
+ noUnusedLocals: true,
3107
+ noUnusedParameters: true,
3108
+ noFallthroughCasesInSwitch: true,
3109
+ noUncheckedSideEffectImports: true
3110
+ },
3111
+ include: ["src"]
3112
+ };
3113
+ writeFileSync12(join22(projectDir, "tsconfig.app.json"), JSON.stringify(tsconfigApp, null, 2) + "\n");
3114
+ console.log(dim2(" Created tsconfig.json"));
3115
+ const title = projectName.replace(/[-_]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
3116
+ const indexHtml = `<!doctype html>
3117
+ <html lang="en">
3118
+ <head>
3119
+ <meta charset="UTF-8" />
3120
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
3121
+ <title>${title}</title>
3122
+ </head>
3123
+ <body>
3124
+ <div id="root"></div>
3125
+ <script type="module" src="/src/main.tsx"></script>
3126
+ </body>
3127
+ </html>
3128
+ `;
3129
+ writeFileSync12(join22(projectDir, "index.html"), indexHtml);
3130
+ console.log(dim2(" Created index.html"));
3131
+ const srcDir = join22(projectDir, "src");
3132
+ mkdirSync7(srcDir, { recursive: true });
3133
+ const mainTsx = `import { StrictMode } from 'react';
3134
+ import { createRoot } from 'react-dom/client';
3135
+ import { BrowserRouter } from 'react-router-dom';
3136
+ import { App } from './App';
3137
+ import './styles/tokens.css';
3138
+ import './styles/decorators.css';
3139
+ import './styles/global.css';
3140
+
3141
+ createRoot(document.getElementById('root')!).render(
3142
+ <StrictMode>
3143
+ <BrowserRouter>
3144
+ <App />
3145
+ </BrowserRouter>
3146
+ </StrictMode>,
3147
+ );
3148
+ `;
3149
+ writeFileSync12(join22(srcDir, "main.tsx"), mainTsx);
3150
+ const appTsx = `import { Routes, Route } from 'react-router-dom';
3151
+
3152
+ function WelcomePage() {
3153
+ return (
3154
+ <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', minHeight: '100vh', gap: '1rem' }}>
3155
+ <h1>${title}</h1>
3156
+ <p style={{ opacity: 0.6 }}>Scaffolded with Decantr. Run <code>decantr status</code> to check project health.</p>
3157
+ </div>
3158
+ );
3159
+ }
3160
+
3161
+ export function App() {
3162
+ return (
3163
+ <Routes>
3164
+ <Route path="/" element={<WelcomePage />} />
3165
+ </Routes>
3166
+ );
3167
+ }
3168
+ `;
3169
+ writeFileSync12(join22(srcDir, "App.tsx"), appTsx);
3170
+ writeFileSync12(join22(srcDir, "vite-env.d.ts"), '/// <reference types="vite/client" />\n');
3171
+ mkdirSync7(join22(srcDir, "styles"), { recursive: true });
3172
+ console.log(dim2(" Created src/"));
3173
+ console.log(heading("Installing dependencies..."));
3174
+ const packageManager = detectPackageManager();
3175
+ try {
3176
+ execSync(`${packageManager} install`, { cwd: projectDir, stdio: "inherit" });
3177
+ } catch {
3178
+ console.log(`
3179
+ ${YELLOW8}Dependency install failed. Run \`${packageManager} install\` manually.${RESET12}`);
3180
+ }
3181
+ console.log(heading("Initializing Decantr..."));
3182
+ const initFlags = ["--yes", "--existing"];
3183
+ if (options.blueprint) initFlags.push(`--blueprint=${options.blueprint}`);
3184
+ if (options.archetype) initFlags.push(`--archetype=${options.archetype}`);
3185
+ if (options.theme) initFlags.push(`--theme=${options.theme}`);
3186
+ if (options.mode) initFlags.push(`--mode=${options.mode}`);
3187
+ if (options.shape) initFlags.push(`--shape=${options.shape}`);
3188
+ if (options.offline) initFlags.push("--offline");
3189
+ if (options.registry) initFlags.push(`--registry=${options.registry}`);
3190
+ try {
3191
+ const cliBin = join22(__dirname, "..", "bin", "decantr.js");
3192
+ const cliPath = existsSync22(cliBin) ? `node ${cliBin}` : "npx decantr";
3193
+ execSync(`${cliPath} init ${initFlags.join(" ")}`, { cwd: projectDir, stdio: "inherit" });
3194
+ } catch {
3195
+ console.log(`
3196
+ ${YELLOW8}Decantr init encountered issues. Run \`decantr init\` manually inside ${projectName}/.${RESET12}`);
3197
+ }
3198
+ console.log(success2(`
3199
+ \u2713 Project "${projectName}" created!
3200
+ `));
3201
+ console.log(` ${cyan2("cd " + projectName)}`);
3202
+ console.log(` ${cyan2(packageManager + " run dev")}`);
3203
+ console.log("");
3204
+ }
3205
+ function detectPackageManager() {
3206
+ if (existsSync22(join22(process.cwd(), "pnpm-lock.yaml")) || existsSync22(join22(process.cwd(), "pnpm-workspace.yaml"))) {
3207
+ return "pnpm";
3208
+ }
3209
+ if (existsSync22(join22(process.cwd(), "yarn.lock"))) {
3210
+ return "yarn";
3211
+ }
3212
+ if (existsSync22(join22(process.cwd(), "bun.lockb")) || existsSync22(join22(process.cwd(), "bun.lock"))) {
3213
+ return "bun";
3214
+ }
3215
+ return "npm";
3216
+ }
3217
+
3218
+ // src/index.ts
3219
+ var BOLD6 = "\x1B[1m";
3220
+ var DIM13 = "\x1B[2m";
3221
+ var RESET13 = "\x1B[0m";
3222
+ var RED11 = "\x1B[31m";
3223
+ var GREEN13 = "\x1B[32m";
3224
+ var CYAN7 = "\x1B[36m";
3225
+ var YELLOW9 = "\x1B[33m";
3226
+ function heading2(text) {
3227
+ return `
3228
+ ${BOLD6}${text}${RESET13}
3229
+ `;
3230
+ }
3231
+ function success3(text) {
3232
+ return `${GREEN13}${text}${RESET13}`;
3233
+ }
3234
+ function error3(text) {
3235
+ return `${RED11}${text}${RESET13}`;
3236
+ }
3237
+ function dim3(text) {
3238
+ return `${DIM13}${text}${RESET13}`;
3239
+ }
3240
+ function cyan3(text) {
3241
+ return `${CYAN7}${text}${RESET13}`;
3242
+ }
2228
3243
  function extractPatternName(item) {
2229
3244
  if (typeof item === "string") return item;
2230
3245
  if (typeof item === "object" && item !== null) {
@@ -2267,7 +3282,7 @@ function boxedPrompt(content, title) {
2267
3282
  const maxLen = Math.max(...lines.map((l) => l.length), title.length + 4);
2268
3283
  const width = maxLen + 4;
2269
3284
  const top = `\u250C${"\u2500".repeat(width - 2)}\u2510`;
2270
- const titleLine = `\u2502 ${BOLD4}${title}${RESET9}${" ".repeat(width - title.length - 4)} \u2502`;
3285
+ const titleLine = `\u2502 ${BOLD6}${title}${RESET13}${" ".repeat(width - title.length - 4)} \u2502`;
2271
3286
  const sep2 = `\u251C${"\u2500".repeat(width - 2)}\u2524`;
2272
3287
  const bottom = `\u2514${"\u2500".repeat(width - 2)}\u2518`;
2273
3288
  const body = lines.map((line) => {
@@ -2281,7 +3296,7 @@ ${body}
2281
3296
  ${bottom}`;
2282
3297
  }
2283
3298
  function getAPIClient() {
2284
- return new RegistryAPIClient2({
3299
+ return new RegistryAPIClient3({
2285
3300
  baseUrl: process.env.DECANTR_API_URL || void 0,
2286
3301
  apiKey: process.env.DECANTR_API_KEY || void 0
2287
3302
  });
@@ -2292,17 +3307,17 @@ async function cmdSearch(query, type) {
2292
3307
  const response = await apiClient.search({ q: query, type });
2293
3308
  const results = response.results;
2294
3309
  if (results.length === 0) {
2295
- console.log(dim(`No results for "${query}"`));
3310
+ console.log(dim3(`No results for "${query}"`));
2296
3311
  return;
2297
3312
  }
2298
- console.log(heading(`${results.length} result(s) for "${query}"`));
3313
+ console.log(heading2(`${results.length} result(s) for "${query}"`));
2299
3314
  for (const r of results) {
2300
- console.log(` ${cyan(r.type.padEnd(12))} ${BOLD4}${r.slug}${RESET9}`);
2301
- console.log(` ${dim(r.description || "")}`);
3315
+ console.log(` ${cyan3(r.type.padEnd(12))} ${BOLD6}${r.slug}${RESET13}`);
3316
+ console.log(` ${dim3(r.description || "")}`);
2302
3317
  console.log("");
2303
3318
  }
2304
3319
  } catch {
2305
- console.log(dim(`Search failed. API may be unavailable.`));
3320
+ console.log(dim3(`Search failed. API may be unavailable.`));
2306
3321
  }
2307
3322
  }
2308
3323
  async function cmdSuggest(query, type) {
@@ -2312,40 +3327,40 @@ async function cmdSuggest(query, type) {
2312
3327
  const response = await apiClient.search({ q: query, type: searchType });
2313
3328
  const results = response.results;
2314
3329
  if (results.length === 0) {
2315
- console.log(dim(`No suggestions for "${query}"`));
3330
+ console.log(dim3(`No suggestions for "${query}"`));
2316
3331
  console.log("");
2317
3332
  console.log("Try:");
2318
- console.log(` ${cyan("decantr list patterns")} - see all patterns`);
2319
- console.log(` ${cyan("decantr search <broader-term>")} - broaden your search`);
3333
+ console.log(` ${cyan3("decantr list patterns")} - see all patterns`);
3334
+ console.log(` ${cyan3("decantr search <broader-term>")} - broaden your search`);
2320
3335
  return;
2321
3336
  }
2322
- console.log(heading(`Suggestions for "${query}"`));
3337
+ console.log(heading2(`Suggestions for "${query}"`));
2323
3338
  const queryLower = query.toLowerCase();
2324
3339
  const exact = results.filter((r) => r.slug.toLowerCase().includes(queryLower));
2325
3340
  const related = results.filter((r) => !r.slug.toLowerCase().includes(queryLower));
2326
3341
  if (exact.length > 0) {
2327
- console.log(`${BOLD4}Direct matches:${RESET9}`);
3342
+ console.log(`${BOLD6}Direct matches:${RESET13}`);
2328
3343
  for (const r of exact.slice(0, 3)) {
2329
- console.log(` ${cyan(r.slug)} - ${r.description || ""}`);
3344
+ console.log(` ${cyan3(r.slug)} - ${r.description || ""}`);
2330
3345
  }
2331
3346
  console.log("");
2332
3347
  }
2333
3348
  if (related.length > 0) {
2334
- console.log(`${BOLD4}Related:${RESET9}`);
3349
+ console.log(`${BOLD6}Related:${RESET13}`);
2335
3350
  for (const r of related.slice(0, 5)) {
2336
- console.log(` ${cyan(r.slug)} - ${r.description || ""}`);
3351
+ console.log(` ${cyan3(r.slug)} - ${r.description || ""}`);
2337
3352
  }
2338
3353
  console.log("");
2339
3354
  }
2340
- console.log(dim(`Use "decantr get pattern <id>" for full details`));
3355
+ console.log(dim3(`Use "decantr get pattern <id>" for full details`));
2341
3356
  } catch {
2342
- console.log(dim(`Suggestion search failed. API may be unavailable.`));
3357
+ console.log(dim3(`Suggestion search failed. API may be unavailable.`));
2343
3358
  }
2344
3359
  }
2345
3360
  async function cmdGet(type, id) {
2346
3361
  const validTypes = ["pattern", "archetype", "recipe", "theme", "blueprint", "shell"];
2347
3362
  if (!validTypes.includes(type)) {
2348
- console.error(error(`Invalid type "${type}". Must be one of: ${validTypes.join(", ")}`));
3363
+ console.error(error3(`Invalid type "${type}". Must be one of: ${validTypes.join(", ")}`));
2349
3364
  process.exitCode = 1;
2350
3365
  return;
2351
3366
  }
@@ -2359,29 +3374,29 @@ async function cmdGet(type, id) {
2359
3374
  };
2360
3375
  const apiType = typeMap[type];
2361
3376
  const registryClient = new RegistryClient({
2362
- cacheDir: join19(process.cwd(), ".decantr", "cache")
3377
+ cacheDir: join23(process.cwd(), ".decantr", "cache")
2363
3378
  });
2364
3379
  const result = await registryClient.fetchContentItem(apiType, id);
2365
3380
  if (result) {
2366
3381
  console.log(JSON.stringify(result.data, null, 2));
2367
3382
  return;
2368
3383
  }
2369
- const currentDir = dirname(fileURLToPath(import.meta.url));
3384
+ const currentDir = dirname2(fileURLToPath(import.meta.url));
2370
3385
  const bundledCandidates = [
2371
- join19(currentDir, "bundled", apiType, `${id}.json`),
3386
+ join23(currentDir, "bundled", apiType, `${id}.json`),
2372
3387
  // Running from src/
2373
- join19(currentDir, "..", "src", "bundled", apiType, `${id}.json`),
3388
+ join23(currentDir, "..", "src", "bundled", apiType, `${id}.json`),
2374
3389
  // Running from dist/
2375
- join19(currentDir, "..", "bundled", apiType, `${id}.json`)
3390
+ join23(currentDir, "..", "bundled", apiType, `${id}.json`)
2376
3391
  // Alternative dist layout
2377
3392
  ];
2378
- const bundledPath = bundledCandidates.find((p) => existsSync19(p)) || null;
3393
+ const bundledPath = bundledCandidates.find((p) => existsSync23(p)) || null;
2379
3394
  if (bundledPath) {
2380
- const data = JSON.parse(readFileSync14(bundledPath, "utf-8"));
3395
+ const data = JSON.parse(readFileSync15(bundledPath, "utf-8"));
2381
3396
  console.log(JSON.stringify(data, null, 2));
2382
3397
  return;
2383
3398
  }
2384
- console.error(error(`${type} "${id}" not found.`));
3399
+ console.error(error3(`${type} "${id}" not found.`));
2385
3400
  process.exitCode = 1;
2386
3401
  return;
2387
3402
  }
@@ -2389,13 +3404,13 @@ function buildRegistryContext() {
2389
3404
  const themeRegistry = /* @__PURE__ */ new Map();
2390
3405
  const patternRegistry = /* @__PURE__ */ new Map();
2391
3406
  const projectRoot = process.cwd();
2392
- const cacheDir = join19(projectRoot, ".decantr", "cache");
2393
- const customDir = join19(projectRoot, ".decantr", "custom");
2394
- const cachedThemesDir = join19(cacheDir, "@official", "themes");
3407
+ const cacheDir = join23(projectRoot, ".decantr", "cache");
3408
+ const customDir = join23(projectRoot, ".decantr", "custom");
3409
+ const cachedThemesDir = join23(cacheDir, "@official", "themes");
2395
3410
  try {
2396
- if (existsSync19(cachedThemesDir)) {
3411
+ if (existsSync23(cachedThemesDir)) {
2397
3412
  for (const f of readdirSync6(cachedThemesDir).filter((f2) => f2.endsWith(".json") && f2 !== "index.json")) {
2398
- const data = JSON.parse(readFileSync14(join19(cachedThemesDir, f), "utf-8"));
3413
+ const data = JSON.parse(readFileSync15(join23(cachedThemesDir, f), "utf-8"));
2399
3414
  if (data.id && !themeRegistry.has(data.id)) {
2400
3415
  themeRegistry.set(data.id, { modes: data.modes || ["light", "dark"] });
2401
3416
  }
@@ -2403,11 +3418,11 @@ function buildRegistryContext() {
2403
3418
  }
2404
3419
  } catch {
2405
3420
  }
2406
- const customThemesDir = join19(customDir, "themes");
3421
+ const customThemesDir = join23(customDir, "themes");
2407
3422
  try {
2408
- if (existsSync19(customThemesDir)) {
3423
+ if (existsSync23(customThemesDir)) {
2409
3424
  for (const f of readdirSync6(customThemesDir).filter((f2) => f2.endsWith(".json"))) {
2410
- const data = JSON.parse(readFileSync14(join19(customThemesDir, f), "utf-8"));
3425
+ const data = JSON.parse(readFileSync15(join23(customThemesDir, f), "utf-8"));
2411
3426
  if (data.id) {
2412
3427
  themeRegistry.set(`custom:${data.id}`, { modes: data.modes || ["light", "dark"] });
2413
3428
  }
@@ -2415,11 +3430,11 @@ function buildRegistryContext() {
2415
3430
  }
2416
3431
  } catch {
2417
3432
  }
2418
- const cachedPatternsDir = join19(cacheDir, "@official", "patterns");
3433
+ const cachedPatternsDir = join23(cacheDir, "@official", "patterns");
2419
3434
  try {
2420
- if (existsSync19(cachedPatternsDir)) {
3435
+ if (existsSync23(cachedPatternsDir)) {
2421
3436
  for (const f of readdirSync6(cachedPatternsDir).filter((f2) => f2.endsWith(".json") && f2 !== "index.json")) {
2422
- const data = JSON.parse(readFileSync14(join19(cachedPatternsDir, f), "utf-8"));
3437
+ const data = JSON.parse(readFileSync15(join23(cachedPatternsDir, f), "utf-8"));
2423
3438
  if (data.id && !patternRegistry.has(data.id)) {
2424
3439
  patternRegistry.set(data.id, data);
2425
3440
  }
@@ -2430,12 +3445,12 @@ function buildRegistryContext() {
2430
3445
  return { themeRegistry, patternRegistry };
2431
3446
  }
2432
3447
  async function cmdValidate(path) {
2433
- const essencePath = path || join19(process.cwd(), "decantr.essence.json");
3448
+ const essencePath = path || join23(process.cwd(), "decantr.essence.json");
2434
3449
  let raw;
2435
3450
  try {
2436
- raw = readFileSync14(essencePath, "utf-8");
3451
+ raw = readFileSync15(essencePath, "utf-8");
2437
3452
  } catch {
2438
- console.error(error(`Could not read ${essencePath}`));
3453
+ console.error(error3(`Could not read ${essencePath}`));
2439
3454
  process.exitCode = 1;
2440
3455
  return;
2441
3456
  }
@@ -2443,39 +3458,39 @@ async function cmdValidate(path) {
2443
3458
  try {
2444
3459
  essence = JSON.parse(raw);
2445
3460
  } catch (e) {
2446
- console.error(error(`Invalid JSON: ${e.message}`));
3461
+ console.error(error3(`Invalid JSON: ${e.message}`));
2447
3462
  process.exitCode = 1;
2448
3463
  return;
2449
3464
  }
2450
3465
  const detectedVersion = isV36(essence) ? "v3" : "v2";
2451
- console.log(`${DIM9}Detected essence version: ${detectedVersion}${RESET9}`);
3466
+ console.log(`${DIM13}Detected essence version: ${detectedVersion}${RESET13}`);
2452
3467
  const result = validateEssence2(essence);
2453
3468
  if (result.valid) {
2454
- console.log(success(`Essence is valid (${detectedVersion}).`));
3469
+ console.log(success3(`Essence is valid (${detectedVersion}).`));
2455
3470
  } else {
2456
- console.error(error("Validation failed:"));
3471
+ console.error(error3("Validation failed:"));
2457
3472
  for (const err of result.errors) {
2458
- console.error(` ${RED7}${err}${RESET9}`);
3473
+ console.error(` ${RED11}${err}${RESET13}`);
2459
3474
  }
2460
3475
  process.exitCode = 1;
2461
3476
  }
2462
3477
  if (detectedVersion === "v2" && result.valid) {
2463
- console.log(`${YELLOW6}Tip: Run \`decantr migrate\` to upgrade to v3 format.${RESET9}`);
3478
+ console.log(`${YELLOW9}Tip: Run \`decantr migrate\` to upgrade to v3 format.${RESET13}`);
2464
3479
  }
2465
3480
  try {
2466
3481
  const { themeRegistry, patternRegistry } = buildRegistryContext();
2467
3482
  const violations = evaluateGuard(essence, { themeRegistry, patternRegistry });
2468
3483
  if (violations.length > 0) {
2469
- console.log(heading("Guard violations:"));
3484
+ console.log(heading2("Guard violations:"));
2470
3485
  for (const v of violations) {
2471
3486
  const vr = v;
2472
- console.log(` ${YELLOW6}[${vr.rule}]${RESET9} ${vr.message}`);
3487
+ console.log(` ${YELLOW9}[${vr.rule}]${RESET13} ${vr.message}`);
2473
3488
  if (vr.suggestion) {
2474
- console.log(` ${DIM9}Suggestion: ${vr.suggestion}${RESET9}`);
3489
+ console.log(` ${DIM13}Suggestion: ${vr.suggestion}${RESET13}`);
2475
3490
  }
2476
3491
  }
2477
3492
  } else if (result.valid) {
2478
- console.log(success("No guard violations."));
3493
+ console.log(success3("No guard violations."));
2479
3494
  }
2480
3495
  } catch {
2481
3496
  }
@@ -2483,59 +3498,59 @@ async function cmdValidate(path) {
2483
3498
  async function cmdList(type) {
2484
3499
  const validTypes = ["patterns", "archetypes", "recipes", "themes", "blueprints", "shells"];
2485
3500
  if (!validTypes.includes(type)) {
2486
- console.error(error(`Invalid type "${type}". Must be one of: ${validTypes.join(", ")}`));
3501
+ console.error(error3(`Invalid type "${type}". Must be one of: ${validTypes.join(", ")}`));
2487
3502
  process.exitCode = 1;
2488
3503
  return;
2489
3504
  }
2490
3505
  const registryClient = new RegistryClient({
2491
- cacheDir: join19(process.cwd(), ".decantr", "cache")
3506
+ cacheDir: join23(process.cwd(), ".decantr", "cache")
2492
3507
  });
2493
3508
  const result = await registryClient.fetchContentList(type);
2494
3509
  const items = result.data.items;
2495
3510
  if (items.length === 0) {
2496
- console.log(dim(`No ${type} found.`));
3511
+ console.log(dim3(`No ${type} found.`));
2497
3512
  return;
2498
3513
  }
2499
3514
  if (type === "themes") {
2500
3515
  const customItems = registryClient.listCustomContent("themes");
2501
3516
  const customIds = new Set(customItems.map((c) => c.id));
2502
3517
  const registryItems = items.filter((i) => !customIds.has(i.id));
2503
- console.log(heading(`Registry themes (${registryItems.length}):`));
3518
+ console.log(heading2(`Registry themes (${registryItems.length}):`));
2504
3519
  for (const item of registryItems) {
2505
- console.log(` ${cyan(item.id)} ${dim(item.description || item.name || "")}`);
3520
+ console.log(` ${cyan3(item.id)} ${dim3(item.description || item.name || "")}`);
2506
3521
  }
2507
3522
  if (customItems.length > 0) {
2508
3523
  console.log("");
2509
- console.log(heading(`Custom themes (${customItems.length}):`));
3524
+ console.log(heading2(`Custom themes (${customItems.length}):`));
2510
3525
  for (const item of customItems) {
2511
- console.log(` ${cyan(`custom:${item.id}`)} ${dim(item.description || item.name || "")}`);
3526
+ console.log(` ${cyan3(`custom:${item.id}`)} ${dim3(item.description || item.name || "")}`);
2512
3527
  }
2513
3528
  } else {
2514
3529
  console.log("");
2515
- console.log(dim("Custom themes (0):"));
2516
- console.log(dim(' Run "decantr theme create <name>" to create a custom theme.'));
3530
+ console.log(dim3("Custom themes (0):"));
3531
+ console.log(dim3(' Run "decantr theme create <name>" to create a custom theme.'));
2517
3532
  }
2518
3533
  } else {
2519
- console.log(heading(`${items.length} ${type} found`));
3534
+ console.log(heading2(`${items.length} ${type} found`));
2520
3535
  for (const item of items) {
2521
- console.log(` ${cyan(item.id)} ${dim(item.description || item.name || "")}`);
3536
+ console.log(` ${cyan3(item.id)} ${dim3(item.description || item.name || "")}`);
2522
3537
  }
2523
3538
  }
2524
3539
  }
2525
3540
  async function cmdInit(args) {
2526
3541
  const projectRoot = process.cwd();
2527
- console.log(heading("Decantr Project Setup"));
3542
+ console.log(heading2("Decantr Project Setup"));
2528
3543
  const detected = detectProject(projectRoot);
2529
3544
  if (detected.existingEssence && !args.existing) {
2530
- console.log(`${YELLOW6}Warning: decantr.essence.json already exists.${RESET9}`);
3545
+ console.log(`${YELLOW9}Warning: decantr.essence.json already exists.${RESET13}`);
2531
3546
  const overwrite = await confirm("Overwrite existing configuration?", false);
2532
3547
  if (!overwrite) {
2533
- console.log(dim("Cancelled."));
3548
+ console.log(dim3("Cancelled."));
2534
3549
  return;
2535
3550
  }
2536
3551
  }
2537
3552
  const registryClient = new RegistryClient({
2538
- cacheDir: join19(projectRoot, ".decantr", "cache"),
3553
+ cacheDir: join23(projectRoot, ".decantr", "cache"),
2539
3554
  apiUrl: args.registry,
2540
3555
  offline: args.offline
2541
3556
  });
@@ -2547,30 +3562,30 @@ async function cmdInit(args) {
2547
3562
  } else if (!apiAvailable) {
2548
3563
  if (!args.blueprint) {
2549
3564
  console.log(`
2550
- ${YELLOW6}You're offline. Scaffolding minimal Decantr project.${RESET9}`);
2551
- console.log(dim("Run `decantr sync` or `decantr upgrade` when online to pull full registry content.\n"));
3565
+ ${YELLOW9}You're offline. Scaffolding minimal Decantr project.${RESET13}`);
3566
+ console.log(dim3("Run `decantr sync` or `decantr upgrade` when online to pull full registry content.\n"));
2552
3567
  const result2 = scaffoldMinimal(projectRoot);
2553
- console.log(success("\nProject scaffolded (minimal/offline)!\n"));
3568
+ console.log(success3("\nProject scaffolded (minimal/offline)!\n"));
2554
3569
  console.log(" Files created:");
2555
- console.log(` ${cyan("decantr.essence.json")} Design specification`);
2556
- console.log(` ${cyan("DECANTR.md")} LLM instructions`);
2557
- console.log(` ${cyan(".decantr/")} Project state & custom content dirs`);
3570
+ console.log(` ${cyan3("decantr.essence.json")} Design specification`);
3571
+ console.log(` ${cyan3("DECANTR.md")} LLM instructions`);
3572
+ console.log(` ${cyan3(".decantr/")} Project state & custom content dirs`);
2558
3573
  if (result2.gitignoreUpdated) {
2559
- console.log(` ${dim(".gitignore updated")}`);
3574
+ console.log(` ${dim3(".gitignore updated")}`);
2560
3575
  }
2561
3576
  console.log("");
2562
3577
  console.log(" Next steps:");
2563
- console.log(` 1. Run ${cyan("decantr sync")} when online`);
2564
- console.log(` 2. Use ${cyan("decantr create <type> <name>")} to create custom content`);
3578
+ console.log(` 1. Run ${cyan3("decantr sync")} when online`);
3579
+ console.log(` 2. Use ${cyan3("decantr create <type> <name>")} to create custom content`);
2565
3580
  console.log(` 3. Review DECANTR.md for methodology`);
2566
3581
  return;
2567
3582
  }
2568
3583
  console.log(`
2569
- ${YELLOW6}You're offline. Scaffolding Decantr default.${RESET9}`);
2570
- console.log(dim("Run `decantr upgrade` when online, or visit decantr.ai/registry\n"));
3584
+ ${YELLOW9}You're offline. Scaffolding Decantr default.${RESET13}`);
3585
+ console.log(dim3("Run `decantr upgrade` when online, or visit decantr.ai/registry\n"));
2571
3586
  selectedBlueprint = "default";
2572
3587
  } else {
2573
- console.log(dim("Fetching registry content..."));
3588
+ console.log(dim3("Fetching registry content..."));
2574
3589
  const blueprintsResult2 = await registryClient.fetchBlueprints();
2575
3590
  registrySource = blueprintsResult2.source.type === "api" ? "api" : "cache";
2576
3591
  const { selectedBlueprint: selected } = await runSimplifiedInit(
@@ -2618,8 +3633,8 @@ ${YELLOW6}You're offline. Scaffolding Decantr default.${RESET9}`);
2618
3633
  options.shape = blueprint.theme.shape;
2619
3634
  }
2620
3635
  }
2621
- if (blueprint.personality?.length && (!options.personality || options.personality.length === 0 || options.personality.length === 1 && options.personality[0] === "professional")) {
2622
- options.personality = blueprint.personality;
3636
+ if (blueprint.personality && (!options.personality || options.personality.length === 0 || options.personality.length === 1 && options.personality[0] === "professional")) {
3637
+ options.personality = typeof blueprint.personality === "string" ? [blueprint.personality] : blueprint.personality;
2623
3638
  }
2624
3639
  blueprintRecipeName = blueprint.theme?.recipe;
2625
3640
  if (blueprint.compose && blueprint.compose.length > 0) {
@@ -2726,7 +3741,7 @@ ${YELLOW6}You're offline. Scaffolding Decantr default.${RESET9}`);
2726
3741
  ) : "";
2727
3742
  }
2728
3743
  } else {
2729
- console.log(`${YELLOW6} Warning: Could not fetch blueprint "${options.blueprint}". Using defaults.${RESET9}`);
3744
+ console.log(`${YELLOW9} Warning: Could not fetch blueprint "${options.blueprint}". Using defaults.${RESET13}`);
2730
3745
  }
2731
3746
  } else if (options.archetype) {
2732
3747
  const archetypeResult = await registryClient.fetchArchetype(options.archetype);
@@ -2734,7 +3749,7 @@ ${YELLOW6}You're offline. Scaffolding Decantr default.${RESET9}`);
2734
3749
  const rawArch = archetypeResult.data;
2735
3750
  archetypeData = rawArch.data ?? rawArch;
2736
3751
  } else {
2737
- console.log(`${YELLOW6} Warning: Could not fetch archetype "${options.archetype}". Using defaults.${RESET9}`);
3752
+ console.log(`${YELLOW9} Warning: Could not fetch archetype "${options.archetype}". Using defaults.${RESET13}`);
2738
3753
  }
2739
3754
  }
2740
3755
  let themeData;
@@ -2756,7 +3771,7 @@ ${YELLOW6}You're offline. Scaffolding Decantr default.${RESET9}`);
2756
3771
  recipeData = { decorators: theme.decorators };
2757
3772
  }
2758
3773
  } else {
2759
- console.log(`${YELLOW6} Warning: Could not fetch theme "${options.theme}". Using defaults.${RESET9}`);
3774
+ console.log(`${YELLOW9} Warning: Could not fetch theme "${options.theme}". Using defaults.${RESET13}`);
2760
3775
  }
2761
3776
  const recipeName = blueprintRecipeName || options.theme;
2762
3777
  const recipeResult = await registryClient.fetchRecipe(recipeName);
@@ -2774,7 +3789,7 @@ ${YELLOW6}You're offline. Scaffolding Decantr default.${RESET9}`);
2774
3789
  };
2775
3790
  }
2776
3791
  }
2777
- console.log(heading("Scaffolding project..."));
3792
+ console.log(heading2("Scaffolding project..."));
2778
3793
  const result = await scaffoldProject(
2779
3794
  projectRoot,
2780
3795
  options,
@@ -2791,13 +3806,13 @@ ${YELLOW6}You're offline. Scaffolding Decantr default.${RESET9}`);
2791
3806
  patternSpecs,
2792
3807
  blueprintData
2793
3808
  );
2794
- console.log(success("\nProject scaffolded!\n"));
3809
+ console.log(success3("\nProject scaffolded!\n"));
2795
3810
  console.log(" Files created:");
2796
- console.log(` ${cyan("decantr.essence.json")} Design specification`);
2797
- console.log(` ${cyan("DECANTR.md")} LLM instructions`);
2798
- console.log(` ${cyan(".decantr/")} Project state & cache`);
3811
+ console.log(` ${cyan3("decantr.essence.json")} Design specification`);
3812
+ console.log(` ${cyan3("DECANTR.md")} LLM instructions`);
3813
+ console.log(` ${cyan3(".decantr/")} Project state & cache`);
2799
3814
  if (result.gitignoreUpdated) {
2800
- console.log(` ${dim(".gitignore updated")}`);
3815
+ console.log(` ${dim3(".gitignore updated")}`);
2801
3816
  }
2802
3817
  console.log("");
2803
3818
  console.log(" Next steps:");
@@ -2805,19 +3820,19 @@ ${YELLOW6}You're offline. Scaffolding Decantr default.${RESET9}`);
2805
3820
  console.log(" 2. Explore more at decantr.ai/registry");
2806
3821
  console.log("");
2807
3822
  console.log(" Commands:");
2808
- console.log(` ${cyan("decantr status")} Project health`);
2809
- console.log(` ${cyan("decantr search")} Search registry`);
2810
- console.log(` ${cyan("decantr get")} Fetch content details`);
2811
- console.log(` ${cyan("decantr validate")} Check essence file`);
2812
- console.log(` ${cyan("decantr upgrade")} Update to latest patterns`);
2813
- console.log(` ${cyan("decantr check")} Detect drift issues`);
2814
- console.log(` ${cyan("decantr migrate")} Migrate v2 essence to v3`);
2815
- const essenceContent = readFileSync14(result.essencePath, "utf-8");
3823
+ console.log(` ${cyan3("decantr status")} Project health`);
3824
+ console.log(` ${cyan3("decantr search")} Search registry`);
3825
+ console.log(` ${cyan3("decantr get")} Fetch content details`);
3826
+ console.log(` ${cyan3("decantr validate")} Check essence file`);
3827
+ console.log(` ${cyan3("decantr upgrade")} Update to latest patterns`);
3828
+ console.log(` ${cyan3("decantr check")} Detect drift issues`);
3829
+ console.log(` ${cyan3("decantr migrate")} Migrate v2 essence to v3`);
3830
+ const essenceContent = readFileSync15(result.essencePath, "utf-8");
2816
3831
  const essence = JSON.parse(essenceContent);
2817
3832
  if (essence.version !== "3.1.0") {
2818
3833
  const validation = validateEssence2(essence);
2819
3834
  if (!validation.valid) {
2820
- console.log(error(`
3835
+ console.log(error3(`
2821
3836
  Validation warnings: ${validation.errors.join(", ")}`));
2822
3837
  }
2823
3838
  }
@@ -2848,32 +3863,32 @@ Validation warnings: ${validation.errors.join(", ")}`));
2848
3863
  console.log(boxedPrompt(curatedPrompt, "Copy this prompt for your AI assistant"));
2849
3864
  console.log("");
2850
3865
  if (registrySource === "cache") {
2851
- console.log(dim('Run "decantr sync" when online to get the latest registry content.'));
3866
+ console.log(dim3('Run "decantr sync" when online to get the latest registry content.'));
2852
3867
  }
2853
3868
  }
2854
3869
  async function cmdStatus() {
2855
3870
  const projectRoot = process.cwd();
2856
- const essencePath = join19(projectRoot, "decantr.essence.json");
2857
- const projectJsonPath = join19(projectRoot, ".decantr", "project.json");
2858
- console.log(heading("Decantr Project Status"));
2859
- if (!existsSync19(essencePath)) {
2860
- console.log(`${RED7}No decantr.essence.json found.${RESET9}`);
2861
- console.log(dim('Run "decantr init" to create one.'));
3871
+ const essencePath = join23(projectRoot, "decantr.essence.json");
3872
+ const projectJsonPath = join23(projectRoot, ".decantr", "project.json");
3873
+ console.log(heading2("Decantr Project Status"));
3874
+ if (!existsSync23(essencePath)) {
3875
+ console.log(`${RED11}No decantr.essence.json found.${RESET13}`);
3876
+ console.log(dim3('Run "decantr init" to create one.'));
2862
3877
  return;
2863
3878
  }
2864
3879
  try {
2865
- const essence = JSON.parse(readFileSync14(essencePath, "utf-8"));
3880
+ const essence = JSON.parse(readFileSync15(essencePath, "utf-8"));
2866
3881
  const validation = validateEssence2(essence);
2867
3882
  const essenceVersion = isV36(essence) ? "v3" : "v2";
2868
- console.log(`${BOLD4}Essence:${RESET9}`);
3883
+ console.log(`${BOLD6}Essence:${RESET13}`);
2869
3884
  if (validation.valid) {
2870
- console.log(` ${GREEN9}Valid${RESET9} (${essenceVersion})`);
3885
+ console.log(` ${GREEN13}Valid${RESET13} (${essenceVersion})`);
2871
3886
  } else {
2872
- console.log(` ${RED7}Invalid: ${validation.errors.join(", ")}${RESET9}`);
3887
+ console.log(` ${RED11}Invalid: ${validation.errors.join(", ")}${RESET13}`);
2873
3888
  }
2874
3889
  if (isV36(essence)) {
2875
3890
  const v3 = essence;
2876
- console.log(` ${BOLD4}DNA:${RESET9}`);
3891
+ console.log(` ${BOLD6}DNA:${RESET13}`);
2877
3892
  console.log(` Theme: ${v3.dna.theme.style} (${v3.dna.theme.mode})`);
2878
3893
  console.log(` Spacing: ${v3.dna.spacing.density} density, ${v3.dna.spacing.content_gap} gap`);
2879
3894
  console.log(` Typography: ${v3.dna.typography.scale} scale`);
@@ -2881,11 +3896,11 @@ async function cmdStatus() {
2881
3896
  console.log(` Motion: ${v3.dna.motion.preference} (reduce: ${v3.dna.motion.reduce_motion})`);
2882
3897
  console.log(` Accessibility: WCAG ${v3.dna.accessibility.wcag_level}`);
2883
3898
  console.log(` Personality: ${v3.dna.personality.join(", ")}`);
2884
- console.log(` ${BOLD4}Blueprint:${RESET9}`);
3899
+ console.log(` ${BOLD6}Blueprint:${RESET13}`);
2885
3900
  console.log(` Shell: ${v3.blueprint.shell}`);
2886
3901
  console.log(` Pages: ${v3.blueprint.pages.length}`);
2887
3902
  console.log(` Features: ${v3.blueprint.features.length > 0 ? v3.blueprint.features.join(", ") : "none"}`);
2888
- console.log(` ${BOLD4}Meta:${RESET9}`);
3903
+ console.log(` ${BOLD6}Meta:${RESET13}`);
2889
3904
  console.log(` Archetype: ${v3.meta.archetype}`);
2890
3905
  console.log(` Target: ${v3.meta.target}`);
2891
3906
  console.log(` Guard: ${v3.meta.guard.mode} (DNA: ${v3.meta.guard.dna_enforcement}, Blueprint: ${v3.meta.guard.blueprint_enforcement})`);
@@ -2897,92 +3912,92 @@ async function cmdStatus() {
2897
3912
  console.log(` Theme: ${theme?.style || "unknown"} (${theme?.mode || "unknown"})`);
2898
3913
  console.log(` Guard: ${guard?.mode || "unknown"}`);
2899
3914
  console.log(` Pages: ${(structure || []).length}`);
2900
- console.log(` ${YELLOW6}Tip: Run \`decantr migrate\` to upgrade to v3.${RESET9}`);
3915
+ console.log(` ${YELLOW9}Tip: Run \`decantr migrate\` to upgrade to v3.${RESET13}`);
2901
3916
  }
2902
3917
  } catch (e) {
2903
- console.log(` ${RED7}Error reading essence: ${e.message}${RESET9}`);
3918
+ console.log(` ${RED11}Error reading essence: ${e.message}${RESET13}`);
2904
3919
  }
2905
3920
  console.log("");
2906
- console.log(`${BOLD4}Sync Status:${RESET9}`);
2907
- if (existsSync19(projectJsonPath)) {
3921
+ console.log(`${BOLD6}Sync Status:${RESET13}`);
3922
+ if (existsSync23(projectJsonPath)) {
2908
3923
  try {
2909
- const projectJson = JSON.parse(readFileSync14(projectJsonPath, "utf-8"));
3924
+ const projectJson = JSON.parse(readFileSync15(projectJsonPath, "utf-8"));
2910
3925
  const syncStatus = projectJson.sync?.status || "unknown";
2911
3926
  const lastSync = projectJson.sync?.lastSync || "never";
2912
3927
  const source = projectJson.sync?.registrySource || "unknown";
2913
- const statusColor = syncStatus === "synced" ? GREEN9 : YELLOW6;
2914
- console.log(` Status: ${statusColor}${syncStatus}${RESET9}`);
2915
- console.log(` Last sync: ${dim(lastSync)}`);
2916
- console.log(` Source: ${dim(source)}`);
3928
+ const statusColor = syncStatus === "synced" ? GREEN13 : YELLOW9;
3929
+ console.log(` Status: ${statusColor}${syncStatus}${RESET13}`);
3930
+ console.log(` Last sync: ${dim3(lastSync)}`);
3931
+ console.log(` Source: ${dim3(source)}`);
2917
3932
  } catch {
2918
- console.log(` ${YELLOW6}Could not read project.json${RESET9}`);
3933
+ console.log(` ${YELLOW9}Could not read project.json${RESET13}`);
2919
3934
  }
2920
3935
  } else {
2921
- console.log(` ${YELLOW6}No .decantr/project.json found${RESET9}`);
2922
- console.log(dim(' Run "decantr init" to create project files.'));
3936
+ console.log(` ${YELLOW9}No .decantr/project.json found${RESET13}`);
3937
+ console.log(dim3(' Run "decantr init" to create project files.'));
2923
3938
  }
2924
3939
  }
2925
3940
  async function cmdSync() {
2926
3941
  const projectRoot = process.cwd();
2927
- const cacheDir = join19(projectRoot, ".decantr", "cache");
2928
- console.log(heading("Syncing registry content..."));
3942
+ const cacheDir = join23(projectRoot, ".decantr", "cache");
3943
+ console.log(heading2("Syncing registry content..."));
2929
3944
  const result = await syncRegistry(cacheDir);
2930
3945
  if (result.synced.length > 0) {
2931
- console.log(success("Sync completed successfully."));
3946
+ console.log(success3("Sync completed successfully."));
2932
3947
  console.log(` Synced: ${result.synced.join(", ")}`);
2933
3948
  if (result.failed.length > 0) {
2934
- console.log(` ${YELLOW6}Failed: ${result.failed.join(", ")}${RESET9}`);
3949
+ console.log(` ${YELLOW9}Failed: ${result.failed.join(", ")}${RESET13}`);
2935
3950
  }
2936
3951
  } else {
2937
- console.log(`${YELLOW6}Could not sync: API unavailable${RESET9}`);
3952
+ console.log(`${YELLOW9}Could not sync: API unavailable${RESET13}`);
2938
3953
  if (result.failed.length > 0) {
2939
- console.log(` ${YELLOW6}Failed: ${result.failed.join(", ")}${RESET9}`);
3954
+ console.log(` ${YELLOW9}Failed: ${result.failed.join(", ")}${RESET13}`);
2940
3955
  }
2941
3956
  }
2942
3957
  }
2943
3958
  async function cmdAudit() {
2944
3959
  const projectRoot = process.cwd();
2945
- const essencePath = join19(projectRoot, "decantr.essence.json");
2946
- console.log(heading("Auditing project..."));
2947
- if (!existsSync19(essencePath)) {
2948
- console.log(`${RED7}No decantr.essence.json found.${RESET9}`);
3960
+ const essencePath = join23(projectRoot, "decantr.essence.json");
3961
+ console.log(heading2("Auditing project..."));
3962
+ if (!existsSync23(essencePath)) {
3963
+ console.log(`${RED11}No decantr.essence.json found.${RESET13}`);
2949
3964
  process.exitCode = 1;
2950
3965
  return;
2951
3966
  }
2952
3967
  try {
2953
- const essence = JSON.parse(readFileSync14(essencePath, "utf-8"));
3968
+ const essence = JSON.parse(readFileSync15(essencePath, "utf-8"));
2954
3969
  const validation = validateEssence2(essence);
2955
3970
  if (!validation.valid) {
2956
- console.log(`${RED7}Essence validation failed:${RESET9}`);
3971
+ console.log(`${RED11}Essence validation failed:${RESET13}`);
2957
3972
  for (const err of validation.errors) {
2958
- console.log(` ${RED7}${err}${RESET9}`);
3973
+ console.log(` ${RED11}${err}${RESET13}`);
2959
3974
  }
2960
3975
  process.exitCode = 1;
2961
3976
  return;
2962
3977
  }
2963
- console.log(success("Essence is valid."));
3978
+ console.log(success3("Essence is valid."));
2964
3979
  const { themeRegistry, patternRegistry } = buildRegistryContext();
2965
3980
  const violations = evaluateGuard(essence, { themeRegistry, patternRegistry });
2966
3981
  if (violations.length > 0) {
2967
3982
  console.log("");
2968
- console.log(`${YELLOW6}Guard violations:${RESET9}`);
3983
+ console.log(`${YELLOW9}Guard violations:${RESET13}`);
2969
3984
  for (const v of violations) {
2970
3985
  const vr = v;
2971
- console.log(` ${YELLOW6}[${vr.rule}]${RESET9} ${vr.message}`);
3986
+ console.log(` ${YELLOW9}[${vr.rule}]${RESET13} ${vr.message}`);
2972
3987
  if (vr.suggestion) {
2973
- console.log(` ${DIM9}Suggestion: ${vr.suggestion}${RESET9}`);
3988
+ console.log(` ${DIM13}Suggestion: ${vr.suggestion}${RESET13}`);
2974
3989
  }
2975
3990
  }
2976
3991
  } else {
2977
- console.log(success("No guard violations."));
3992
+ console.log(success3("No guard violations."));
2978
3993
  }
2979
3994
  console.log("");
2980
- console.log(`${BOLD4}Summary:${RESET9}`);
3995
+ console.log(`${BOLD6}Summary:${RESET13}`);
2981
3996
  console.log(` Pages defined: ${essence.structure.length}`);
2982
3997
  console.log(` Guard mode: ${essence.guard.mode}`);
2983
3998
  console.log(` Theme: ${essence.theme.style}`);
2984
3999
  } catch (e) {
2985
- console.log(`${RED7}Error: ${e.message}${RESET9}`);
4000
+ console.log(`${RED11}Error: ${e.message}${RESET13}`);
2986
4001
  process.exitCode = 1;
2987
4002
  }
2988
4003
  }
@@ -2991,17 +4006,17 @@ async function cmdTheme(args) {
2991
4006
  const projectRoot = process.cwd();
2992
4007
  if (!subcommand || subcommand === "help") {
2993
4008
  console.log(`
2994
- ${BOLD4}decantr theme${RESET9} \u2014 Manage custom themes
4009
+ ${BOLD6}decantr theme${RESET13} \u2014 Manage custom themes
2995
4010
 
2996
- ${BOLD4}Commands:${RESET9}
2997
- ${cyan("create")} <name> Create a new custom theme
2998
- ${cyan("create")} <name> --guided Interactive theme creation
2999
- ${cyan("list")} List custom themes
3000
- ${cyan("validate")} <name> Validate a custom theme
3001
- ${cyan("delete")} <name> Delete a custom theme
3002
- ${cyan("import")} <path> Import theme from JSON file
4011
+ ${BOLD6}Commands:${RESET13}
4012
+ ${cyan3("create")} <name> Create a new custom theme
4013
+ ${cyan3("create")} <name> --guided Interactive theme creation
4014
+ ${cyan3("list")} List custom themes
4015
+ ${cyan3("validate")} <name> Validate a custom theme
4016
+ ${cyan3("delete")} <name> Delete a custom theme
4017
+ ${cyan3("import")} <path> Import theme from JSON file
3003
4018
 
3004
- ${BOLD4}Examples:${RESET9}
4019
+ ${BOLD6}Examples:${RESET13}
3005
4020
  decantr theme create mytheme
3006
4021
  decantr theme list
3007
4022
  decantr theme validate mytheme
@@ -3013,19 +4028,19 @@ ${BOLD4}Examples:${RESET9}
3013
4028
  case "create": {
3014
4029
  const name = args[1];
3015
4030
  if (!name) {
3016
- console.error(error("Usage: decantr theme create <name>"));
4031
+ console.error(error3("Usage: decantr theme create <name>"));
3017
4032
  process.exitCode = 1;
3018
4033
  return;
3019
4034
  }
3020
4035
  const displayName = name.charAt(0).toUpperCase() + name.slice(1).replace(/-/g, " ");
3021
4036
  const result = createTheme(projectRoot, name, displayName);
3022
4037
  if (result.success) {
3023
- console.log(success(`Created custom theme "${name}"`));
3024
- console.log(dim(` Path: ${result.path}`));
4038
+ console.log(success3(`Created custom theme "${name}"`));
4039
+ console.log(dim3(` Path: ${result.path}`));
3025
4040
  console.log("");
3026
- console.log(`Use in essence: ${cyan(`"style": "custom:${name}"`)}`);
4041
+ console.log(`Use in essence: ${cyan3(`"style": "custom:${name}"`)}`);
3027
4042
  } else {
3028
- console.error(error(result.error || "Failed to create theme"));
4043
+ console.error(error3(result.error || "Failed to create theme"));
3029
4044
  process.exitCode = 1;
3030
4045
  }
3031
4046
  break;
@@ -3033,12 +4048,12 @@ ${BOLD4}Examples:${RESET9}
3033
4048
  case "list": {
3034
4049
  const themes = listCustomThemes(projectRoot);
3035
4050
  if (themes.length === 0) {
3036
- console.log(dim("No custom themes found."));
3037
- console.log(dim('Run "decantr theme create <name>" to create one.'));
4051
+ console.log(dim3("No custom themes found."));
4052
+ console.log(dim3('Run "decantr theme create <name>" to create one.'));
3038
4053
  } else {
3039
- console.log(heading(`${themes.length} custom theme(s)`));
4054
+ console.log(heading2(`${themes.length} custom theme(s)`));
3040
4055
  for (const theme of themes) {
3041
- console.log(` ${cyan(`custom:${theme.id}`)} ${dim(theme.description || theme.name)}`);
4056
+ console.log(` ${cyan3(`custom:${theme.id}`)} ${dim3(theme.description || theme.name)}`);
3042
4057
  }
3043
4058
  }
3044
4059
  break;
@@ -3046,30 +4061,30 @@ ${BOLD4}Examples:${RESET9}
3046
4061
  case "validate": {
3047
4062
  const name = args[1];
3048
4063
  if (!name) {
3049
- console.error(error("Usage: decantr theme validate <name>"));
4064
+ console.error(error3("Usage: decantr theme validate <name>"));
3050
4065
  process.exitCode = 1;
3051
4066
  return;
3052
4067
  }
3053
- const themePath = join19(projectRoot, ".decantr", "custom", "themes", `${name}.json`);
3054
- if (!existsSync19(themePath)) {
3055
- console.error(error(`Theme "${name}" not found at ${themePath}`));
4068
+ const themePath = join23(projectRoot, ".decantr", "custom", "themes", `${name}.json`);
4069
+ if (!existsSync23(themePath)) {
4070
+ console.error(error3(`Theme "${name}" not found at ${themePath}`));
3056
4071
  process.exitCode = 1;
3057
4072
  return;
3058
4073
  }
3059
4074
  try {
3060
- const theme = JSON.parse(readFileSync14(themePath, "utf-8"));
4075
+ const theme = JSON.parse(readFileSync15(themePath, "utf-8"));
3061
4076
  const result = validateCustomTheme(theme);
3062
4077
  if (result.valid) {
3063
- console.log(success(`Custom theme "${name}" is valid`));
4078
+ console.log(success3(`Custom theme "${name}" is valid`));
3064
4079
  } else {
3065
- console.error(error("Validation failed:"));
4080
+ console.error(error3("Validation failed:"));
3066
4081
  for (const err of result.errors) {
3067
- console.error(` ${RED7}${err}${RESET9}`);
4082
+ console.error(` ${RED11}${err}${RESET13}`);
3068
4083
  }
3069
4084
  process.exitCode = 1;
3070
4085
  }
3071
4086
  } catch (e) {
3072
- console.error(error(`Invalid JSON: ${e.message}`));
4087
+ console.error(error3(`Invalid JSON: ${e.message}`));
3073
4088
  process.exitCode = 1;
3074
4089
  }
3075
4090
  break;
@@ -3077,15 +4092,15 @@ ${BOLD4}Examples:${RESET9}
3077
4092
  case "delete": {
3078
4093
  const name = args[1];
3079
4094
  if (!name) {
3080
- console.error(error("Usage: decantr theme delete <name>"));
4095
+ console.error(error3("Usage: decantr theme delete <name>"));
3081
4096
  process.exitCode = 1;
3082
4097
  return;
3083
4098
  }
3084
4099
  const result = deleteTheme(projectRoot, name);
3085
4100
  if (result.success) {
3086
- console.log(success(`Deleted custom theme "${name}"`));
4101
+ console.log(success3(`Deleted custom theme "${name}"`));
3087
4102
  } else {
3088
- console.error(error(result.error || "Failed to delete theme"));
4103
+ console.error(error3(result.error || "Failed to delete theme"));
3089
4104
  process.exitCode = 1;
3090
4105
  }
3091
4106
  break;
@@ -3093,18 +4108,18 @@ ${BOLD4}Examples:${RESET9}
3093
4108
  case "import": {
3094
4109
  const sourcePath = args[1];
3095
4110
  if (!sourcePath) {
3096
- console.error(error("Usage: decantr theme import <path>"));
4111
+ console.error(error3("Usage: decantr theme import <path>"));
3097
4112
  process.exitCode = 1;
3098
4113
  return;
3099
4114
  }
3100
4115
  const result = importTheme(projectRoot, sourcePath);
3101
4116
  if (result.success) {
3102
- console.log(success("Theme imported successfully"));
3103
- console.log(dim(` Path: ${result.path}`));
4117
+ console.log(success3("Theme imported successfully"));
4118
+ console.log(dim3(` Path: ${result.path}`));
3104
4119
  } else {
3105
- console.error(error("Import failed:"));
4120
+ console.error(error3("Import failed:"));
3106
4121
  for (const err of result.errors || []) {
3107
- console.error(` ${RED7}${err}${RESET9}`);
4122
+ console.error(` ${RED11}${err}${RESET13}`);
3108
4123
  }
3109
4124
  process.exitCode = 1;
3110
4125
  }
@@ -3113,7 +4128,7 @@ ${BOLD4}Examples:${RESET9}
3113
4128
  case "switch": {
3114
4129
  const name = args[1];
3115
4130
  if (!name) {
3116
- console.error(error("Usage: decantr theme switch <themeName> [--recipe <r>] [--shape <s>] [--mode <m>]"));
4131
+ console.error(error3("Usage: decantr theme switch <themeName> [--recipe <r>] [--shape <s>] [--mode <m>]"));
3117
4132
  process.exitCode = 1;
3118
4133
  return;
3119
4134
  }
@@ -3121,15 +4136,17 @@ ${BOLD4}Examples:${RESET9}
3121
4136
  break;
3122
4137
  }
3123
4138
  default:
3124
- console.error(error(`Unknown theme command: ${subcommand}`));
4139
+ console.error(error3(`Unknown theme command: ${subcommand}`));
3125
4140
  process.exitCode = 1;
3126
4141
  }
3127
4142
  }
3128
4143
  function cmdHelp() {
3129
4144
  console.log(`
3130
- ${BOLD4}decantr${RESET9} \u2014 Design intelligence for AI-generated UI
4145
+ ${BOLD6}decantr${RESET13} \u2014 Design intelligence for AI-generated UI
3131
4146
 
3132
- ${BOLD4}Usage:${RESET9}
4147
+ ${BOLD6}Usage:${RESET13}
4148
+ decantr new <name> [--blueprint=X] [--archetype=X] [--theme=X]
4149
+ decantr magic <prompt> [--dry-run]
3133
4150
  decantr init [options]
3134
4151
  decantr status
3135
4152
  decantr sync
@@ -3150,7 +4167,7 @@ ${BOLD4}Usage:${RESET9}
3150
4167
  decantr logout
3151
4168
  decantr help
3152
4169
 
3153
- ${BOLD4}Init Options:${RESET9}
4170
+ ${BOLD6}Init Options:${RESET13}
3154
4171
  --blueprint, -b Blueprint ID
3155
4172
  --theme Theme ID
3156
4173
  --mode Color mode: dark | light | auto
@@ -3164,29 +4181,35 @@ ${BOLD4}Init Options:${RESET9}
3164
4181
  --yes, -y Accept defaults, skip confirmations
3165
4182
  --registry Custom registry URL
3166
4183
 
3167
- ${BOLD4}Commands:${RESET9}
3168
- ${cyan("init")} Initialize a new Decantr project (v3 essence by default)
3169
- ${cyan("status")} Show project status, DNA axioms, and blueprint info
3170
- ${cyan("sync")} Sync registry content from API
3171
- ${cyan("audit")} Validate essence and check for drift
3172
- ${cyan("migrate")} Migrate v2 essence to v3 format (with .v2.backup.json backup)
3173
- ${cyan("check")} Detect drift issues (validate + guard rules)
3174
- ${cyan("sync-drift")} Review and resolve drift log entries
3175
- ${cyan("search")} Search the registry
3176
- ${cyan("suggest")} Suggest patterns or alternatives for a query
3177
- ${cyan("get")} Get full details of a registry item
3178
- ${cyan("list")} List items by type
3179
- ${cyan("validate")} Validate essence file (v2 and v3)
3180
- ${cyan("theme")} Manage custom themes (create, list, validate, delete, import)
3181
- ${cyan("create")} Create a custom content item (pattern, recipe, theme, etc.)
3182
- ${cyan("publish")} Publish a custom content item to the community registry
3183
- ${cyan("login")} Authenticate with the Decantr registry
3184
- ${cyan("logout")} Remove stored credentials
3185
- ${cyan("analyze")} Scan existing project and produce analysis report
3186
- ${cyan("upgrade")} Check for content updates from registry
3187
- ${cyan("help")} Show this help
4184
+ ${BOLD6}Commands:${RESET13}
4185
+ ${cyan3("new")} Create a new project with Vite + React + Decantr
4186
+ ${cyan3("magic")} One-liner scaffold from a natural language prompt
4187
+ ${cyan3("init")} Initialize Decantr in an existing project (v3 essence by default)
4188
+ ${cyan3("status")} Show project status, DNA axioms, and blueprint info
4189
+ ${cyan3("sync")} Sync registry content from API
4190
+ ${cyan3("audit")} Validate essence and check for drift
4191
+ ${cyan3("migrate")} Migrate v2 essence to v3 format (with .v2.backup.json backup)
4192
+ ${cyan3("check")} Detect drift issues (validate + guard rules) [--telemetry]
4193
+ ${cyan3("sync-drift")} Review and resolve drift log entries
4194
+ ${cyan3("search")} Search the registry
4195
+ ${cyan3("suggest")} Suggest patterns or alternatives for a query
4196
+ ${cyan3("get")} Get full details of a registry item
4197
+ ${cyan3("list")} List items by type
4198
+ ${cyan3("validate")} Validate essence file (v2 and v3)
4199
+ ${cyan3("theme")} Manage custom themes (create, list, validate, delete, import)
4200
+ ${cyan3("create")} Create a custom content item (pattern, recipe, theme, etc.)
4201
+ ${cyan3("publish")} Publish a custom content item to the community registry
4202
+ ${cyan3("login")} Authenticate with the Decantr registry
4203
+ ${cyan3("logout")} Remove stored credentials
4204
+ ${cyan3("analyze")} Scan existing project and produce analysis report
4205
+ ${cyan3("export")} Export design tokens to framework format (shadcn, tailwind, css-vars)
4206
+ ${cyan3("registry")} Registry management (mirror)
4207
+ ${cyan3("upgrade")} Check for content updates from registry
4208
+ ${cyan3("help")} Show this help
3188
4209
 
3189
- ${BOLD4}Examples:${RESET9}
4210
+ ${BOLD6}Examples:${RESET13}
4211
+ decantr new my-app --blueprint=carbon-ai-portal
4212
+ decantr magic "AI chatbot with dark cyber theme \u2014 bold and futuristic"
3190
4213
  decantr init
3191
4214
  decantr init --blueprint=saas-dashboard --theme=luminarum --yes
3192
4215
  decantr status
@@ -3207,6 +4230,38 @@ async function main() {
3207
4230
  return;
3208
4231
  }
3209
4232
  switch (command) {
4233
+ case "new": {
4234
+ const newName = args[1];
4235
+ if (!newName) {
4236
+ console.error(error3("Usage: decantr new <project-name> [--blueprint=X] [--archetype=X] [--theme=X]"));
4237
+ process.exitCode = 1;
4238
+ break;
4239
+ }
4240
+ const newOpts = {};
4241
+ for (let i = 2; i < args.length; i++) {
4242
+ const arg = args[i];
4243
+ if (arg === "--offline") {
4244
+ newOpts.offline = true;
4245
+ } else if (arg.startsWith("--")) {
4246
+ const [key, value] = arg.slice(2).split("=");
4247
+ if (value) {
4248
+ newOpts[key] = value;
4249
+ } else if (args[i + 1] && !args[i + 1].startsWith("-")) {
4250
+ newOpts[key] = args[++i];
4251
+ }
4252
+ }
4253
+ }
4254
+ await cmdNewProject(newName, {
4255
+ blueprint: newOpts.blueprint,
4256
+ archetype: newOpts.archetype,
4257
+ theme: newOpts.theme,
4258
+ mode: newOpts.mode,
4259
+ shape: newOpts.shape,
4260
+ offline: newOpts.offline === true,
4261
+ registry: newOpts.registry
4262
+ });
4263
+ break;
4264
+ }
3210
4265
  case "init": {
3211
4266
  const initArgs = {};
3212
4267
  for (let i = 1; i < args.length; i++) {
@@ -3242,7 +4297,7 @@ async function main() {
3242
4297
  break;
3243
4298
  }
3244
4299
  case "upgrade": {
3245
- const { cmdUpgrade } = await import("./upgrade-I2RUTNAT.js");
4300
+ const { cmdUpgrade } = await import("./upgrade-25IURU4X.js");
3246
4301
  const applyFlag = args.includes("--apply");
3247
4302
  await cmdUpgrade(process.cwd(), { apply: applyFlag });
3248
4303
  break;
@@ -3250,10 +4305,11 @@ async function main() {
3250
4305
  case "check":
3251
4306
  case "heal": {
3252
4307
  if (command === "heal") {
3253
- console.log(`${YELLOW6}Note: \`decantr heal\` is deprecated. Use \`decantr check\` instead.${RESET9}`);
4308
+ console.log(`${YELLOW9}Note: \`decantr heal\` is deprecated. Use \`decantr check\` instead.${RESET13}`);
3254
4309
  }
3255
- const { cmdHeal } = await import("./heal-ZG5VJZ5J.js");
3256
- await cmdHeal(process.cwd());
4310
+ const { cmdHeal } = await import("./heal-54MKDDSQ.js");
4311
+ const telemetryFlag = args.includes("--telemetry");
4312
+ await cmdHeal(process.cwd(), { telemetry: telemetryFlag });
3257
4313
  break;
3258
4314
  }
3259
4315
  case "migrate": {
@@ -3272,9 +4328,9 @@ async function main() {
3272
4328
  resolveIndex: resolveNum
3273
4329
  });
3274
4330
  if (result.success) {
3275
- console.log(success(clearFlag ? "Drift log cleared." : "Entries resolved."));
4331
+ console.log(success3(clearFlag ? "Drift log cleared." : "Entries resolved."));
3276
4332
  } else {
3277
- console.error(error(result.error || "Failed"));
4333
+ console.error(error3(result.error || "Failed"));
3278
4334
  process.exitCode = 1;
3279
4335
  }
3280
4336
  } else {
@@ -3289,7 +4345,7 @@ async function main() {
3289
4345
  case "search": {
3290
4346
  const query = args[1];
3291
4347
  if (!query) {
3292
- console.error(error("Usage: decantr search <query> [--type <type>]"));
4348
+ console.error(error3("Usage: decantr search <query> [--type <type>]"));
3293
4349
  process.exitCode = 1;
3294
4350
  return;
3295
4351
  }
@@ -3301,7 +4357,7 @@ async function main() {
3301
4357
  case "suggest": {
3302
4358
  const query = args[1];
3303
4359
  if (!query) {
3304
- console.error(error("Usage: decantr suggest <query> [--type <type>]"));
4360
+ console.error(error3("Usage: decantr suggest <query> [--type <type>]"));
3305
4361
  process.exitCode = 1;
3306
4362
  return;
3307
4363
  }
@@ -3314,7 +4370,7 @@ async function main() {
3314
4370
  const type = args[1];
3315
4371
  const id = args[2];
3316
4372
  if (!type || !id) {
3317
- console.error(error("Usage: decantr get <type> <id>"));
4373
+ console.error(error3("Usage: decantr get <type> <id>"));
3318
4374
  process.exitCode = 1;
3319
4375
  return;
3320
4376
  }
@@ -3324,7 +4380,7 @@ async function main() {
3324
4380
  case "list": {
3325
4381
  const type = args[1];
3326
4382
  if (!type) {
3327
- console.error(error("Usage: decantr list <type>"));
4383
+ console.error(error3("Usage: decantr list <type>"));
3328
4384
  process.exitCode = 1;
3329
4385
  return;
3330
4386
  }
@@ -3344,37 +4400,37 @@ async function main() {
3344
4400
  if (apiKeyArg && apiKeyArg.startsWith("--api-key=")) {
3345
4401
  const key = apiKeyArg.split("=")[1];
3346
4402
  saveCredentials({ access_token: key, api_key: key });
3347
- console.log(success("API key saved."));
4403
+ console.log(success3("API key saved."));
3348
4404
  } else {
3349
- console.log(heading("Decantr Login"));
4405
+ console.log(heading2("Decantr Login"));
3350
4406
  console.log(" To authenticate, get your API key from the Decantr dashboard:");
3351
4407
  console.log("");
3352
- console.log(` ${cyan("https://decantr.ai/dashboard/api-keys")}`);
4408
+ console.log(` ${cyan3("https://decantr.ai/dashboard/api-keys")}`);
3353
4409
  console.log("");
3354
4410
  console.log(" Then run:");
3355
- console.log(` ${cyan("decantr login --api-key=<your-key>")}`);
4411
+ console.log(` ${cyan3("decantr login --api-key=<your-key>")}`);
3356
4412
  console.log("");
3357
4413
  console.log(" Or set the environment variable:");
3358
- console.log(` ${cyan("export DECANTR_API_KEY=<your-key>")}`);
4414
+ console.log(` ${cyan3("export DECANTR_API_KEY=<your-key>")}`);
3359
4415
  const existingCreds = getCredentials();
3360
4416
  if (existingCreds) {
3361
4417
  console.log("");
3362
- console.log(dim("You are currently authenticated."));
4418
+ console.log(dim3("You are currently authenticated."));
3363
4419
  }
3364
4420
  }
3365
4421
  break;
3366
4422
  }
3367
4423
  case "logout": {
3368
4424
  clearCredentials();
3369
- console.log(success("Logged out. Credentials removed."));
4425
+ console.log(success3("Logged out. Credentials removed."));
3370
4426
  break;
3371
4427
  }
3372
4428
  case "create": {
3373
4429
  const type = args[1];
3374
4430
  const name = args[2];
3375
4431
  if (!type || !name) {
3376
- console.error(error("Usage: decantr create <type> <name>"));
3377
- console.error(dim("Types: pattern, recipe, theme, blueprint, archetype, shell"));
4432
+ console.error(error3("Usage: decantr create <type> <name>"));
4433
+ console.error(dim3("Types: pattern, recipe, theme, blueprint, archetype, shell"));
3378
4434
  process.exitCode = 1;
3379
4435
  break;
3380
4436
  }
@@ -3385,8 +4441,8 @@ async function main() {
3385
4441
  const type = args[1];
3386
4442
  const name = args[2];
3387
4443
  if (!type || !name) {
3388
- console.error(error("Usage: decantr publish <type> <name>"));
3389
- console.error(dim("Types: pattern, recipe, theme, blueprint, archetype, shell"));
4444
+ console.error(error3("Usage: decantr publish <type> <name>"));
4445
+ console.error(dim3("Types: pattern, recipe, theme, blueprint, archetype, shell"));
3390
4446
  process.exitCode = 1;
3391
4447
  break;
3392
4448
  }
@@ -3394,13 +4450,26 @@ async function main() {
3394
4450
  break;
3395
4451
  }
3396
4452
  case "refresh": {
3397
- await cmdRefresh(process.cwd());
4453
+ const refreshOffline = args.includes("--offline");
4454
+ await cmdRefresh(process.cwd(), { offline: refreshOffline });
4455
+ break;
4456
+ }
4457
+ case "registry": {
4458
+ const subcommand = args[1];
4459
+ if (subcommand === "mirror") {
4460
+ const typeIdx = args.indexOf("--type");
4461
+ const mirrorType = typeIdx !== -1 ? args[typeIdx + 1] : void 0;
4462
+ await cmdRegistryMirror(process.cwd(), { type: mirrorType });
4463
+ } else {
4464
+ console.error(`${RED11}Usage: decantr registry mirror [--type <type>]${RESET13}`);
4465
+ process.exitCode = 1;
4466
+ }
3398
4467
  break;
3399
4468
  }
3400
4469
  case "add": {
3401
4470
  const subcommand = args[1];
3402
4471
  if (!subcommand) {
3403
- console.error(error("Usage: decantr add <section|page|feature> <target>"));
4472
+ console.error(error3("Usage: decantr add <section|page|feature> <target>"));
3404
4473
  process.exitCode = 1;
3405
4474
  break;
3406
4475
  }
@@ -3408,7 +4477,7 @@ async function main() {
3408
4477
  case "section": {
3409
4478
  const id = args[2];
3410
4479
  if (!id) {
3411
- console.error(error("Usage: decantr add section <archetypeId>"));
4480
+ console.error(error3("Usage: decantr add section <archetypeId>"));
3412
4481
  process.exitCode = 1;
3413
4482
  break;
3414
4483
  }
@@ -3418,7 +4487,7 @@ async function main() {
3418
4487
  case "page": {
3419
4488
  const pagePath = args[2];
3420
4489
  if (!pagePath) {
3421
- console.error(error("Usage: decantr add page <section>/<page>"));
4490
+ console.error(error3("Usage: decantr add page <section>/<page>"));
3422
4491
  process.exitCode = 1;
3423
4492
  break;
3424
4493
  }
@@ -3428,7 +4497,7 @@ async function main() {
3428
4497
  case "feature": {
3429
4498
  const feature = args[2];
3430
4499
  if (!feature) {
3431
- console.error(error("Usage: decantr add feature <feature> [--section <id>]"));
4500
+ console.error(error3("Usage: decantr add feature <feature> [--section <id>]"));
3432
4501
  process.exitCode = 1;
3433
4502
  break;
3434
4503
  }
@@ -3436,7 +4505,7 @@ async function main() {
3436
4505
  break;
3437
4506
  }
3438
4507
  default:
3439
- console.error(error(`Unknown add subcommand: ${subcommand}. Use section, page, or feature.`));
4508
+ console.error(error3(`Unknown add subcommand: ${subcommand}. Use section, page, or feature.`));
3440
4509
  process.exitCode = 1;
3441
4510
  }
3442
4511
  break;
@@ -3444,7 +4513,7 @@ async function main() {
3444
4513
  case "remove": {
3445
4514
  const subcommand = args[1];
3446
4515
  if (!subcommand) {
3447
- console.error(error("Usage: decantr remove <section|page|feature> <target>"));
4516
+ console.error(error3("Usage: decantr remove <section|page|feature> <target>"));
3448
4517
  process.exitCode = 1;
3449
4518
  break;
3450
4519
  }
@@ -3452,7 +4521,7 @@ async function main() {
3452
4521
  case "section": {
3453
4522
  const id = args[2];
3454
4523
  if (!id) {
3455
- console.error(error("Usage: decantr remove section <sectionId>"));
4524
+ console.error(error3("Usage: decantr remove section <sectionId>"));
3456
4525
  process.exitCode = 1;
3457
4526
  break;
3458
4527
  }
@@ -3462,7 +4531,7 @@ async function main() {
3462
4531
  case "page": {
3463
4532
  const pagePath = args[2];
3464
4533
  if (!pagePath) {
3465
- console.error(error("Usage: decantr remove page <section>/<page>"));
4534
+ console.error(error3("Usage: decantr remove page <section>/<page>"));
3466
4535
  process.exitCode = 1;
3467
4536
  break;
3468
4537
  }
@@ -3472,7 +4541,7 @@ async function main() {
3472
4541
  case "feature": {
3473
4542
  const feature = args[2];
3474
4543
  if (!feature) {
3475
- console.error(error("Usage: decantr remove feature <feature> [--section <id>]"));
4544
+ console.error(error3("Usage: decantr remove feature <feature> [--section <id>]"));
3476
4545
  process.exitCode = 1;
3477
4546
  break;
3478
4547
  }
@@ -3480,7 +4549,7 @@ async function main() {
3480
4549
  break;
3481
4550
  }
3482
4551
  default:
3483
- console.error(error(`Unknown remove subcommand: ${subcommand}. Use section, page, or feature.`));
4552
+ console.error(error3(`Unknown remove subcommand: ${subcommand}. Use section, page, or feature.`));
3484
4553
  process.exitCode = 1;
3485
4554
  }
3486
4555
  break;
@@ -3489,14 +4558,69 @@ async function main() {
3489
4558
  cmdAnalyze(process.cwd());
3490
4559
  break;
3491
4560
  }
4561
+ case "magic": {
4562
+ const magicFlags = {};
4563
+ const promptParts = [];
4564
+ for (let i = 1; i < args.length; i++) {
4565
+ if (args[i] === "--dry-run") {
4566
+ magicFlags.dryRun = true;
4567
+ } else if (args[i] === "--offline") {
4568
+ magicFlags.offline = true;
4569
+ } else if (args[i].startsWith("--registry=")) {
4570
+ magicFlags.registry = args[i].split("=")[1];
4571
+ } else if (args[i].startsWith("--registry") && args[i + 1]) {
4572
+ magicFlags.registry = args[++i];
4573
+ } else {
4574
+ promptParts.push(args[i]);
4575
+ }
4576
+ }
4577
+ const magicPrompt = promptParts.join(" ").trim();
4578
+ if (!magicPrompt) {
4579
+ console.error(error3("Usage: decantr magic <prompt> [--dry-run] [--offline]"));
4580
+ console.error("");
4581
+ console.error(" Example:");
4582
+ console.error(` ${CYAN7}decantr magic "AI agent dashboard \u2014 dark, neon, confident"${RESET13}`);
4583
+ process.exitCode = 1;
4584
+ break;
4585
+ }
4586
+ await cmdMagic(magicPrompt, process.cwd(), {
4587
+ dryRun: magicFlags.dryRun,
4588
+ offline: magicFlags.offline,
4589
+ registry: magicFlags.registry
4590
+ });
4591
+ break;
4592
+ }
4593
+ case "export": {
4594
+ let exportTarget;
4595
+ let exportOutput;
4596
+ for (let i = 1; i < args.length; i++) {
4597
+ if (args[i] === "--to" && args[i + 1]) {
4598
+ exportTarget = args[++i];
4599
+ } else if (args[i].startsWith("--to=")) {
4600
+ exportTarget = args[i].split("=")[1];
4601
+ } else if (args[i] === "--output" && args[i + 1]) {
4602
+ exportOutput = args[++i];
4603
+ } else if (args[i].startsWith("--output=")) {
4604
+ exportOutput = args[i].split("=")[1];
4605
+ }
4606
+ }
4607
+ const validTargets = ["shadcn", "tailwind", "css-vars"];
4608
+ if (!exportTarget || !validTargets.includes(exportTarget)) {
4609
+ console.error(error3(`Usage: decantr export --to <${validTargets.join("|")}>`));
4610
+ process.exitCode = 1;
4611
+ break;
4612
+ }
4613
+ await cmdExport(exportTarget, process.cwd(), { output: exportOutput });
4614
+ break;
4615
+ }
3492
4616
  default:
3493
- console.error(error(`Unknown command: ${command}`));
4617
+ console.error(error3(`Unknown command: ${command}`));
3494
4618
  cmdHelp();
3495
4619
  process.exitCode = 1;
3496
4620
  }
3497
4621
  }
3498
4622
  main().catch((e) => {
3499
- console.error(error(e.message));
4623
+ console.error(error3(e.message));
3500
4624
  if (e.stack) console.error(e.stack);
3501
4625
  process.exitCode = 1;
3502
4626
  });