@decantr/cli 1.6.2 → 1.6.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-TL5VMEPJ.js";
3
- import "./chunk-7QOXORFL.js";
2
+ import "./chunk-NH3YWDNG.js";
3
+ import "./chunk-AFX57QLI.js";
@@ -13,6 +13,8 @@ function generateTreatmentCSS(spatialTokens, treatmentOverrides, themeDecorators
13
13
  lines.push("");
14
14
  lines.push("/* \u2500\u2500 Layer 1: Base Treatments \u2500\u2500 */");
15
15
  lines.push("");
16
+ const THEME_ONLY_PROPS = /* @__PURE__ */ new Set(["backdrop-filter", "-webkit-backdrop-filter"]);
17
+ const themeOverrideRules = [];
16
18
  function emitRule(selector, props) {
17
19
  const treatmentName = selector.replace(/^\./, "").replace(/[:[\s].+$/, "");
18
20
  const overrides = treatmentOverrides?.[treatmentName];
@@ -21,8 +23,20 @@ function generateTreatmentCSS(spatialTokens, treatmentOverrides, themeDecorators
21
23
  merged.set(prop, val);
22
24
  }
23
25
  if (overrides && selector === `.${treatmentName}`) {
26
+ const themeProps = [];
24
27
  for (const [prop, val] of Object.entries(overrides)) {
25
- merged.set(prop, val);
28
+ if (THEME_ONLY_PROPS.has(prop)) {
29
+ themeProps.push([prop, val]);
30
+ } else {
31
+ merged.set(prop, val);
32
+ }
33
+ }
34
+ if (themeProps.length > 0 && themeName) {
35
+ const themeSelector = `[data-theme="${themeName}"] ${selector}`;
36
+ const themeBody = themeProps.map(([p, v]) => ` ${p}: ${v};`).join("\n");
37
+ themeOverrideRules.push(`${themeSelector} {
38
+ ${themeBody}
39
+ }`);
26
40
  }
27
41
  }
28
42
  const body = Array.from(merged.entries()).map(([p, v]) => ` ${p}: ${v};`).join("\n");
@@ -204,13 +218,16 @@ function generateTreatmentCSS(spatialTokens, treatmentOverrides, themeDecorators
204
218
  ["color", "var(--d-text-muted)"],
205
219
  ["font-family", "var(--d-font-mono, ui-monospace, monospace)"]
206
220
  ]);
221
+ if (themeOverrideRules.length > 0) {
222
+ lines.push("/* \u2500\u2500 Theme-scoped Treatment Overrides \u2500\u2500 */");
223
+ lines.push("");
224
+ for (const rule of themeOverrideRules) {
225
+ lines.push(rule);
226
+ lines.push("");
227
+ }
228
+ }
207
229
  lines.push("/* \u2500\u2500 Keyframes \u2500\u2500 */");
208
230
  lines.push("");
209
- lines.push("@keyframes decantr-fade-in {");
210
- lines.push(" from { opacity: 0; transform: translateY(4px); }");
211
- lines.push(" to { opacity: 1; transform: translateY(0); }");
212
- lines.push("}");
213
- lines.push("");
214
231
  lines.push("@keyframes decantr-pulse {");
215
232
  lines.push(" 0%, 100% { opacity: 1; }");
216
233
  lines.push(" 50% { opacity: 0.5; }");
@@ -245,6 +262,7 @@ function generatePersonalityCSS(personality, themeData) {
245
262
  rules.push(`.status-ring[data-status="error"] { border-color: var(--d-error); box-shadow: 0 0 12px color-mix(in srgb, var(--d-error) 25%, transparent); }`);
246
263
  rules.push(`.status-ring[data-status="warning"] { border-color: var(--d-warning); }`);
247
264
  rules.push(`.status-ring[data-status="idle"] { border-color: var(--d-text-muted); }`);
265
+ rules.push(`.status-ring[data-status="processing"] { border-color: var(--d-primary); }`);
248
266
  rules.push(`@keyframes pulse-ring { 0% { opacity: 0.6; transform: scale(1); } 100% { opacity: 0; transform: scale(1.3); } }`);
249
267
  rules.push(`.status-ring[data-status="active"]::after { content: ''; position: absolute; inset: -4px; border-radius: 50%; border: 2px solid var(--d-success); opacity: 0; animation: pulse-ring 2s ease-out infinite; }`);
250
268
  }
@@ -474,14 +492,15 @@ function generateTopologySection(data, personality) {
474
492
  lines.push("");
475
493
  lines.push("### Zones");
476
494
  lines.push("");
495
+ if (personality.length > 0) {
496
+ lines.push(`**Personality:** ${personality.join(", ")}`);
497
+ lines.push("");
498
+ }
477
499
  for (const zone of data.zones) {
478
500
  const label = ZONE_LABELS[zone.role] || zone.role;
479
501
  lines.push(`**${label}** \u2014 ${zone.shell} shell`);
480
502
  lines.push(` Archetypes: ${zone.archetypes.join(", ")}`);
481
503
  lines.push(` Purpose: ${zone.descriptions.join(" ")}`);
482
- if (personality.length > 0) {
483
- lines.push(` Tone: ${personality.join(", ")}`);
484
- }
485
504
  if (zone.features.length > 0) {
486
505
  lines.push(` Features: ${zone.features.join(", ")}`);
487
506
  }
@@ -532,7 +551,7 @@ function generateTokensCSS(themeData, mode, spatialTokens) {
532
551
  return {
533
552
  // Seed colors
534
553
  "--d-primary": seed.primary || "#6366f1",
535
- "--d-secondary": seed.secondary || "#a1a1aa",
554
+ "--d-secondary": palette.secondary?.[tokenMode] || palette.secondary?.dark || seed.secondary || "#A1A1AA",
536
555
  "--d-accent": seed.accent || "#f59e0b",
537
556
  // Palette colors (mode-aware)
538
557
  "--d-bg": palette.background?.[tokenMode] || "#18181b",
@@ -1127,10 +1146,8 @@ function generateDecantrMdV31(params) {
1127
1146
  briefLines.push("## Project Brief");
1128
1147
  briefLines.push("");
1129
1148
  briefLines.push(`- **Blueprint:** ${params.blueprintId || "custom"}`);
1130
- const themeParts = [params.themeName || "default"];
1131
- if (params.themeMode) themeParts.push(`${params.themeMode} mode`);
1132
- if (params.themeShape) themeParts.push(params.themeShape);
1133
- briefLines.push(`- **Theme:** ${themeParts.join(" (").replace(/ \($/, "") + (themeParts.length > 1 ? ")" : "")}`);
1149
+ const themeDesc = `${params.themeName || "default"} (${params.themeMode || "dark"} mode${params.themeShape ? `, ${params.themeShape} shape` : ""})`;
1150
+ briefLines.push(`- **Theme:** ${themeDesc}`);
1134
1151
  if (params.personality && params.personality.length > 0) {
1135
1152
  briefLines.push(`- **Personality:** ${params.personality.join(". ")}`);
1136
1153
  }
@@ -1197,6 +1214,9 @@ function generateProjectJson(detected, options, registrySource) {
1197
1214
  flags: buildFlagsString(options)
1198
1215
  }
1199
1216
  };
1217
+ if (options.blueprint) {
1218
+ data.blueprintId = options.blueprint;
1219
+ }
1200
1220
  return JSON.stringify(data, null, 2);
1201
1221
  }
1202
1222
  function buildFlagsString(options) {
@@ -1209,13 +1229,21 @@ function buildFlagsString(options) {
1209
1229
  }
1210
1230
  function generateTaskContextV3(templateName, essence) {
1211
1231
  const template = loadTemplate(templateName);
1212
- const pages = essence.blueprint.sections && essence.blueprint.sections.length > 0 ? essence.blueprint.sections.flatMap((s) => s.pages) : essence.blueprint.pages || [];
1213
- const defaultShell = essence.blueprint.sections?.[0]?.shell || essence.blueprint.shell || "sidebar-main";
1232
+ const sections = essence.blueprint.sections && essence.blueprint.sections.length > 0 ? essence.blueprint.sections : [];
1233
+ const pages = sections.length > 0 ? sections.flatMap((s) => s.pages) : essence.blueprint.pages || [];
1234
+ const defaultShell = sections[0]?.shell || essence.blueprint.shell || "sidebar-main";
1214
1235
  const layout = pages[0]?.layout?.map(serializeLayoutItem).join(", ") || "none";
1236
+ const pageShellMap = /* @__PURE__ */ new Map();
1237
+ for (const s of sections) {
1238
+ for (const p of s.pages) {
1239
+ pageShellMap.set(p.id, s.shell);
1240
+ }
1241
+ }
1215
1242
  const scaffoldStructure = pages.map((p) => {
1243
+ const shell = pageShellMap.get(p.id) || defaultShell;
1216
1244
  const patterns = p.layout.length > 0 ? `
1217
1245
  - Patterns: ${p.layout.map(serializeLayoutItem).join(", ")}` : "";
1218
- return `- **${p.id}** (${defaultShell})${patterns}`;
1246
+ return `- **${p.id}** (${shell})${patterns}`;
1219
1247
  }).join("\n");
1220
1248
  const densityLevel = essence.dna.spacing?.density || "comfortable";
1221
1249
  const contentGap = essence.dna.spacing?.content_gap || "_gap4";
@@ -1307,7 +1335,12 @@ async function scaffoldProject(projectRoot, options, detected, registry, archety
1307
1335
  const essencePath = join(projectRoot, "decantr.essence.json");
1308
1336
  writeFileSync(essencePath, JSON.stringify(essenceV3, null, 2) + "\n");
1309
1337
  const projectJsonPath = join(decantrDir, "project.json");
1310
- writeFileSync(projectJsonPath, generateProjectJson(detected, options, registrySource));
1338
+ const projectJsonStr = generateProjectJson(detected, options, registrySource);
1339
+ const projectJsonObj = JSON.parse(projectJsonStr);
1340
+ if (blueprintData?.voice) {
1341
+ projectJsonObj.voice = blueprintData.voice;
1342
+ }
1343
+ writeFileSync(projectJsonPath, JSON.stringify(projectJsonObj, null, 2));
1311
1344
  const contextFiles = [];
1312
1345
  const scaffoldPath = join(contextDir, "task-scaffold.md");
1313
1346
  writeFileSync(scaffoldPath, generateTaskContextV3("task-scaffold.md.template", essenceV3));
@@ -1599,6 +1632,32 @@ async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThe
1599
1632
  const decantrDir = join(projectRoot, ".decantr");
1600
1633
  const contextDir = join(decantrDir, "context");
1601
1634
  mkdirSync(contextDir, { recursive: true });
1635
+ let storedBlueprintId;
1636
+ let storedVoice;
1637
+ const projectJsonFilePath = join(decantrDir, "project.json");
1638
+ let projectJsonData = {};
1639
+ if (existsSync(projectJsonFilePath)) {
1640
+ try {
1641
+ projectJsonData = JSON.parse(readFileSync(projectJsonFilePath, "utf-8"));
1642
+ if (projectJsonData.blueprintId) storedBlueprintId = projectJsonData.blueprintId;
1643
+ if (projectJsonData.voice) storedVoice = projectJsonData.voice;
1644
+ } catch {
1645
+ }
1646
+ }
1647
+ if (!storedVoice && storedBlueprintId) {
1648
+ try {
1649
+ const bpResult = await registry.fetchBlueprint(storedBlueprintId);
1650
+ if (bpResult?.data) {
1651
+ const bpData = bpResult.data;
1652
+ if (bpData.voice) {
1653
+ storedVoice = bpData.voice;
1654
+ projectJsonData.voice = bpData.voice;
1655
+ writeFileSync(projectJsonFilePath, JSON.stringify(projectJsonData, null, 2));
1656
+ }
1657
+ }
1658
+ } catch {
1659
+ }
1660
+ }
1602
1661
  const themeName = essence.dna.theme.id || essence.dna.theme.style || "default";
1603
1662
  const mode = essence.dna.theme.mode;
1604
1663
  const guardMode = essence.meta.guard.mode;
@@ -1716,7 +1775,7 @@ async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThe
1716
1775
  writeFileSync(decantrMdPath, generateDecantrMdV31({
1717
1776
  guardMode,
1718
1777
  cssApproach: CSS_APPROACH_CONTENT,
1719
- blueprintId: essence.meta.blueprint || void 0,
1778
+ blueprintId: storedBlueprintId || essence.meta.blueprint || void 0,
1720
1779
  themeName,
1721
1780
  themeMode: mode,
1722
1781
  themeShape: essence.dna.theme.shape || void 0,
@@ -1865,7 +1924,7 @@ async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThe
1865
1924
  const routes = blueprint.routes || {};
1866
1925
  const scaffoldContent = generateScaffoldContext({
1867
1926
  appName: essence.meta.archetype || "Application",
1868
- blueprintId: "",
1927
+ blueprintId: storedBlueprintId || essence.meta.blueprint || "",
1869
1928
  themeName,
1870
1929
  personality,
1871
1930
  topologyMarkdown,
@@ -1873,7 +1932,8 @@ async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThe
1873
1932
  routes,
1874
1933
  constraints: essence.dna.constraints,
1875
1934
  seo: essence.meta.seo,
1876
- navigation: essence.meta.navigation
1935
+ navigation: essence.meta.navigation,
1936
+ voice: storedVoice
1877
1937
  });
1878
1938
  const scaffoldMdPath = join(contextDir, "scaffold.md");
1879
1939
  writeFileSync(scaffoldMdPath, scaffoldContent);
@@ -2086,18 +2146,31 @@ function generateSectionContext(input) {
2086
2146
  text: "Body text, headings, primary content",
2087
2147
  "text-muted": "Secondary text, placeholders, labels",
2088
2148
  primary: "Brand color, key interactive, selected states",
2089
- "primary-hover": "Hover state for primary elements"
2149
+ "primary-hover": "Hover state for primary elements",
2150
+ secondary: "Secondary brand color, supporting elements"
2090
2151
  };
2152
+ const addedTokens = /* @__PURE__ */ new Set();
2091
2153
  if (input.themeData?.palette) {
2092
2154
  const modeKey = input.themeMode || "dark";
2093
2155
  for (const [name, values] of Object.entries(input.themeData.palette)) {
2094
- const val = values[modeKey] || values.dark || values.light || Object.values(values)[0];
2095
- lines.push(`| \`--d-${name}\` | \`${val}\` | ${semanticRoles[name] || ""} |`);
2156
+ if (!addedTokens.has(name)) {
2157
+ addedTokens.add(name);
2158
+ const val = values[modeKey] || values.dark || values.light || Object.values(values)[0];
2159
+ lines.push(`| \`--d-${name}\` | \`${val}\` | ${semanticRoles[name] || ""} |`);
2160
+ }
2096
2161
  }
2097
2162
  }
2098
- if (input.themeData?.seed?.accent) {
2163
+ if (input.themeData?.seed?.accent && !addedTokens.has("accent")) {
2164
+ addedTokens.add("accent");
2099
2165
  lines.push(`| \`--d-accent\` | \`${input.themeData.seed.accent}\` | CTAs, links, active states, glow effects |`);
2100
2166
  }
2167
+ if (!addedTokens.has("accent-glow")) {
2168
+ const accentGlowVal = input.themeData?.palette?.["accent-glow"]?.[input.themeMode || "dark"] || input.themeData?.tokens?.base?.["accent-glow"];
2169
+ if (accentGlowVal) {
2170
+ addedTokens.add("accent-glow");
2171
+ lines.push(`| \`--d-accent-glow\` | \`${accentGlowVal}\` | Ambient glow effect around accent elements |`);
2172
+ }
2173
+ }
2101
2174
  lines.push("");
2102
2175
  lines.push("Full token set: `src/styles/tokens.css`");
2103
2176
  lines.push("");
@@ -2137,7 +2210,11 @@ function generateSectionContext(input) {
2137
2210
  }
2138
2211
  if (themeHints) {
2139
2212
  if (themeHints.preferred && themeHints.preferred.length > 0) {
2140
- lines.push(`**Preferred:** ${themeHints.preferred.join(", ")}`);
2213
+ const sectionPatterns = new Set(section.pages.flatMap((p) => p.layout.map((l) => typeof l === "string" ? l : l.pattern)));
2214
+ const relevant = themeHints.preferred.filter((p) => sectionPatterns.has(p));
2215
+ if (relevant.length > 0) {
2216
+ lines.push(`**Preferred:** ${relevant.join(", ")}`);
2217
+ }
2141
2218
  }
2142
2219
  if (themeHints.compositions) {
2143
2220
  lines.push(`**Compositions:** ${themeHints.compositions}`);
@@ -9,7 +9,7 @@ import {
9
9
  scaffoldMinimal,
10
10
  scaffoldProject,
11
11
  syncRegistry
12
- } from "./chunk-7QOXORFL.js";
12
+ } from "./chunk-AFX57QLI.js";
13
13
 
14
14
  // src/index.ts
15
15
  import { readFileSync as readFileSync15, existsSync as existsSync23, readdirSync as readdirSync6 } from "fs";
@@ -4332,7 +4332,7 @@ async function main() {
4332
4332
  break;
4333
4333
  }
4334
4334
  case "upgrade": {
4335
- const { cmdUpgrade } = await import("./upgrade-PKKLUMFJ.js");
4335
+ const { cmdUpgrade } = await import("./upgrade-74OUB65K.js");
4336
4336
  const applyFlag = args.includes("--apply");
4337
4337
  await cmdUpgrade(process.cwd(), { apply: applyFlag });
4338
4338
  break;
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import "./chunk-TL5VMEPJ.js";
2
- import "./chunk-7QOXORFL.js";
1
+ import "./chunk-NH3YWDNG.js";
2
+ import "./chunk-AFX57QLI.js";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  RegistryClient,
3
3
  refreshDerivedFiles
4
- } from "./chunk-7QOXORFL.js";
4
+ } from "./chunk-AFX57QLI.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.6.2",
3
+ "version": "1.6.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": {
@@ -2,7 +2,7 @@
2
2
 
3
3
  **Enforcement Tier: Strict**
4
4
 
5
- You are modifying existing code in a Decantr project. ALL 8 guard rules are enforced exactly.
5
+ You are modifying existing code in a Decantr project. ALL 7 guard rules are enforced exactly.
6
6
 
7
7
  ---
8
8
 
@@ -16,7 +16,7 @@ You are modifying existing code in a Decantr project. ALL 8 guard rules are enfo
16
16
  | 4 | DNA | **Theme-mode** | STRICT | ERROR — Code rejected |
17
17
  | 5 | Blueprint | **Structure** | STRICT | ERROR — Code rejected |
18
18
  | 6 | Blueprint | **Layout** | STRICT | ERROR — Pattern order must match exactly |
19
- | 8 | Blueprint | **Pattern-exists** | STRICT | ERROR — Code rejected |
19
+ | 7 | Blueprint | **Pattern-exists** | STRICT | ERROR — Code rejected |
20
20
 
21
21
  ## Violation Response Protocol
22
22
 
@@ -90,9 +90,8 @@ Before writing code:
90
90
  Before modifying:
91
91
 
92
92
  - [ ] Page exists in essence structure
93
- - [ ] I know the exact layout order: `{{LAYOUT}}`
93
+ - [ ] I know the layout order for the target page (check `blueprint.pages[]` or `blueprint.sections[]`)
94
94
  - [ ] I will use theme: `{{THEME_STYLE}}`
95
- - [ ] I will use theme: `{{THEME_RECIPE}}`
96
95
  - [ ] I will follow density: `{{DENSITY}}`
97
96
 
98
97
  During modification: