@decantr/cli 1.5.3 → 1.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin.js CHANGED
@@ -1,3 +1,3 @@
1
1
  #!/usr/bin/env node
2
- import "./chunk-QZVA3PFR.js";
3
- import "./chunk-B5OX2EXL.js";
2
+ import "./chunk-D3W3MYKT.js";
3
+ import "./chunk-T7CQSJGV.js";
@@ -9,7 +9,7 @@ import {
9
9
  scaffoldMinimal,
10
10
  scaffoldProject,
11
11
  syncRegistry
12
- } from "./chunk-B5OX2EXL.js";
12
+ } from "./chunk-T7CQSJGV.js";
13
13
 
14
14
  // src/index.ts
15
15
  import { readFileSync as readFileSync15, existsSync as existsSync23, readdirSync as readdirSync6 } from "fs";
@@ -284,7 +284,7 @@ async function runInteractivePrompts(detected, archetypes, blueprints, themes) {
284
284
  "Guard enforcement level",
285
285
  [
286
286
  { value: "creative", label: "creative", description: "Advisory only (new projects)" },
287
- { value: "guided", label: "guided", description: "Style, structure, recipe enforced" },
287
+ { value: "guided", label: "guided", description: "Style, structure, density enforced" },
288
288
  { value: "strict", label: "strict", description: "All 5 rules enforced exactly" }
289
289
  ],
290
290
  detected.existingEssence ? 1 : 2
@@ -649,7 +649,6 @@ import { join as join4 } from "path";
649
649
  import { RegistryAPIClient } from "@decantr/registry";
650
650
  var PLURAL_TO_SINGULAR = {
651
651
  patterns: "pattern",
652
- recipes: "recipe",
653
652
  themes: "theme",
654
653
  blueprints: "blueprint",
655
654
  archetypes: "archetype",
@@ -657,7 +656,6 @@ var PLURAL_TO_SINGULAR = {
657
656
  };
658
657
  var SINGULAR_TO_PLURAL = {
659
658
  pattern: "patterns",
660
- recipe: "recipes",
661
659
  theme: "themes",
662
660
  blueprint: "blueprints",
663
661
  archetype: "archetypes",
@@ -710,10 +708,9 @@ async function cmdPublish(type, name, projectRoot = process.cwd()) {
710
708
  // src/commands/create.ts
711
709
  import { existsSync as existsSync5, mkdirSync as mkdirSync3, writeFileSync as writeFileSync3 } from "fs";
712
710
  import { join as join5 } from "path";
713
- var CONTENT_TYPES = ["pattern", "recipe", "theme", "blueprint", "archetype", "shell"];
711
+ var CONTENT_TYPES = ["pattern", "theme", "blueprint", "archetype", "shell"];
714
712
  var PLURAL = {
715
713
  pattern: "patterns",
716
- recipe: "recipes",
717
714
  theme: "themes",
718
715
  blueprint: "blueprints",
719
716
  archetype: "archetypes",
@@ -730,8 +727,6 @@ function getSkeleton(type, id, name) {
730
727
  switch (type) {
731
728
  case "pattern":
732
729
  return { ...base, components: [], presets: {}, layout: {} };
733
- case "recipe":
734
- return { ...base, shell: {}, spatial: {}, effects: {} };
735
730
  case "theme":
736
731
  return { ...base, seed: { primary: "#6500C6", secondary: "#0AF3EB", accent: "#F58882", background: "#0D0D1A" }, modes: ["dark"], shapes: ["rounded"] };
737
732
  case "blueprint":
@@ -1339,7 +1334,7 @@ var DIM7 = "\x1B[2m";
1339
1334
  var RESET7 = "\x1B[0m";
1340
1335
  async function cmdThemeSwitch(themeName, args, projectRoot = process.cwd()) {
1341
1336
  if (!themeName) {
1342
- console.error(`${RED6}Usage: decantr theme switch <themeName> [--recipe <r>] [--shape <s>] [--mode <m>]${RESET7}`);
1337
+ console.error(`${RED6}Usage: decantr theme switch <themeName> [--shape <s>] [--mode <m>]${RESET7}`);
1343
1338
  process.exitCode = 1;
1344
1339
  return;
1345
1340
  }
@@ -1363,16 +1358,11 @@ async function cmdThemeSwitch(themeName, args, projectRoot = process.cwd()) {
1363
1358
  return;
1364
1359
  }
1365
1360
  const essence = migrateV30ToV313(parsed);
1366
- let recipe;
1367
1361
  let shape;
1368
1362
  let mode;
1369
1363
  for (let i = 0; i < args.length; i++) {
1370
1364
  const arg = args[i];
1371
- if (arg.startsWith("--recipe=")) {
1372
- recipe = arg.split("=")[1];
1373
- } else if (arg === "--recipe" && args[i + 1] && !args[i + 1].startsWith("-")) {
1374
- recipe = args[++i];
1375
- } else if (arg.startsWith("--shape=")) {
1365
+ if (arg.startsWith("--shape=")) {
1376
1366
  shape = arg.split("=")[1];
1377
1367
  } else if (arg === "--shape" && args[i + 1] && !args[i + 1].startsWith("-")) {
1378
1368
  shape = args[++i];
@@ -1382,13 +1372,10 @@ async function cmdThemeSwitch(themeName, args, projectRoot = process.cwd()) {
1382
1372
  mode = args[++i];
1383
1373
  }
1384
1374
  }
1385
- const oldStyle = essence.dna.theme.style;
1386
- essence.dna.theme.style = themeName;
1387
- if (recipe) {
1388
- essence.dna.theme.recipe = recipe;
1389
- } else {
1390
- essence.dna.theme.recipe = themeName;
1391
- }
1375
+ const oldThemeId = essence.dna.theme.id || essence.dna.theme.style;
1376
+ essence.dna.theme.id = themeName;
1377
+ delete essence.dna.theme.style;
1378
+ delete essence.dna.theme.recipe;
1392
1379
  if (shape) {
1393
1380
  essence.dna.theme.shape = shape;
1394
1381
  }
@@ -1398,29 +1385,27 @@ async function cmdThemeSwitch(themeName, args, projectRoot = process.cwd()) {
1398
1385
  const registryClient = new RegistryClient({
1399
1386
  cacheDir: join11(projectRoot, ".decantr", "cache")
1400
1387
  });
1401
- const recipeName = essence.dna.theme.recipe;
1402
1388
  try {
1403
- const recipeResult = await registryClient.fetchRecipe(recipeName);
1404
- if (recipeResult?.data) {
1405
- const raw = recipeResult.data;
1389
+ const themeResult = await registryClient.fetchTheme(themeName);
1390
+ if (themeResult?.data) {
1391
+ const raw = themeResult.data;
1406
1392
  const inner = raw.data ?? raw;
1407
- if (inner.radius_hints) {
1393
+ if (inner.radius) {
1408
1394
  essence.dna.radius = {
1409
1395
  ...essence.dna.radius,
1410
- philosophy: inner.radius_hints.philosophy || essence.dna.radius.philosophy,
1411
- base: inner.radius_hints.base ?? essence.dna.radius.base
1396
+ philosophy: inner.radius.philosophy || essence.dna.radius.philosophy,
1397
+ base: inner.radius.base ?? essence.dna.radius.base
1412
1398
  };
1413
1399
  }
1414
1400
  }
1415
1401
  } catch {
1416
1402
  }
1417
1403
  writeFileSync8(essencePath, JSON.stringify(essence, null, 2) + "\n");
1418
- console.log(`${GREEN7}Switched theme: ${oldStyle} \u2192 ${themeName}${RESET7}`);
1419
- if (recipe) console.log(` ${DIM7}Recipe: ${recipe}${RESET7}`);
1404
+ console.log(`${GREEN7}Switched theme: ${oldThemeId} \u2192 ${themeName}${RESET7}`);
1420
1405
  if (shape) console.log(` ${DIM7}Shape: ${shape}${RESET7}`);
1421
1406
  if (mode) console.log(` ${DIM7}Mode: ${mode}${RESET7}`);
1422
1407
  await refreshDerivedFiles(projectRoot, essence, registryClient);
1423
- console.log(`${GREEN7}Derived files refreshed (tokens.css, decorators.css, all contexts).${RESET7}`);
1408
+ console.log(`${GREEN7}Derived files refreshed (tokens.css, treatments.css, all contexts).${RESET7}`);
1424
1409
  console.log(`${YELLOW4}Guard will flag code using old tokens. Run \`decantr check\`.${RESET7}`);
1425
1410
  }
1426
1411
 
@@ -2467,7 +2452,7 @@ async function cmdMagic(prompt, projectRoot, options) {
2467
2452
  existing: false
2468
2453
  };
2469
2454
  if (blueprintData) {
2470
- if (blueprintData.theme?.style) initOptions.theme = blueprintData.theme.style;
2455
+ if (blueprintData.theme?.id || blueprintData.theme?.style) initOptions.theme = blueprintData.theme.id || blueprintData.theme.style;
2471
2456
  if (blueprintData.theme?.mode) initOptions.mode = blueprintData.theme.mode;
2472
2457
  if (blueprintData.theme?.shape) initOptions.shape = blueprintData.theme.shape;
2473
2458
  if (blueprintData.personality) {
@@ -2499,8 +2484,6 @@ async function cmdMagic(prompt, projectRoot, options) {
2499
2484
  let patternSpecs;
2500
2485
  let topologyMarkdown = "";
2501
2486
  let themeData;
2502
- let recipeData;
2503
- let blueprintRecipeName;
2504
2487
  let registrySource = apiAvailable ? "api" : "cache";
2505
2488
  if (blueprintData?.compose && blueprintData.compose.length > 0) {
2506
2489
  const entries = blueprintData.compose;
@@ -2604,7 +2587,6 @@ async function cmdMagic(prompt, projectRoot, options) {
2604
2587
  initOptions.personality
2605
2588
  );
2606
2589
  }
2607
- blueprintRecipeName = blueprintData.theme?.recipe;
2608
2590
  console.log(`${BOLD4} Composition:${RESET9}`);
2609
2591
  console.log(` Sections: ${composedSections.sections.length} (${composedSections.sections.map((s) => s.id).join(", ")})`);
2610
2592
  const totalRoutes = Object.keys(routeMap).length;
@@ -2630,23 +2612,16 @@ async function cmdMagic(prompt, projectRoot, options) {
2630
2612
  palette: theme.palette,
2631
2613
  tokens: theme.tokens,
2632
2614
  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
- treatment_overrides: recipe.treatment_overrides
2615
+ typography: theme.typography,
2616
+ motion: theme.motion,
2617
+ decorators: theme.decorators,
2618
+ treatments: theme.treatments,
2619
+ spatial: theme.spatial,
2620
+ radius: theme.radius,
2621
+ shell: theme.shell,
2622
+ effects: theme.effects,
2623
+ compositions: theme.compositions,
2624
+ pattern_preferences: theme.pattern_preferences
2650
2625
  };
2651
2626
  }
2652
2627
  }
@@ -2659,7 +2634,6 @@ async function cmdMagic(prompt, projectRoot, options) {
2659
2634
  archetypeData,
2660
2635
  registrySource,
2661
2636
  themeData,
2662
- recipeData,
2663
2637
  topologyMarkdown,
2664
2638
  composedSections,
2665
2639
  routeMap,
@@ -2916,7 +2890,6 @@ var ALL_CONTENT_TYPES = [
2916
2890
  "patterns",
2917
2891
  "archetypes",
2918
2892
  "themes",
2919
- "recipes",
2920
2893
  "blueprints",
2921
2894
  "shells"
2922
2895
  ];
@@ -3359,7 +3332,7 @@ async function cmdSuggest(query, type) {
3359
3332
  }
3360
3333
  }
3361
3334
  async function cmdGet(type, id) {
3362
- const validTypes = ["pattern", "archetype", "recipe", "theme", "blueprint", "shell"];
3335
+ const validTypes = ["pattern", "archetype", "theme", "blueprint", "shell"];
3363
3336
  if (!validTypes.includes(type)) {
3364
3337
  console.error(error3(`Invalid type "${type}". Must be one of: ${validTypes.join(", ")}`));
3365
3338
  process.exitCode = 1;
@@ -3368,7 +3341,6 @@ async function cmdGet(type, id) {
3368
3341
  const typeMap = {
3369
3342
  pattern: "patterns",
3370
3343
  archetype: "archetypes",
3371
- recipe: "recipes",
3372
3344
  theme: "themes",
3373
3345
  blueprint: "blueprints",
3374
3346
  shell: "shells"
@@ -3497,7 +3469,7 @@ async function cmdValidate(path) {
3497
3469
  }
3498
3470
  }
3499
3471
  async function cmdList(type) {
3500
- const validTypes = ["patterns", "archetypes", "recipes", "themes", "blueprints", "shells"];
3472
+ const validTypes = ["patterns", "archetypes", "themes", "blueprints", "shells"];
3501
3473
  if (!validTypes.includes(type)) {
3502
3474
  console.error(error3(`Invalid type "${type}". Must be one of: ${validTypes.join(", ")}`));
3503
3475
  process.exitCode = 1;
@@ -3611,7 +3583,6 @@ ${YELLOW9}You're offline. Scaffolding Decantr default.${RESET13}`);
3611
3583
  } else {
3612
3584
  options = await runInteractivePrompts(detected, archetypes, blueprints, themes);
3613
3585
  }
3614
- let blueprintRecipeName;
3615
3586
  let topologyMarkdown = "";
3616
3587
  let archetypeData;
3617
3588
  let composedSections;
@@ -3624,8 +3595,8 @@ ${YELLOW9}You're offline. Scaffolding Decantr default.${RESET13}`);
3624
3595
  const rawBlueprint = blueprintResult.data;
3625
3596
  const blueprint = rawBlueprint.data ?? rawBlueprint;
3626
3597
  if (blueprint.theme) {
3627
- if (blueprint.theme.style && options.theme === "luminarum") {
3628
- options.theme = blueprint.theme.style;
3598
+ if ((blueprint.theme.id || blueprint.theme.style) && options.theme === "luminarum") {
3599
+ options.theme = blueprint.theme.id || blueprint.theme.style;
3629
3600
  }
3630
3601
  if (blueprint.theme.mode && options.mode === "dark") {
3631
3602
  options.mode = blueprint.theme.mode;
@@ -3637,7 +3608,6 @@ ${YELLOW9}You're offline. Scaffolding Decantr default.${RESET13}`);
3637
3608
  if (blueprint.personality && (!options.personality || options.personality.length === 0 || options.personality.length === 1 && options.personality[0] === "professional")) {
3638
3609
  options.personality = typeof blueprint.personality === "string" ? [blueprint.personality] : blueprint.personality;
3639
3610
  }
3640
- blueprintRecipeName = blueprint.theme?.recipe;
3641
3611
  if (blueprint.compose && blueprint.compose.length > 0) {
3642
3612
  const entries = blueprint.compose;
3643
3613
  const results = [];
@@ -3754,7 +3724,6 @@ ${YELLOW9}You're offline. Scaffolding Decantr default.${RESET13}`);
3754
3724
  }
3755
3725
  }
3756
3726
  let themeData;
3757
- let recipeData;
3758
3727
  if (options.theme) {
3759
3728
  const themeResult = await registryClient.fetchTheme(options.theme);
3760
3729
  if (themeResult) {
@@ -3765,31 +3734,20 @@ ${YELLOW9}You're offline. Scaffolding Decantr default.${RESET13}`);
3765
3734
  palette: theme.palette,
3766
3735
  tokens: theme.tokens,
3767
3736
  cvd_support: theme.cvd_support,
3768
- typography_hints: theme.typography_hints,
3769
- motion_hints: theme.motion_hints
3737
+ typography: theme.typography,
3738
+ motion: theme.motion,
3739
+ decorators: theme.decorators,
3740
+ treatments: theme.treatments,
3741
+ spatial: theme.spatial,
3742
+ radius: theme.radius,
3743
+ shell: theme.shell,
3744
+ effects: theme.effects,
3745
+ compositions: theme.compositions,
3746
+ pattern_preferences: theme.pattern_preferences
3770
3747
  };
3771
- if (theme.decorators) {
3772
- recipeData = { decorators: theme.decorators };
3773
- }
3774
3748
  } else {
3775
3749
  console.log(`${YELLOW9} Warning: Could not fetch theme "${options.theme}". Using defaults.${RESET13}`);
3776
3750
  }
3777
- const recipeName = blueprintRecipeName || options.theme;
3778
- const recipeResult = await registryClient.fetchRecipe(recipeName);
3779
- if (process.env.DECANTR_DEBUG && recipeResult) {
3780
- const dbg = recipeResult.data;
3781
- console.error(` [debug] recipe source: ${recipeResult.source.type}, keys: ${Object.keys(dbg).join(",")}, has .data: ${"data" in dbg}, has .decorators: ${"decorators" in dbg}, inner.decorators: ${!!dbg.data?.decorators}`);
3782
- }
3783
- if (recipeResult) {
3784
- const rawRecipe = recipeResult.data;
3785
- const recipe = rawRecipe.data ?? rawRecipe;
3786
- recipeData = {
3787
- decorators: recipe.decorators || recipeData?.decorators,
3788
- spatial_hints: recipe.spatial_hints,
3789
- radius_hints: recipe.radius_hints,
3790
- treatment_overrides: recipe.treatment_overrides
3791
- };
3792
- }
3793
3751
  }
3794
3752
  console.log(heading2("Scaffolding project..."));
3795
3753
  const result = await scaffoldProject(
@@ -3800,7 +3758,6 @@ ${YELLOW9}You're offline. Scaffolding Decantr default.${RESET13}`);
3800
3758
  archetypeData,
3801
3759
  registrySource,
3802
3760
  themeData,
3803
- recipeData,
3804
3761
  topologyMarkdown,
3805
3762
  // V3.1 composition data:
3806
3763
  composedSections,
@@ -4130,7 +4087,7 @@ ${BOLD6}Examples:${RESET13}
4130
4087
  case "switch": {
4131
4088
  const name = args[1];
4132
4089
  if (!name) {
4133
- console.error(error3("Usage: decantr theme switch <themeName> [--recipe <r>] [--shape <s>] [--mode <m>]"));
4090
+ console.error(error3("Usage: decantr theme switch <themeName> [--shape <s>] [--mode <m>]"));
4134
4091
  process.exitCode = 1;
4135
4092
  return;
4136
4093
  }
@@ -4199,7 +4156,7 @@ ${BOLD6}Commands:${RESET13}
4199
4156
  ${cyan3("list")} List items by type
4200
4157
  ${cyan3("validate")} Validate essence file (v2 and v3)
4201
4158
  ${cyan3("theme")} Manage custom themes (create, list, validate, delete, import)
4202
- ${cyan3("create")} Create a custom content item (pattern, recipe, theme, etc.)
4159
+ ${cyan3("create")} Create a custom content item (pattern, theme, blueprint, etc.)
4203
4160
  ${cyan3("publish")} Publish a custom content item to the community registry
4204
4161
  ${cyan3("login")} Authenticate with the Decantr registry
4205
4162
  ${cyan3("logout")} Remove stored credentials
@@ -4299,7 +4256,7 @@ async function main() {
4299
4256
  break;
4300
4257
  }
4301
4258
  case "upgrade": {
4302
- const { cmdUpgrade } = await import("./upgrade-LTLUPBZQ.js");
4259
+ const { cmdUpgrade } = await import("./upgrade-TXVD2WIN.js");
4303
4260
  const applyFlag = args.includes("--apply");
4304
4261
  await cmdUpgrade(process.cwd(), { apply: applyFlag });
4305
4262
  break;
@@ -4309,7 +4266,7 @@ async function main() {
4309
4266
  if (command === "heal") {
4310
4267
  console.log(`${YELLOW9}Note: \`decantr heal\` is deprecated. Use \`decantr check\` instead.${RESET13}`);
4311
4268
  }
4312
- const { cmdHeal } = await import("./heal-54MKDDSQ.js");
4269
+ const { cmdHeal } = await import("./heal-VYEGIUAS.js");
4313
4270
  const telemetryFlag = args.includes("--telemetry");
4314
4271
  await cmdHeal(process.cwd(), { telemetry: telemetryFlag });
4315
4272
  break;
@@ -4432,7 +4389,7 @@ async function main() {
4432
4389
  const name = args[2];
4433
4390
  if (!type || !name) {
4434
4391
  console.error(error3("Usage: decantr create <type> <name>"));
4435
- console.error(dim3("Types: pattern, recipe, theme, blueprint, archetype, shell"));
4392
+ console.error(dim3("Types: pattern, theme, blueprint, archetype, shell"));
4436
4393
  process.exitCode = 1;
4437
4394
  break;
4438
4395
  }
@@ -4444,7 +4401,7 @@ async function main() {
4444
4401
  const name = args[2];
4445
4402
  if (!type || !name) {
4446
4403
  console.error(error3("Usage: decantr publish <type> <name>"));
4447
- console.error(dim3("Types: pattern, recipe, theme, blueprint, archetype, shell"));
4404
+ console.error(dim3("Types: pattern, theme, blueprint, archetype, shell"));
4448
4405
  process.exitCode = 1;
4449
4406
  break;
4450
4407
  }
@@ -5,7 +5,7 @@ import { fileURLToPath } from "url";
5
5
  import { computeSpatialTokens } from "@decantr/essence-spec";
6
6
 
7
7
  // src/treatments.ts
8
- function generateTreatmentCSS(spatialTokens, treatmentOverrides, recipeDecorators, recipeName) {
8
+ function generateTreatmentCSS(spatialTokens, treatmentOverrides, themeDecorators, themeName) {
9
9
  const lines = [];
10
10
  lines.push("/* Generated by @decantr/cli \u2014 Visual Treatment System */");
11
11
  lines.push("");
@@ -185,11 +185,11 @@ function generateTreatmentCSS(spatialTokens, treatmentOverrides, recipeDecorator
185
185
  ["background", "color-mix(in srgb, var(--d-info) 15%, transparent)"],
186
186
  ["color", "var(--d-info)"]
187
187
  ]);
188
- if (recipeDecorators && Object.keys(recipeDecorators).length > 0) {
189
- const label = recipeName ? ` (${recipeName})` : "";
190
- lines.push(`/* \u2500\u2500 Layer 3: Recipe Decorators${label} \u2500\u2500 */`);
188
+ if (themeDecorators && Object.keys(themeDecorators).length > 0) {
189
+ const label = themeName ? ` (${themeName})` : "";
190
+ lines.push(`/* \u2500\u2500 Layer 3: Theme Decorators${label} \u2500\u2500 */`);
191
191
  lines.push("");
192
- for (const [name, description] of Object.entries(recipeDecorators)) {
192
+ for (const [name, description] of Object.entries(themeDecorators)) {
193
193
  const rule = generateDecoratorRule(name, description);
194
194
  lines.push(rule);
195
195
  lines.push("");
@@ -520,6 +520,21 @@ function generateTokensCSS(themeData, mode, spatialTokens) {
520
520
  };
521
521
  }
522
522
  const tokens = buildTokens(resolvedMode);
523
+ if (themeData?.typography?.mono) {
524
+ tokens["--d-font-mono"] = themeData.typography.mono;
525
+ }
526
+ if (themeData?.palette?.["accent-glow"]?.[resolvedMode]) {
527
+ tokens["--d-accent-glow"] = themeData.palette["accent-glow"][resolvedMode];
528
+ }
529
+ if (themeData?.motion?.durations?.hover) {
530
+ tokens["--d-duration-hover"] = themeData.motion.durations.hover;
531
+ }
532
+ if (themeData?.motion?.durations?.entrance) {
533
+ tokens["--d-duration-entrance"] = themeData.motion.durations.entrance;
534
+ }
535
+ if (themeData?.motion?.timing) {
536
+ tokens["--d-easing"] = themeData.motion.timing;
537
+ }
523
538
  const lines = Object.entries(tokens).map(([key, value]) => ` ${key}: ${value};`).join("\n");
524
539
  const spatialLines = spatialTokens ? "\n" + Object.entries(spatialTokens).map(([k, v]) => ` ${k}: ${v};`).join("\n") : "";
525
540
  let css = `/* Generated by @decantr/cli */
@@ -612,20 +627,20 @@ input, button, textarea, select {
612
627
  }
613
628
  `;
614
629
  }
615
- function generateTreatmentsContext(recipeData, recipeName) {
630
+ function generateTreatmentsContext(themeData, themeName) {
616
631
  const lines = [];
617
- lines.push(`# Visual Treatments: ${recipeName}`);
632
+ lines.push(`# Visual Treatments: ${themeName}`);
618
633
  lines.push("");
619
634
  lines.push("## Base Treatments");
620
635
  lines.push("");
621
636
  lines.push("d-interactive, d-surface, d-data, d-control, d-section, d-annotation \u2014 see DECANTR.md for usage.");
622
637
  lines.push("");
623
- if (recipeData?.decorators && Object.keys(recipeData.decorators).length > 0) {
624
- lines.push(`## Recipe Decorators (${recipeName}-specific)`);
638
+ if (themeData?.decorators && Object.keys(themeData.decorators).length > 0) {
639
+ lines.push(`## Theme Decorators (${themeName}-specific)`);
625
640
  lines.push("");
626
641
  lines.push("| Class | Use for |");
627
642
  lines.push("|-------|---------|");
628
- for (const [name, description] of Object.entries(recipeData.decorators)) {
643
+ for (const [name, description] of Object.entries(themeData.decorators)) {
629
644
  const useFor = description.split(".")[0].trim();
630
645
  lines.push(`| ${name} | ${useFor} |`);
631
646
  }
@@ -633,12 +648,12 @@ function generateTreatmentsContext(recipeData, recipeName) {
633
648
  }
634
649
  lines.push("## Composition");
635
650
  lines.push("");
636
- lines.push("Atoms + treatment + recipe decorator:");
651
+ lines.push("Atoms + treatment + theme decorator:");
637
652
  lines.push("```tsx");
638
653
  lines.push(`css('_flex _col _gap4') + ' d-surface'`);
639
654
  lines.push("```");
640
655
  lines.push("");
641
- lines.push("Atoms use `css()` function. Treatments and recipe decorators are plain class strings.");
656
+ lines.push("Atoms use `css()` function. Treatments and theme decorators are plain class strings.");
642
657
  return lines.join("\n");
643
658
  }
644
659
  function generateDecoratorRule(name, description) {
@@ -876,7 +891,7 @@ function buildEssence(options, archetypeData) {
876
891
  style: options.theme,
877
892
  mode: options.mode,
878
893
  recipe: options.theme,
879
- // Recipe defaults to theme
894
+ // Legacy v2 field — kept for backward compatibility
880
895
  shape: options.shape
881
896
  },
882
897
  personality: options.personality,
@@ -889,6 +904,7 @@ function buildEssence(options, archetypeData) {
889
904
  guard: {
890
905
  enforce_style: true,
891
906
  enforce_recipe: true,
907
+ // Legacy v2 field — kept for backward compatibility
892
908
  mode: options.guard
893
909
  },
894
910
  density: {
@@ -902,7 +918,7 @@ function buildEssence(options, archetypeData) {
902
918
  }
903
919
  return essence;
904
920
  }
905
- function buildEssenceV3(options, archetypeData, themeHints, recipeHints) {
921
+ function buildEssenceV3(options, archetypeData, themeHints) {
906
922
  let pages = [
907
923
  { id: "home", layout: ["hero"] }
908
924
  ];
@@ -939,9 +955,8 @@ function buildEssenceV3(options, archetypeData, themeHints, recipeHints) {
939
955
  };
940
956
  const dna = {
941
957
  theme: {
942
- style: options.theme,
958
+ id: options.theme,
943
959
  mode: options.mode,
944
- recipe: options.theme,
945
960
  shape: options.shape
946
961
  },
947
962
  spacing: {
@@ -951,9 +966,9 @@ function buildEssenceV3(options, archetypeData, themeHints, recipeHints) {
951
966
  content_gap: densityLevelMap[options.density] || "_gap4"
952
967
  },
953
968
  typography: {
954
- scale: themeHints?.typography_hints?.scale || "modular",
955
- heading_weight: themeHints?.typography_hints?.heading_weight || 600,
956
- body_weight: themeHints?.typography_hints?.body_weight || 400
969
+ scale: themeHints?.typography?.scale || "modular",
970
+ heading_weight: themeHints?.typography?.heading_weight || 600,
971
+ body_weight: themeHints?.typography?.body_weight || 400
957
972
  },
958
973
  color: {
959
974
  palette: "semantic",
@@ -961,17 +976,17 @@ function buildEssenceV3(options, archetypeData, themeHints, recipeHints) {
961
976
  cvd_preference: options.accessibility?.cvd_preference || "auto"
962
977
  },
963
978
  radius: {
964
- philosophy: recipeHints?.radius_hints?.philosophy || options.shape,
965
- base: recipeHints?.radius_hints?.base || shapeRadiusMap[options.shape] || 8
979
+ philosophy: themeHints?.radius?.philosophy || options.shape,
980
+ base: themeHints?.radius?.base || shapeRadiusMap[options.shape] || 8
966
981
  },
967
982
  elevation: {
968
983
  system: "layered",
969
984
  max_levels: 3
970
985
  },
971
986
  motion: {
972
- preference: recipeHints?.animation?.preference || themeHints?.motion_hints?.preference || "subtle",
987
+ preference: themeHints?.motion?.preference || "subtle",
973
988
  duration_scale: 1,
974
- reduce_motion: themeHints?.motion_hints?.reduce_motion_default ?? true
989
+ reduce_motion: themeHints?.motion?.reduce_motion ?? true
975
990
  },
976
991
  accessibility: {
977
992
  wcag_level: options.accessibility?.wcag_level || "AA",
@@ -1003,21 +1018,21 @@ function buildEssenceV3(options, archetypeData, themeHints, recipeHints) {
1003
1018
  }
1004
1019
  var CSS_APPROACH_CONTENT = `## CSS Implementation
1005
1020
 
1006
- This project uses **@decantr/css** for layout atoms, **visual treatments** for semantic styling, and **recipe decorators** for theme-specific decoration.
1021
+ This project uses **@decantr/css** for layout atoms, **visual treatments** for semantic styling, and **theme decorators** for theme-specific decoration.
1007
1022
 
1008
1023
  ### Three File Setup
1009
1024
 
1010
1025
  \`\`\`
1011
1026
  src/styles/
1012
1027
  tokens.css # Design tokens: --d-primary, --d-surface, --d-bg, etc.
1013
- treatments.css # Visual treatments (d-interactive, d-surface, ...) + recipe decorators
1028
+ treatments.css # Visual treatments (d-interactive, d-surface, ...) + theme decorators
1014
1029
  global.css # Resets, base typography, sr-only
1015
1030
  \`\`\`
1016
1031
 
1017
1032
  \`\`\`javascript
1018
1033
  import { css } from '@decantr/css'; // Atoms runtime
1019
1034
  import './styles/tokens.css'; // Theme tokens
1020
- import './styles/treatments.css'; // Treatments + recipe decorators
1035
+ import './styles/treatments.css'; // Treatments + theme decorators
1021
1036
  import './styles/global.css'; // Resets
1022
1037
  \`\`\`
1023
1038
 
@@ -1036,7 +1051,7 @@ Six base treatment classes provide semantic styling. Combine with atoms for layo
1036
1051
 
1037
1052
  ### Composition
1038
1053
 
1039
- Atoms + treatment + recipe decorator:
1054
+ Atoms + treatment + theme decorator:
1040
1055
 
1041
1056
  \`\`\`tsx
1042
1057
  <button className={css('_px4 _py2') + ' d-interactive'} data-variant="primary">Deploy</button>
@@ -1046,7 +1061,7 @@ Atoms + treatment + recipe decorator:
1046
1061
 
1047
1062
  - **Atoms:** \`css('_flex _col _gap4')\` \u2014 processed by @decantr/css runtime
1048
1063
  - **Treatments:** \`d-interactive\`, \`d-surface\` \u2014 semantic base styles from treatments.css
1049
- - **Recipe decorators:** \`carbon-glass\`, \`carbon-code\` \u2014 theme-specific decoration from treatments.css
1064
+ - **Theme decorators:** \`carbon-glass\`, \`carbon-code\` \u2014 theme-specific decoration from treatments.css
1050
1065
  - **Combined:** \`css('_flex _col') + ' d-surface carbon-card'\`
1051
1066
 
1052
1067
  ### Atoms Quick Reference
@@ -1067,16 +1082,20 @@ Scale: 0, 1, 2, 3, 4, 5, 6, 8, 10, 12, 16, 20, 24. Example: \`_gap4\` = \`gap:1r
1067
1082
 
1068
1083
  ### Design Tokens
1069
1084
 
1070
- | Token | Purpose |
1071
- |-------|---------|
1072
- | \`--d-primary\` | Primary brand color |
1073
- | \`--d-surface\`, \`--d-surface-raised\` | Surface backgrounds |
1074
- | \`--d-bg\` | Page background |
1075
- | \`--d-border\` | Border color |
1076
- | \`--d-text\`, \`--d-text-muted\` | Text colors |
1077
- | \`--d-success\`, \`--d-error\`, \`--d-warning\`, \`--d-info\` | Status colors |
1078
- | \`--d-shadow\`, \`--d-shadow-lg\` | Elevation shadows |
1079
- | \`--d-radius\`, \`--d-radius-lg\` | Border radii |
1085
+ | Token | Purpose | Use for |
1086
+ |-------|---------|---------|
1087
+ | \`--d-primary\` | Primary brand color | Buttons, links, focus rings |
1088
+ | \`--d-surface\`, \`--d-surface-raised\` | Surface backgrounds | Cards, panels |
1089
+ | \`--d-bg\` | Page background | Body, main container |
1090
+ | \`--d-border\` | Border color | Dividers, card borders |
1091
+ | \`--d-text\`, \`--d-text-muted\` | Text colors | Body text, secondary text |
1092
+ | \`--d-success\`, \`--d-error\`, \`--d-warning\`, \`--d-info\` | Status colors | Alerts, badges, toasts |
1093
+ | \`--d-shadow\`, \`--d-shadow-lg\` | Elevation shadows | Cards, overlays |
1094
+ | \`--d-radius\`, \`--d-radius-lg\` | Border radii | Buttons, cards |
1095
+ | \`--d-font-mono\` | Monospace font stack | Code, metrics, data |
1096
+ | \`--d-duration-hover\` | Hover transition | Interactive elements |
1097
+ | \`--d-easing\` | Animation easing | All transitions |
1098
+ | \`--d-accent-glow\` | Glow color | Hover effects, focus rings |
1080
1099
 
1081
1100
  ### Routing
1082
1101
 
@@ -1113,8 +1132,7 @@ function generateProjectJson(detected, options, registrySource) {
1113
1132
  cachedContent: {
1114
1133
  archetypes: [],
1115
1134
  patterns: [],
1116
- themes: [],
1117
- recipes: []
1135
+ themes: []
1118
1136
  }
1119
1137
  },
1120
1138
  initialized: {
@@ -1147,7 +1165,7 @@ function generateTaskContext(templateName, essence) {
1147
1165
  TARGET: essence.target,
1148
1166
  THEME_STYLE: essence.theme.style,
1149
1167
  THEME_MODE: essence.theme.mode,
1150
- THEME_RECIPE: essence.theme.recipe,
1168
+ THEME_RECIPE: essence.theme.style,
1151
1169
  DEFAULT_SHELL: defaultShell,
1152
1170
  GUARD_MODE: essence.guard.mode,
1153
1171
  LAYOUT: layout,
@@ -1171,9 +1189,9 @@ function generateTaskContextV3(templateName, essence) {
1171
1189
  const contentGap = essence.dna.spacing?.content_gap || "_gap4";
1172
1190
  const vars = {
1173
1191
  TARGET: essence.meta.target || "react",
1174
- THEME_STYLE: essence.dna.theme.style,
1192
+ THEME_STYLE: essence.dna.theme.id || essence.dna.theme.style || "",
1175
1193
  THEME_MODE: essence.dna.theme.mode,
1176
- THEME_RECIPE: essence.dna.theme.recipe || essence.dna.theme.style,
1194
+ THEME_RECIPE: essence.dna.theme.id || essence.dna.theme.style || "",
1177
1195
  DEFAULT_SHELL: defaultShell,
1178
1196
  GUARD_MODE: essence.meta.guard.mode,
1179
1197
  LAYOUT: layout,
@@ -1210,9 +1228,9 @@ ${rows.join("\n")}`;
1210
1228
  BLUEPRINT: "",
1211
1229
  PERSONALITY: (essence.dna.personality || []).join(", "),
1212
1230
  TARGET: essence.meta.target ?? "",
1213
- THEME_STYLE: essence.dna.theme.style,
1231
+ THEME_STYLE: essence.dna.theme.id ?? essence.dna.theme.style ?? "",
1214
1232
  THEME_MODE: essence.dna.theme.mode,
1215
- THEME_RECIPE: essence.dna.theme.recipe ?? "",
1233
+ THEME_RECIPE: essence.dna.theme.id ?? essence.dna.theme.style ?? "",
1216
1234
  SHAPE: essence.dna.theme.shape ?? "",
1217
1235
  PAGES_TABLE: pagesTable,
1218
1236
  FEATURES_LIST: featuresList,
@@ -1247,8 +1265,8 @@ ${cacheEntry}
1247
1265
  return true;
1248
1266
  }
1249
1267
  }
1250
- async function scaffoldProject(projectRoot, options, detected, registry, archetypeData, registrySource = "cache", themeData, recipeData, topologyMarkdown, composedSections, routeMap, patternSpecs, blueprintData) {
1251
- const essenceV3 = buildEssenceV3(options, archetypeData, themeData, recipeData);
1268
+ async function scaffoldProject(projectRoot, options, detected, registry, archetypeData, registrySource = "cache", themeData, topologyMarkdown, composedSections, routeMap, patternSpecs, blueprintData) {
1269
+ const essenceV3 = buildEssenceV3(options, archetypeData, themeData);
1252
1270
  const essence = buildEssence(options, archetypeData);
1253
1271
  const decantrDir = join(projectRoot, ".decantr");
1254
1272
  const contextDir = join(decantrDir, "context");
@@ -1284,7 +1302,7 @@ async function scaffoldProject(projectRoot, options, detected, registry, archety
1284
1302
  }
1285
1303
  writeFileSync(essencePath, JSON.stringify(essenceV3, null, 2) + "\n");
1286
1304
  }
1287
- const refreshResult = await refreshDerivedFiles(projectRoot, essenceV3, registry, themeData, recipeData, { isInitialScaffold: true });
1305
+ const refreshResult = await refreshDerivedFiles(projectRoot, essenceV3, registry, themeData, { isInitialScaffold: true });
1288
1306
  contextFiles.push(...refreshResult.contextFiles);
1289
1307
  const gitignoreUpdated = updateGitignore(projectRoot);
1290
1308
  return {
@@ -1299,7 +1317,7 @@ async function scaffoldProject(projectRoot, options, detected, registry, archety
1299
1317
  function scaffoldMinimal(projectRoot) {
1300
1318
  const decantrDir = join(projectRoot, ".decantr");
1301
1319
  const customDir = join(decantrDir, "custom");
1302
- const contentTypes = ["patterns", "recipes", "themes", "blueprints", "archetypes", "shells"];
1320
+ const contentTypes = ["patterns", "themes", "blueprints", "archetypes", "shells"];
1303
1321
  for (const type of contentTypes) {
1304
1322
  mkdirSync(join(customDir, type), { recursive: true });
1305
1323
  }
@@ -1307,9 +1325,8 @@ function scaffoldMinimal(projectRoot) {
1307
1325
  version: "3.0.0",
1308
1326
  dna: {
1309
1327
  theme: {
1310
- style: "default",
1328
+ id: "default",
1311
1329
  mode: "dark",
1312
- recipe: "default",
1313
1330
  shape: "rounded"
1314
1331
  },
1315
1332
  spacing: {
@@ -1391,8 +1408,7 @@ function scaffoldMinimal(projectRoot) {
1391
1408
  cachedContent: {
1392
1409
  archetypes: [],
1393
1410
  patterns: [],
1394
- themes: [],
1395
- recipes: []
1411
+ themes: []
1396
1412
  }
1397
1413
  },
1398
1414
  initialized: {
@@ -1486,12 +1502,11 @@ When available, use these tools:
1486
1502
  gitignoreUpdated
1487
1503
  };
1488
1504
  }
1489
- async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThemeData, prefetchedRecipeData, options) {
1505
+ async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThemeData, options) {
1490
1506
  const decantrDir = join(projectRoot, ".decantr");
1491
1507
  const contextDir = join(decantrDir, "context");
1492
1508
  mkdirSync(contextDir, { recursive: true });
1493
- const themeName = essence.dna.theme.style;
1494
- const recipeName = essence.dna.theme.recipe ?? themeName;
1509
+ const themeName = essence.dna.theme.id || essence.dna.theme.style || "default";
1495
1510
  const mode = essence.dna.theme.mode;
1496
1511
  const guardMode = essence.meta.guard.mode;
1497
1512
  const guardConfig = {
@@ -1501,7 +1516,6 @@ async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThe
1501
1516
  };
1502
1517
  const personality = essence.dna.personality || [];
1503
1518
  let themeData = prefetchedThemeData;
1504
- let recipeData = prefetchedRecipeData;
1505
1519
  if (!themeData) try {
1506
1520
  const themeResult = await registry.fetchTheme(themeName);
1507
1521
  if (themeResult?.data) {
@@ -1512,53 +1526,20 @@ async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThe
1512
1526
  palette: t.palette,
1513
1527
  cvd_support: t.cvd_support,
1514
1528
  tokens: t.tokens,
1515
- typography_hints: t.typography_hints,
1516
- motion_hints: t.motion_hints
1529
+ typography: t.typography,
1530
+ motion: t.motion,
1531
+ decorators: t.decorators,
1532
+ treatments: t.treatments,
1533
+ spatial: t.spatial,
1534
+ radius: t.radius,
1535
+ shell: t.shell,
1536
+ effects: t.effects,
1537
+ compositions: t.compositions,
1538
+ pattern_preferences: t.pattern_preferences
1517
1539
  };
1518
1540
  }
1519
1541
  } catch {
1520
1542
  }
1521
- if (!recipeData) try {
1522
- const recipeResult = await registry.fetchRecipe(recipeName);
1523
- if (recipeResult?.data) {
1524
- const raw = recipeResult.data;
1525
- const r = raw.data ?? raw;
1526
- recipeData = {
1527
- decorators: r.decorators,
1528
- spatial_hints: r.spatial_hints,
1529
- radius_hints: r.radius_hints,
1530
- treatment_overrides: r.treatment_overrides
1531
- };
1532
- if (!recipeData.decorators && raw.data) {
1533
- const inner = raw.data;
1534
- if (inner.decorators) {
1535
- recipeData.decorators = inner.decorators;
1536
- recipeData.spatial_hints = inner.spatial_hints;
1537
- recipeData.radius_hints = inner.radius_hints;
1538
- }
1539
- }
1540
- }
1541
- } catch {
1542
- }
1543
- if (!recipeData?.decorators || Object.keys(recipeData.decorators).length === 0) {
1544
- try {
1545
- const apiUrl = registry.apiUrl || "https://api.decantr.ai/v1";
1546
- const resp = await fetch(`${apiUrl}/recipes/@official/${recipeName}`);
1547
- if (resp.ok) {
1548
- const apiData = await resp.json();
1549
- const inner = apiData.data ?? apiData;
1550
- if (inner.decorators && Object.keys(inner.decorators).length > 0) {
1551
- recipeData = {
1552
- decorators: inner.decorators,
1553
- spatial_hints: inner.spatial_hints,
1554
- radius_hints: inner.radius_hints,
1555
- treatment_overrides: inner.treatment_overrides
1556
- };
1557
- }
1558
- }
1559
- } catch {
1560
- }
1561
- }
1562
1543
  if (!themeData?.seed?.primary) {
1563
1544
  try {
1564
1545
  const apiUrl = registry.apiUrl || "https://api.decantr.ai/v1";
@@ -1572,8 +1553,16 @@ async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThe
1572
1553
  palette: inner.palette,
1573
1554
  cvd_support: inner.cvd_support,
1574
1555
  tokens: inner.tokens,
1575
- typography_hints: inner.typography_hints,
1576
- motion_hints: inner.motion_hints
1556
+ typography: inner.typography,
1557
+ motion: inner.motion,
1558
+ decorators: inner.decorators,
1559
+ treatments: inner.treatments,
1560
+ spatial: inner.spatial,
1561
+ radius: inner.radius,
1562
+ shell: inner.shell,
1563
+ effects: inner.effects,
1564
+ compositions: inner.compositions,
1565
+ pattern_preferences: inner.pattern_preferences
1577
1566
  };
1578
1567
  }
1579
1568
  }
@@ -1583,10 +1572,10 @@ async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThe
1583
1572
  const stylesDir = join(projectRoot, "src", "styles");
1584
1573
  mkdirSync(stylesDir, { recursive: true });
1585
1574
  const densityLevel = options.density || "comfortable";
1586
- const spatialTokens = computeSpatialTokens(densityLevel, recipeData?.spatial_hints ? {
1587
- section_padding: recipeData.spatial_hints.section_padding ?? void 0,
1588
- density_bias: typeof recipeData.spatial_hints.density_bias === "number" ? recipeData.spatial_hints.density_bias : void 0,
1589
- content_gap_shift: recipeData.spatial_hints.content_gap_shift
1575
+ const spatialTokens = computeSpatialTokens(densityLevel, themeData?.spatial ? {
1576
+ section_padding: themeData.spatial.section_padding ?? void 0,
1577
+ density_bias: typeof themeData.spatial.density_bias === "number" ? themeData.spatial.density_bias : void 0,
1578
+ content_gap_shift: themeData.spatial.content_gap_shift
1590
1579
  } : void 0);
1591
1580
  const tokensPath = join(stylesDir, "tokens.css");
1592
1581
  const hasRealThemeData = themeData?.seed?.primary || themeData?.palette?.background;
@@ -1596,8 +1585,8 @@ async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThe
1596
1585
  const treatmentsPath = join(stylesDir, "treatments.css");
1597
1586
  writeFileSync(treatmentsPath, generateTreatmentCSS(
1598
1587
  spatialTokens,
1599
- recipeData?.treatment_overrides,
1600
- recipeData?.decorators,
1588
+ themeData?.treatments,
1589
+ themeData?.decorators,
1601
1590
  themeName
1602
1591
  ));
1603
1592
  const globalPath = join(stylesDir, "global.css");
@@ -1606,7 +1595,7 @@ async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThe
1606
1595
  }
1607
1596
  const cssFiles = [tokensPath, treatmentsPath, globalPath];
1608
1597
  const treatmentsMdPath = join(contextDir, "treatments.md");
1609
- writeFileSync(treatmentsMdPath, generateTreatmentsContext(recipeData, recipeName));
1598
+ writeFileSync(treatmentsMdPath, generateTreatmentsContext(themeData, themeName));
1610
1599
  const decantrMdPath = join(projectRoot, "DECANTR.md");
1611
1600
  writeFileSync(decantrMdPath, generateDecantrMdV31(guardMode, CSS_APPROACH_CONTENT));
1612
1601
  const hasSections = essence.blueprint.sections && essence.blueprint.sections.length > 0;
@@ -1708,8 +1697,8 @@ async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThe
1708
1697
  const topologyMarkdown = generateTopologySection(topologyData, personality);
1709
1698
  const themeTokensCss = existsSync(tokensPath) ? readFileSync(tokensPath, "utf-8") : "";
1710
1699
  const decoratorList = [];
1711
- if (recipeData?.decorators) {
1712
- for (const [name, desc] of Object.entries(recipeData.decorators)) {
1700
+ if (themeData?.decorators) {
1701
+ for (const [name, desc] of Object.entries(themeData.decorators)) {
1713
1702
  decoratorList.push({ name, description: desc });
1714
1703
  }
1715
1704
  } else if (existsSync(decoratorsPath)) {
@@ -1777,7 +1766,6 @@ async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThe
1777
1766
  guardConfig,
1778
1767
  personality,
1779
1768
  themeName,
1780
- recipeName,
1781
1769
  zoneContext,
1782
1770
  patternSpecs: sectionPatterns,
1783
1771
  constraints: essence.dna.constraints,
@@ -1792,7 +1780,6 @@ async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThe
1792
1780
  appName: essence.meta.archetype || "Application",
1793
1781
  blueprintId: "",
1794
1782
  themeName,
1795
- recipeName,
1796
1783
  personality,
1797
1784
  topologyMarkdown,
1798
1785
  sections,
@@ -1867,8 +1854,8 @@ async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThe
1867
1854
  }
1868
1855
  const themeTokensCss = existsSync(tokensPath) ? readFileSync(tokensPath, "utf-8") : "";
1869
1856
  const decoratorList = [];
1870
- if (recipeData?.decorators) {
1871
- for (const [name, desc] of Object.entries(recipeData.decorators)) {
1857
+ if (themeData?.decorators) {
1858
+ for (const [name, desc] of Object.entries(themeData.decorators)) {
1872
1859
  decoratorList.push({ name, description: desc });
1873
1860
  }
1874
1861
  } else if (existsSync(decoratorsPath)) {
@@ -1906,7 +1893,6 @@ async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThe
1906
1893
  guardConfig,
1907
1894
  personality,
1908
1895
  themeName,
1909
- recipeName,
1910
1896
  zoneContext: `This is the primary section (${shell} shell).`,
1911
1897
  patternSpecs,
1912
1898
  constraints: essence.dna.constraints,
@@ -2010,7 +1996,7 @@ function generateSyntheticComponents(patternId, description) {
2010
1996
  return [...new Set(syntheticComponents)];
2011
1997
  }
2012
1998
  function generateSectionContext(input) {
2013
- const { section, decorators, guardConfig, personality, themeName, recipeName, zoneContext, patternSpecs, recipeHints, constraints, shellInfo } = input;
1999
+ const { section, decorators, guardConfig, personality, themeName, zoneContext, patternSpecs, themeHints, constraints, shellInfo } = input;
2014
2000
  const lines = [];
2015
2001
  lines.push(`# Section: ${section.id}`);
2016
2002
  lines.push("");
@@ -2038,18 +2024,18 @@ function generateSectionContext(input) {
2038
2024
  lines.push("**Visual Treatments:** All 6 base treatments available (see DECANTR.md for usage).");
2039
2025
  if (decorators.length > 0) {
2040
2026
  const names = decorators.map((d) => d.name).join(", ");
2041
- lines.push(`**Recipe decorators:** ${names}`);
2027
+ lines.push(`**Theme decorators:** ${names}`);
2042
2028
  }
2043
2029
  lines.push("");
2044
- if (recipeHints) {
2045
- if (recipeHints.preferred && recipeHints.preferred.length > 0) {
2046
- lines.push(`**Preferred:** ${recipeHints.preferred.join(", ")}`);
2030
+ if (themeHints) {
2031
+ if (themeHints.preferred && themeHints.preferred.length > 0) {
2032
+ lines.push(`**Preferred:** ${themeHints.preferred.join(", ")}`);
2047
2033
  }
2048
- if (recipeHints.compositions) {
2049
- lines.push(`**Compositions:** ${recipeHints.compositions}`);
2034
+ if (themeHints.compositions) {
2035
+ lines.push(`**Compositions:** ${themeHints.compositions}`);
2050
2036
  }
2051
- if (recipeHints.spatialHints) {
2052
- lines.push(`**Spatial hints:** ${recipeHints.spatialHints}`);
2037
+ if (themeHints.spatialHints) {
2038
+ lines.push(`**Spatial hints:** ${themeHints.spatialHints}`);
2053
2039
  }
2054
2040
  lines.push("");
2055
2041
  }
@@ -2134,12 +2120,12 @@ function generateSectionContext(input) {
2134
2120
  return lines.join("\n");
2135
2121
  }
2136
2122
  function generateScaffoldContext(input) {
2137
- const { appName, blueprintId, themeName, recipeName, personality, topologyMarkdown, sections, routes, constraints, seo, navigation } = input;
2123
+ const { appName, blueprintId, themeName, personality, topologyMarkdown, sections, routes, constraints, seo, navigation } = input;
2138
2124
  const lines = [];
2139
2125
  lines.push(`# Scaffold: ${appName}`);
2140
2126
  lines.push("");
2141
2127
  lines.push(`**Blueprint:** ${blueprintId}`);
2142
- lines.push(`**Theme:** ${themeName} | **Recipe:** ${recipeName}`);
2128
+ lines.push(`**Theme:** ${themeName}`);
2143
2129
  lines.push(`**Personality:** ${personality.join(", ")}`);
2144
2130
  lines.push("**Guard mode:** creative (no enforcement during initial scaffolding)");
2145
2131
  lines.push("");
@@ -2234,7 +2220,7 @@ import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as rea
2234
2220
  import { join as join2 } from "path";
2235
2221
  import { RegistryAPIClient } from "@decantr/registry";
2236
2222
  var DEFAULT_API_URL = "https://api.decantr.ai/v1";
2237
- var ALL_CONTENT_TYPES = ["themes", "patterns", "recipes", "blueprints", "archetypes", "shells"];
2223
+ var ALL_CONTENT_TYPES = ["themes", "patterns", "blueprints", "archetypes", "shells"];
2238
2224
  function loadFromCache(cacheDir, contentType, id, namespace) {
2239
2225
  const nsDir = namespace ? join2(cacheDir, namespace) : cacheDir;
2240
2226
  const cachePath = id ? join2(nsDir, contentType, `${id}.json`) : join2(nsDir, contentType, "index.json");
@@ -2398,12 +2384,6 @@ var RegistryClient = class {
2398
2384
  async fetchShell(id) {
2399
2385
  return this.fetchContentItem("shells", id);
2400
2386
  }
2401
- async fetchRecipes() {
2402
- return this.fetchContentList("recipes");
2403
- }
2404
- async fetchRecipe(id) {
2405
- return this.fetchContentItem("recipes", id);
2406
- }
2407
2387
  /**
2408
2388
  * Check if API is available.
2409
2389
  */
@@ -8,7 +8,7 @@ import { readFileSync, writeFileSync, existsSync } from "fs";
8
8
  import { join } from "path";
9
9
  var TELEMETRY_ENDPOINT = "https://api.decantr.ai/v1/telemetry/guard";
10
10
  var TELEMETRY_TIMEOUT_MS = 3e3;
11
- var DNA_RULES = /* @__PURE__ */ new Set(["style", "recipe", "density", "accessibility", "theme-mode"]);
11
+ var DNA_RULES = /* @__PURE__ */ new Set(["style", "density", "accessibility", "theme-mode"]);
12
12
  async function sendGuardMetrics(metrics) {
13
13
  try {
14
14
  const controller = new AbortController();
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import "./chunk-QZVA3PFR.js";
2
- import "./chunk-B5OX2EXL.js";
1
+ import "./chunk-D3W3MYKT.js";
2
+ import "./chunk-T7CQSJGV.js";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  RegistryClient,
3
3
  refreshDerivedFiles
4
- } from "./chunk-B5OX2EXL.js";
4
+ } from "./chunk-T7CQSJGV.js";
5
5
 
6
6
  // src/commands/upgrade.ts
7
7
  import { readFileSync, writeFileSync, existsSync } from "fs";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@decantr/cli",
3
- "version": "1.5.3",
3
+ "version": "1.5.4",
4
4
  "description": "Decantr CLI — search the registry, validate essence files, and access design intelligence from the terminal",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -8,9 +8,8 @@
8
8
  "tags": ["starter", "minimal", "offline"],
9
9
  "compose": [],
10
10
  "theme": {
11
- "style": "default",
11
+ "id": "default",
12
12
  "mode": "system",
13
- "recipe": null,
14
13
  "shape": "rounded"
15
14
  },
16
15
  "personality": ["clean", "minimal"],
@@ -18,7 +18,7 @@ Decantr is a design intelligence layer that sits between you (the AI code genera
18
18
 
19
19
  DNA defines the foundational design rules. **DNA violations are errors** -- they must never happen without updating the essence first.
20
20
 
21
- DNA axioms include: Theme (style, mode, recipe, shape), Spacing (density, content gap), Typography (scale, weights), Color (palette, accent count), Radius (philosophy, base), Elevation (system, levels), Motion (preference, reduce-motion), Accessibility (WCAG level, focus-visible), and Personality traits.
21
+ DNA axioms include: Theme (id, mode, shape), Spacing (density, content gap), Typography (scale, weights), Color (palette, accent count), Radius (philosophy, base), Elevation (system, levels), Motion (preference, reduce-motion), Accessibility (WCAG level, focus-visible), and Personality traits.
22
22
 
23
23
  ### Blueprint (Structural Layout)
24
24
 
@@ -33,13 +33,12 @@ Blueprint includes: Sections (grouped by archetype with role, shell, and scoped
33
33
  | # | Rule | Layer | What It Checks |
34
34
  |---|------|-------|----------------|
35
35
  | 1 | Style | DNA (error) | Code uses the theme specified in DNA |
36
- | 2 | Recipe | DNA (error) | Decorations match the DNA recipe |
37
- | 3 | Density | DNA (error) | Spacing follows the density profile |
38
- | 4 | Accessibility | DNA (error) | Code meets the WCAG level |
39
- | 5 | Theme-mode | DNA (error) | Theme/mode combination is valid |
40
- | 6 | Structure | Blueprint (warn) | Pages exist in the blueprint sections |
41
- | 7 | Layout | Blueprint (warn) | Pattern order matches the layout spec |
42
- | 8 | Pattern existence | Blueprint (warn) | Patterns referenced exist in the registry |
36
+ | 2 | Density | DNA (error) | Spacing follows the density profile |
37
+ | 3 | Accessibility | DNA (error) | Code meets the WCAG level |
38
+ | 4 | Theme-mode | DNA (error) | Theme/mode combination is valid |
39
+ | 5 | Structure | Blueprint (warn) | Pages exist in the blueprint sections |
40
+ | 6 | Layout | Blueprint (warn) | Pattern order matches the layout spec |
41
+ | 7 | Pattern existence | Blueprint (warn) | Patterns referenced exist in the registry |
43
42
 
44
43
  ### Enforcement Tiers
45
44
 
@@ -96,7 +95,7 @@ Run `decantr check` to validate code against the spec.
96
95
  decantr status # Project health
97
96
  decantr check # Detect drift violations
98
97
  decantr get pattern X # Fetch a pattern spec from registry
99
- decantr get recipe X # Fetch recipe decorators
98
+ decantr get theme X # Fetch theme details and decorators
100
99
  decantr search <query> # Search the registry
101
100
  ```
102
101
 
@@ -19,7 +19,7 @@ Auto-generated summary of `decantr.essence.json`.
19
19
  |----------|-------|
20
20
  | Theme | {{THEME_STYLE}} |
21
21
  | Mode | {{THEME_MODE}} |
22
- | Recipe | {{THEME_RECIPE}} |
22
+ | Theme ID | {{THEME_RECIPE}} |
23
23
  | Shape | {{SHAPE}} |
24
24
 
25
25
  ## Structure
@@ -17,8 +17,7 @@
17
17
  "cachedContent": {
18
18
  "archetypes": {{CACHED_ARCHETYPES}},
19
19
  "patterns": {{CACHED_PATTERNS}},
20
- "themes": {{CACHED_THEMES}},
21
- "recipes": {{CACHED_RECIPES}}
20
+ "themes": {{CACHED_THEMES}}
22
21
  }
23
22
  },
24
23
  "initialized": {
@@ -11,12 +11,11 @@ You are adding new pages or features to an existing Decantr project. Guided mode
11
11
  | # | Layer | Rule | Enforcement | What It Means |
12
12
  |---|-------|------|-------------|---------------|
13
13
  | 1 | DNA | **Style** | ENFORCED | You MUST use theme `{{THEME_STYLE}}` |
14
- | 2 | DNA | **Recipe** | ENFORCED | You MUST use recipe `{{THEME_RECIPE}}` |
15
- | 3 | DNA | **Density** | ENFORCED | You MUST follow density `{{DENSITY}}` |
16
- | 4 | DNA | **Accessibility** | ENFORCED | You MUST meet WCAG level from essence |
17
- | 5 | DNA | **Theme-mode** | ENFORCED | Theme/mode combination must be compatible |
18
- | 6 | Blueprint | **Structure** | ENFORCED | Page MUST exist in essence before generating code |
19
- | 7 | Blueprint | Layout | advisory | Pattern order is flexible |
14
+ | 2 | DNA | **Density** | ENFORCED | You MUST follow density `{{DENSITY}}` |
15
+ | 3 | DNA | **Accessibility** | ENFORCED | You MUST meet WCAG level from essence |
16
+ | 4 | DNA | **Theme-mode** | ENFORCED | Theme/mode combination must be compatible |
17
+ | 5 | Blueprint | **Structure** | ENFORCED | Page MUST exist in essence before generating code |
18
+ | 6 | Blueprint | Layout | advisory | Pattern order is flexible |
20
19
  | 8 | Blueprint | **Pattern-exists** | ENFORCED | All patterns must exist in the registry |
21
20
 
22
21
  ## Before You Start
@@ -64,7 +63,7 @@ Before adding a page:
64
63
  During code generation:
65
64
 
66
65
  - [ ] Use theme `{{THEME_STYLE}}` for all styling
67
- - [ ] Use recipe `{{THEME_RECIPE}}` for decorations
66
+ - [ ] Use theme `{{THEME_RECIPE}}` decorators for decoration
68
67
  - [ ] Follow the shell structure ({{DEFAULT_SHELL}})
69
68
  - [ ] Include patterns from the layout array
70
69
 
@@ -72,7 +71,7 @@ After generation:
72
71
 
73
72
  - [ ] Run `npx @decantr/cli validate`
74
73
  - [ ] Verify the page matches the theme
75
- - [ ] Check that the recipe styles are applied
74
+ - [ ] Check that the theme decorator styles are applied
76
75
 
77
76
  ## Violation Response
78
77
 
@@ -11,12 +11,11 @@ You are modifying existing code in a Decantr project. ALL 8 guard rules are enfo
11
11
  | # | Layer | Rule | Enforcement | Consequence of Violation |
12
12
  |---|-------|------|-------------|--------------------------|
13
13
  | 1 | DNA | **Style** | STRICT | ERROR — Code rejected |
14
- | 2 | DNA | **Recipe** | STRICT | ERRORCode rejected |
15
- | 3 | DNA | **Density** | STRICT | WARNINGFlagged for review |
16
- | 4 | DNA | **Accessibility** | STRICT | ERROR — Code rejected |
17
- | 5 | DNA | **Theme-mode** | STRICT | ERROR — Code rejected |
18
- | 6 | Blueprint | **Structure** | STRICT | ERROR — Code rejected |
19
- | 7 | Blueprint | **Layout** | STRICT | ERROR — Pattern order must match exactly |
14
+ | 2 | DNA | **Density** | STRICT | WARNINGFlagged for review |
15
+ | 3 | DNA | **Accessibility** | STRICT | ERRORCode rejected |
16
+ | 4 | DNA | **Theme-mode** | STRICT | ERROR — Code rejected |
17
+ | 5 | Blueprint | **Structure** | STRICT | ERROR — Code rejected |
18
+ | 6 | Blueprint | **Layout** | STRICT | ERROR — Pattern order must match exactly |
20
19
  | 8 | Blueprint | **Pattern-exists** | STRICT | ERROR — Code rejected |
21
20
 
22
21
  ## Violation Response Protocol
@@ -75,7 +74,7 @@ For the page you're modifying, verify:
75
74
  - Shell matches the page's `shell` property
76
75
  - Patterns match the page's `layout[]` in order
77
76
  - Theme matches `theme.style`
78
- - Recipe matches `theme.recipe`
77
+ - Theme decorators match `theme.id`
79
78
 
80
79
  ### 3. Plan Changes
81
80
 
@@ -93,7 +92,7 @@ Before modifying:
93
92
  - [ ] Page exists in essence structure
94
93
  - [ ] I know the exact layout order: `{{LAYOUT}}`
95
94
  - [ ] I will use theme: `{{THEME_STYLE}}`
96
- - [ ] I will use recipe: `{{THEME_RECIPE}}`
95
+ - [ ] I will use theme: `{{THEME_RECIPE}}`
97
96
  - [ ] I will follow density: `{{DENSITY}}`
98
97
 
99
98
  During modification:
@@ -144,7 +143,7 @@ Swapping `chart-grid` and `data-table` is a Layout guard violation.
144
143
  | "Theme mismatch" | Used different theme | Revert to `{{THEME_STYLE}}` |
145
144
  | "Page undefined" | Edited undeclared page | Add page to essence first |
146
145
  | "Layout order wrong" | Patterns out of order | Match `layout[]` exactly |
147
- | "Recipe mismatch" | Wrong decoration style | Use `{{THEME_RECIPE}}` |
146
+ | "Theme mismatch" | Wrong decoration style | Use `{{THEME_RECIPE}}` |
148
147
  | "Density drift" | Wrong spacing values | Use `{{CONTENT_GAP}}` tokens |
149
148
 
150
149
  ## Proposing Essence Changes
@@ -17,8 +17,7 @@ During scaffolding, the following rules are recommendations, not requirements:
17
17
  | # | Layer | Rule | Status | Guidance |
18
18
  |---|-------|------|--------|----------|
19
19
  | 1 | DNA | Style | Advisory | Use the theme from essence, but creative variations are acceptable |
20
- | 2 | DNA | Recipe | Advisory | Apply recipe styles where possible |
21
- | 3 | DNA | Density | Advisory | Follow spacing guidelines loosely |
20
+ | 2 | DNA | Density | Advisory | Follow spacing guidelines loosely |
22
21
  | 4 | DNA | Accessibility | Advisory | Meet WCAG level from essence where possible |
23
22
  | 5 | DNA | Theme-mode | Advisory | Use the specified theme/mode combination |
24
23
  | 6 | Blueprint | Structure | Advisory | Follow the page structure, add placeholder content |