@decantr/cli 1.6.3 → 1.6.5

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-HWMN432I.js";
3
- import "./chunk-5MKMLONH.js";
2
+ import "./chunk-MEW5X6AP.js";
3
+ import "./chunk-GSRPDFXK.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,7 +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); }`);
248
- rules.push(`.status-ring[data-status="processing"] { border-color: var(--d-primary); }`);
265
+ rules.push(`.status-ring[data-status="processing"] { border-color: var(--d-primary); animation: pulse-ring 2s ease-in-out infinite; }`);
249
266
  rules.push(`@keyframes pulse-ring { 0% { opacity: 0.6; transform: scale(1); } 100% { opacity: 0; transform: scale(1.3); } }`);
250
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; }`);
251
268
  }
@@ -480,9 +497,6 @@ function generateTopologySection(data, personality) {
480
497
  lines.push(`**${label}** \u2014 ${zone.shell} shell`);
481
498
  lines.push(` Archetypes: ${zone.archetypes.join(", ")}`);
482
499
  lines.push(` Purpose: ${zone.descriptions.join(" ")}`);
483
- if (personality.length > 0) {
484
- lines.push(` Tone: ${personality.join(", ")}`);
485
- }
486
500
  if (zone.features.length > 0) {
487
501
  lines.push(` Features: ${zone.features.join(", ")}`);
488
502
  }
@@ -1615,11 +1629,28 @@ async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThe
1615
1629
  const contextDir = join(decantrDir, "context");
1616
1630
  mkdirSync(contextDir, { recursive: true });
1617
1631
  let storedBlueprintId;
1632
+ let storedVoice;
1618
1633
  const projectJsonFilePath = join(decantrDir, "project.json");
1634
+ let projectJsonData = {};
1619
1635
  if (existsSync(projectJsonFilePath)) {
1620
1636
  try {
1621
- const projData = JSON.parse(readFileSync(projectJsonFilePath, "utf-8"));
1622
- if (projData.blueprintId) storedBlueprintId = projData.blueprintId;
1637
+ projectJsonData = JSON.parse(readFileSync(projectJsonFilePath, "utf-8"));
1638
+ if (projectJsonData.blueprintId) storedBlueprintId = projectJsonData.blueprintId;
1639
+ if (projectJsonData.voice) storedVoice = projectJsonData.voice;
1640
+ } catch {
1641
+ }
1642
+ }
1643
+ if (!storedVoice && storedBlueprintId) {
1644
+ try {
1645
+ const bpResult = await registry.fetchBlueprint(storedBlueprintId);
1646
+ if (bpResult?.data) {
1647
+ const bpData = bpResult.data;
1648
+ if (bpData.voice) {
1649
+ storedVoice = bpData.voice;
1650
+ projectJsonData.voice = bpData.voice;
1651
+ writeFileSync(projectJsonFilePath, JSON.stringify(projectJsonData, null, 2));
1652
+ }
1653
+ }
1623
1654
  } catch {
1624
1655
  }
1625
1656
  }
@@ -1886,14 +1917,6 @@ async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThe
1886
1917
  writeFileSync(sectionContextPath, contextContent);
1887
1918
  contextFiles.push(sectionContextPath);
1888
1919
  }
1889
- let projectVoice;
1890
- if (existsSync(projectJsonFilePath)) {
1891
- try {
1892
- const projData = JSON.parse(readFileSync(projectJsonFilePath, "utf-8"));
1893
- if (projData.voice) projectVoice = projData.voice;
1894
- } catch {
1895
- }
1896
- }
1897
1920
  const routes = blueprint.routes || {};
1898
1921
  const scaffoldContent = generateScaffoldContext({
1899
1922
  appName: essence.meta.archetype || "Application",
@@ -1906,7 +1929,7 @@ async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThe
1906
1929
  constraints: essence.dna.constraints,
1907
1930
  seo: essence.meta.seo,
1908
1931
  navigation: essence.meta.navigation,
1909
- voice: projectVoice
1932
+ voice: storedVoice
1910
1933
  });
1911
1934
  const scaffoldMdPath = join(contextDir, "scaffold.md");
1912
1935
  writeFileSync(scaffoldMdPath, scaffoldContent);
@@ -2120,19 +2143,32 @@ function generateSectionContext(input) {
2120
2143
  "text-muted": "Secondary text, placeholders, labels",
2121
2144
  primary: "Brand color, key interactive, selected states",
2122
2145
  "primary-hover": "Hover state for primary elements",
2123
- secondary: "Secondary brand color, supporting elements"
2146
+ secondary: "Secondary brand color, supporting elements",
2147
+ "accent-glow": "Ambient glow effect for accent-colored elements"
2148
+ };
2149
+ const paletteToTokenName = {
2150
+ "background": "bg"
2124
2151
  };
2152
+ const addedTokens = /* @__PURE__ */ new Set();
2125
2153
  if (input.themeData?.palette) {
2126
2154
  const modeKey = input.themeMode || "dark";
2127
2155
  for (const [name, values] of Object.entries(input.themeData.palette)) {
2128
- const val = values[modeKey] || values.dark || values.light || Object.values(values)[0];
2129
- lines.push(`| \`--d-${name}\` | \`${val}\` | ${semanticRoles[name] || ""} |`);
2156
+ if (!addedTokens.has(name)) {
2157
+ addedTokens.add(name);
2158
+ const tokenName = paletteToTokenName[name] || name;
2159
+ const val = values[modeKey] || values.dark || values.light || Object.values(values)[0];
2160
+ lines.push(`| \`--d-${tokenName}\` | \`${val}\` | ${semanticRoles[name] || ""} |`);
2161
+ }
2130
2162
  }
2131
2163
  }
2132
- if (input.themeData?.seed?.accent) {
2164
+ if (input.themeData?.seed?.accent && !addedTokens.has("accent")) {
2165
+ addedTokens.add("accent");
2133
2166
  lines.push(`| \`--d-accent\` | \`${input.themeData.seed.accent}\` | CTAs, links, active states, glow effects |`);
2167
+ }
2168
+ if (!addedTokens.has("accent-glow")) {
2134
2169
  const accentGlowVal = input.themeData?.palette?.["accent-glow"]?.[input.themeMode || "dark"] || input.themeData?.tokens?.base?.["accent-glow"];
2135
2170
  if (accentGlowVal) {
2171
+ addedTokens.add("accent-glow");
2136
2172
  lines.push(`| \`--d-accent-glow\` | \`${accentGlowVal}\` | Ambient glow effect around accent elements |`);
2137
2173
  }
2138
2174
  }
@@ -9,7 +9,7 @@ import {
9
9
  scaffoldMinimal,
10
10
  scaffoldProject,
11
11
  syncRegistry
12
- } from "./chunk-5MKMLONH.js";
12
+ } from "./chunk-GSRPDFXK.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-3AAWHJGG.js");
4335
+ const { cmdUpgrade } = await import("./upgrade-WPC7QPXX.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-HWMN432I.js";
2
- import "./chunk-5MKMLONH.js";
1
+ import "./chunk-MEW5X6AP.js";
2
+ import "./chunk-GSRPDFXK.js";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  RegistryClient,
3
3
  refreshDerivedFiles
4
- } from "./chunk-5MKMLONH.js";
4
+ } from "./chunk-GSRPDFXK.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.3",
3
+ "version": "1.6.5",
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": {
@@ -16,23 +16,28 @@ You are adding new pages or features to an existing Decantr project. Guided mode
16
16
  | 4 | DNA | **Theme-mode** | ENFORCED | Theme/mode combination must be compatible |
17
17
  | 5 | Blueprint | **Structure** | ENFORCED | Page MUST exist in essence before generating code |
18
18
  | 6 | Blueprint | Layout | advisory | Pattern order is flexible |
19
- | 8 | Blueprint | **Pattern-exists** | ENFORCED | All patterns must exist in the registry |
19
+ | 7 | Blueprint | **Pattern-exists** | ENFORCED | All patterns must exist in the registry |
20
20
 
21
21
  ## Before You Start
22
22
 
23
23
  ### 1. Update the Essence
24
24
 
25
- Before generating code for a new page, add it to the essence:
25
+ Before generating code for a new page, add it to the relevant section in the essence:
26
26
 
27
27
  ```json
28
28
  {
29
29
  "blueprint": {
30
- "shell": "{{DEFAULT_SHELL}}",
31
- "pages": [
32
- // ... existing pages ...
30
+ "sections": [
33
31
  {
34
- "id": "new-page-id",
35
- "layout": ["pattern-1", "pattern-2"]
32
+ "id": "section-id",
33
+ "shell": "{{DEFAULT_SHELL}}",
34
+ "pages": [
35
+ // ... existing pages ...
36
+ {
37
+ "id": "new-page-id",
38
+ "layout": ["pattern-1", "pattern-2"]
39
+ }
40
+ ]
36
41
  }
37
42
  ]
38
43
  }
@@ -55,8 +60,8 @@ Only after the page exists in the essence should you generate code for it.
55
60
 
56
61
  Before adding a page:
57
62
 
58
- - [ ] The page ID is added to `blueprint.pages[]` in essence
59
- - [ ] The page has a `shell` defined
63
+ - [ ] The page ID is added to the target `blueprint.sections[].pages[]` in essence
64
+ - [ ] The section has a `shell` defined
60
65
  - [ ] The page has a `layout[]` with pattern IDs
61
66
  - [ ] Validation passes (`npx @decantr/cli validate`)
62
67
 
@@ -64,7 +69,7 @@ During code generation:
64
69
 
65
70
  - [ ] Use theme `{{THEME_STYLE}}` for all styling
66
71
  - [ ] Use theme `{{THEME_RECIPE}}` decorators for decoration
67
- - [ ] Follow the shell structure ({{DEFAULT_SHELL}})
72
+ - [ ] Follow the shell structure for the target section (see section context file for shell notes)
68
73
  - [ ] Include patterns from the layout array
69
74
 
70
75
  After generation:
@@ -95,7 +100,7 @@ Please confirm how you'd like to proceed.
95
100
  When adding features (auth, search, payments, etc.):
96
101
 
97
102
  1. Add the feature to `features[]` in the essence
98
- 2. Update relevant pages in `blueprint.pages[]`
103
+ 2. Update relevant pages in `blueprint.sections[].pages[]`
99
104
  3. Then implement the feature
100
105
 
101
106
  ## Pattern Selection
@@ -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: