@decantr/cli 1.5.5 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Decantr AI
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/bin.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import "./chunk-
|
|
3
|
-
import "./chunk-
|
|
2
|
+
import "./chunk-G76RSQRX.js";
|
|
3
|
+
import "./chunk-RG7F5APP.js";
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
scaffoldMinimal,
|
|
10
10
|
scaffoldProject,
|
|
11
11
|
syncRegistry
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-RG7F5APP.js";
|
|
13
13
|
|
|
14
14
|
// src/index.ts
|
|
15
15
|
import { readFileSync as readFileSync15, existsSync as existsSync23, readdirSync as readdirSync6 } from "fs";
|
|
@@ -2189,6 +2189,7 @@ ${YELLOW5}Next step:${RESET8} Ask your AI assistant to read ${BOLD3}.decantr/ana
|
|
|
2189
2189
|
// src/commands/magic.ts
|
|
2190
2190
|
import { join as join19 } from "path";
|
|
2191
2191
|
import { existsSync as existsSync19 } from "fs";
|
|
2192
|
+
import * as fs from "fs/promises";
|
|
2192
2193
|
var BOLD4 = "\x1B[1m";
|
|
2193
2194
|
var DIM9 = "\x1B[2m";
|
|
2194
2195
|
var RESET9 = "\x1B[0m";
|
|
@@ -2336,7 +2337,32 @@ function parseMagicPrompt(prompt) {
|
|
|
2336
2337
|
archetype
|
|
2337
2338
|
};
|
|
2338
2339
|
}
|
|
2339
|
-
function resolveTheme(
|
|
2340
|
+
async function resolveTheme(intent, registryClient) {
|
|
2341
|
+
const hints = intent.themeHints;
|
|
2342
|
+
if (registryClient) {
|
|
2343
|
+
try {
|
|
2344
|
+
const themes = await registryClient.fetchThemes();
|
|
2345
|
+
if (themes && themes.length > 0) {
|
|
2346
|
+
const scored = themes.map((t) => {
|
|
2347
|
+
let score = 0;
|
|
2348
|
+
const personality = (t.personality || "").toLowerCase();
|
|
2349
|
+
const tags = (t.tags || []).map((tag) => tag.toLowerCase());
|
|
2350
|
+
for (const hint of intent.themeHints) {
|
|
2351
|
+
if (personality.includes(hint)) score += 3;
|
|
2352
|
+
if (tags.some((tag) => tag.includes(hint))) score += 2;
|
|
2353
|
+
}
|
|
2354
|
+
if (intent.themeHints.includes("dark") && t.modes?.includes("dark")) score += 1;
|
|
2355
|
+
if (intent.themeHints.includes("light") && t.modes?.includes("light")) score += 1;
|
|
2356
|
+
return { id: t.id || t.slug, score, modes: t.modes };
|
|
2357
|
+
}).sort((a, b) => b.score - a.score);
|
|
2358
|
+
if (scored[0] && scored[0].score > 0) {
|
|
2359
|
+
const mode2 = intent.themeHints.includes("light") ? "light" : intent.themeHints.includes("dark") ? "dark" : scored[0].modes?.includes("dark") ? "dark" : "light";
|
|
2360
|
+
return { style: scored[0].id, mode: mode2 };
|
|
2361
|
+
}
|
|
2362
|
+
}
|
|
2363
|
+
} catch {
|
|
2364
|
+
}
|
|
2365
|
+
}
|
|
2340
2366
|
let mode = "dark";
|
|
2341
2367
|
if (hints.includes("light")) mode = "light";
|
|
2342
2368
|
if (hints.includes("neon") || hints.includes("glass")) return { style: "obsidianite", mode };
|
|
@@ -2358,6 +2384,18 @@ function buildPersonality(intent) {
|
|
|
2358
2384
|
if (intent.themeHints.includes("playful")) return ["friendly", "energetic"];
|
|
2359
2385
|
return ["professional"];
|
|
2360
2386
|
}
|
|
2387
|
+
function buildRichPersonality(intent, blueprintData, themeData) {
|
|
2388
|
+
const parts = [];
|
|
2389
|
+
if (blueprintData?.personality && typeof blueprintData.personality === "string")
|
|
2390
|
+
parts.push(blueprintData.personality);
|
|
2391
|
+
if (intent.personalityHints.length > 0 && !parts.some((p) => intent.personalityHints.every((h) => p.toLowerCase().includes(h))))
|
|
2392
|
+
parts.push(`Visual character: ${intent.personalityHints.join(", ")}.`);
|
|
2393
|
+
if (themeData?.personality && !parts.some((p) => p.toLowerCase().includes(themeData.personality.toLowerCase())))
|
|
2394
|
+
parts.push(`Theme influence: ${themeData.personality}.`);
|
|
2395
|
+
if (parts.length === 0)
|
|
2396
|
+
parts.push(`Modern, production-ready ${intent.description}. Clean typography, intentional spacing, polished interactions.`);
|
|
2397
|
+
return parts.join(" ");
|
|
2398
|
+
}
|
|
2361
2399
|
async function cmdMagic(prompt, projectRoot, options) {
|
|
2362
2400
|
console.log("");
|
|
2363
2401
|
console.log(`${MAGENTA}${BOLD4} Decantr Magic${RESET9}`);
|
|
@@ -2435,7 +2473,7 @@ async function cmdMagic(prompt, projectRoot, options) {
|
|
|
2435
2473
|
} else {
|
|
2436
2474
|
console.log(dim(" Offline mode \u2014 using defaults."));
|
|
2437
2475
|
}
|
|
2438
|
-
const themeResolved = resolveTheme(intent
|
|
2476
|
+
const themeResolved = await resolveTheme(intent, apiAvailable ? registryClient : void 0);
|
|
2439
2477
|
const personality = buildPersonality(intent);
|
|
2440
2478
|
const initOptions = {
|
|
2441
2479
|
blueprint: matchedBlueprint,
|
|
@@ -2463,17 +2501,28 @@ async function cmdMagic(prompt, projectRoot, options) {
|
|
|
2463
2501
|
initOptions.personality = [...merged];
|
|
2464
2502
|
}
|
|
2465
2503
|
}
|
|
2504
|
+
if (intent.constraints.includes("accessible")) {
|
|
2505
|
+
initOptions.accessibility = { wcag_level: "AA" };
|
|
2506
|
+
}
|
|
2507
|
+
if (intent.constraints.includes("mobile-first")) {
|
|
2508
|
+
initOptions.density = "comfortable";
|
|
2509
|
+
}
|
|
2510
|
+
if (intent.constraints.includes("real-time")) {
|
|
2511
|
+
initOptions.features = [...initOptions.features || [], "websockets", "live-updates"];
|
|
2512
|
+
}
|
|
2466
2513
|
if (options.dryRun) {
|
|
2514
|
+
const personalityStr = initOptions.personality.join(". ");
|
|
2467
2515
|
console.log("");
|
|
2468
|
-
console.log(`${
|
|
2469
|
-
console.log("");
|
|
2470
|
-
console.log(`
|
|
2471
|
-
console.log(`
|
|
2472
|
-
console.log(`
|
|
2473
|
-
console.log(`
|
|
2474
|
-
console.log(`
|
|
2475
|
-
|
|
2476
|
-
|
|
2516
|
+
console.log(`${BOLD4}decantr magic preview${RESET9}`);
|
|
2517
|
+
console.log("\u2500".repeat(60));
|
|
2518
|
+
console.log(` Blueprint: ${matchedBlueprint || "none (archetype-direct)"}`);
|
|
2519
|
+
console.log(` Theme: ${initOptions.theme} (${initOptions.mode}${initOptions.shape ? ", " + initOptions.shape : ""})`);
|
|
2520
|
+
console.log(` Archetype: ${initOptions.archetype || "auto-detected"}`);
|
|
2521
|
+
console.log(` Personality: ${personalityStr.slice(0, 80)}${personalityStr.length > 80 ? "..." : ""}`);
|
|
2522
|
+
console.log(` WCAG: ${initOptions.accessibility?.wcag_level || "AA"} | Density: ${initOptions.density} | Guard: ${initOptions.guard}`);
|
|
2523
|
+
if (intent.constraints.length > 0)
|
|
2524
|
+
console.log(` Constraints: ${intent.constraints.join(", ")}`);
|
|
2525
|
+
console.log("\u2500".repeat(60));
|
|
2477
2526
|
return;
|
|
2478
2527
|
}
|
|
2479
2528
|
console.log("");
|
|
@@ -2625,6 +2674,10 @@ async function cmdMagic(prompt, projectRoot, options) {
|
|
|
2625
2674
|
};
|
|
2626
2675
|
}
|
|
2627
2676
|
}
|
|
2677
|
+
const richPersonality = buildRichPersonality(intent, blueprintData, themeData);
|
|
2678
|
+
if (richPersonality) {
|
|
2679
|
+
initOptions.personality = [richPersonality];
|
|
2680
|
+
}
|
|
2628
2681
|
console.log(`${BOLD4} Scaffolding...${RESET9}`);
|
|
2629
2682
|
const result = await scaffoldProject(
|
|
2630
2683
|
projectRoot,
|
|
@@ -2664,6 +2717,25 @@ async function cmdMagic(prompt, projectRoot, options) {
|
|
|
2664
2717
|
if (result.gitignoreUpdated) {
|
|
2665
2718
|
console.log(` ${dim(".gitignore updated")}`);
|
|
2666
2719
|
}
|
|
2720
|
+
const contextDir = join19(projectRoot, ".decantr", "context");
|
|
2721
|
+
let sectionCount = 0;
|
|
2722
|
+
try {
|
|
2723
|
+
const files = await fs.readdir(contextDir);
|
|
2724
|
+
sectionCount = files.filter((f) => f.startsWith("section-")).length;
|
|
2725
|
+
} catch {
|
|
2726
|
+
}
|
|
2727
|
+
const treatmentsPath = join19(projectRoot, "src", "styles", "treatments.css");
|
|
2728
|
+
let hasLayers = false;
|
|
2729
|
+
try {
|
|
2730
|
+
const css = await fs.readFile(treatmentsPath, "utf-8");
|
|
2731
|
+
hasLayers = css.includes("@layer");
|
|
2732
|
+
} catch {
|
|
2733
|
+
}
|
|
2734
|
+
console.log(`
|
|
2735
|
+
${GREEN9}${BOLD4}Quality summary:${RESET9}`);
|
|
2736
|
+
console.log(` Context files: ${sectionCount} sections + scaffold.md + DECANTR.md`);
|
|
2737
|
+
console.log(` CSS: tokens.css + treatments.css + global.css`);
|
|
2738
|
+
console.log(` @layer cascade: ${hasLayers ? GREEN9 + "yes" + RESET9 : YELLOW6 + "missing" + RESET9}`);
|
|
2667
2739
|
console.log("");
|
|
2668
2740
|
console.log(`${BOLD4} Ready!${RESET9} Next steps:`);
|
|
2669
2741
|
console.log(` 1. Read ${cyan("DECANTR.md")} to understand the design system`);
|
|
@@ -3576,12 +3648,22 @@ ${YELLOW9}You're offline. Scaffolding Decantr default.${RESET13}`);
|
|
|
3576
3648
|
const blueprints = blueprintsResult.data.items;
|
|
3577
3649
|
const themes = themesResult.data.items;
|
|
3578
3650
|
let options;
|
|
3651
|
+
const userExplicit = {
|
|
3652
|
+
theme: Boolean(args.theme),
|
|
3653
|
+
mode: Boolean(args.mode),
|
|
3654
|
+
shape: Boolean(args.shape),
|
|
3655
|
+
personality: Boolean(args.personality)
|
|
3656
|
+
};
|
|
3579
3657
|
if (args.yes || selectedBlueprint !== "default") {
|
|
3580
3658
|
const flags = parseFlags(args, detected);
|
|
3581
3659
|
flags.blueprint = selectedBlueprint !== "default" ? selectedBlueprint : flags.blueprint;
|
|
3582
3660
|
options = mergeWithDefaults(flags, detected);
|
|
3583
3661
|
} else {
|
|
3584
3662
|
options = await runInteractivePrompts(detected, archetypes, blueprints, themes);
|
|
3663
|
+
userExplicit.theme = true;
|
|
3664
|
+
userExplicit.mode = true;
|
|
3665
|
+
userExplicit.shape = true;
|
|
3666
|
+
userExplicit.personality = true;
|
|
3585
3667
|
}
|
|
3586
3668
|
let topologyMarkdown = "";
|
|
3587
3669
|
let archetypeData;
|
|
@@ -3592,20 +3674,19 @@ ${YELLOW9}You're offline. Scaffolding Decantr default.${RESET13}`);
|
|
|
3592
3674
|
if (options.blueprint) {
|
|
3593
3675
|
const blueprintResult = await registryClient.fetchBlueprint(options.blueprint);
|
|
3594
3676
|
if (blueprintResult) {
|
|
3595
|
-
const
|
|
3596
|
-
const blueprint = rawBlueprint.data ?? rawBlueprint;
|
|
3677
|
+
const blueprint = blueprintResult.data;
|
|
3597
3678
|
if (blueprint.theme) {
|
|
3598
|
-
if ((blueprint.theme.id || blueprint.theme.style)
|
|
3679
|
+
if (!userExplicit.theme && (blueprint.theme.id || blueprint.theme.style)) {
|
|
3599
3680
|
options.theme = blueprint.theme.id || blueprint.theme.style;
|
|
3600
3681
|
}
|
|
3601
|
-
if (
|
|
3682
|
+
if (!userExplicit.mode && blueprint.theme.mode) {
|
|
3602
3683
|
options.mode = blueprint.theme.mode;
|
|
3603
3684
|
}
|
|
3604
|
-
if (
|
|
3685
|
+
if (!userExplicit.shape && blueprint.theme.shape) {
|
|
3605
3686
|
options.shape = blueprint.theme.shape;
|
|
3606
3687
|
}
|
|
3607
3688
|
}
|
|
3608
|
-
if (
|
|
3689
|
+
if (!userExplicit.personality && blueprint.personality) {
|
|
3609
3690
|
options.personality = typeof blueprint.personality === "string" ? [blueprint.personality] : blueprint.personality;
|
|
3610
3691
|
}
|
|
3611
3692
|
if (blueprint.compose && blueprint.compose.length > 0) {
|
|
@@ -3614,9 +3695,7 @@ ${YELLOW9}You're offline. Scaffolding Decantr default.${RESET13}`);
|
|
|
3614
3695
|
for (const entry of entries) {
|
|
3615
3696
|
const id = typeof entry === "string" ? entry : entry.archetype;
|
|
3616
3697
|
const r = await registryClient.fetchArchetype(id);
|
|
3617
|
-
|
|
3618
|
-
const inner = raw?.data ?? raw;
|
|
3619
|
-
results.push([id, inner]);
|
|
3698
|
+
results.push([id, r?.data ?? null]);
|
|
3620
3699
|
}
|
|
3621
3700
|
const archetypeMap = new Map(results.map(([id, data]) => [id, data || null]));
|
|
3622
3701
|
const composed = composeArchetypes(entries, archetypeMap);
|
|
@@ -3664,8 +3743,7 @@ ${YELLOW9}You're offline. Scaffolding Decantr default.${RESET13}`);
|
|
|
3664
3743
|
try {
|
|
3665
3744
|
const result2 = await registryClient.fetchPattern(pid);
|
|
3666
3745
|
if (result2) {
|
|
3667
|
-
const
|
|
3668
|
-
const inner = raw.data ?? raw;
|
|
3746
|
+
const inner = result2.data;
|
|
3669
3747
|
const defaultPreset = inner.default_preset || "standard";
|
|
3670
3748
|
const preset = inner.presets?.[defaultPreset];
|
|
3671
3749
|
patternSpecs[pid] = {
|
|
@@ -3717,8 +3795,7 @@ ${YELLOW9}You're offline. Scaffolding Decantr default.${RESET13}`);
|
|
|
3717
3795
|
} else if (options.archetype) {
|
|
3718
3796
|
const archetypeResult = await registryClient.fetchArchetype(options.archetype);
|
|
3719
3797
|
if (archetypeResult) {
|
|
3720
|
-
|
|
3721
|
-
archetypeData = rawArch.data ?? rawArch;
|
|
3798
|
+
archetypeData = archetypeResult.data;
|
|
3722
3799
|
} else {
|
|
3723
3800
|
console.log(`${YELLOW9} Warning: Could not fetch archetype "${options.archetype}". Using defaults.${RESET13}`);
|
|
3724
3801
|
}
|
|
@@ -3727,8 +3804,7 @@ ${YELLOW9}You're offline. Scaffolding Decantr default.${RESET13}`);
|
|
|
3727
3804
|
if (options.theme) {
|
|
3728
3805
|
const themeResult = await registryClient.fetchTheme(options.theme);
|
|
3729
3806
|
if (themeResult) {
|
|
3730
|
-
const
|
|
3731
|
-
const theme = rawTheme.data ?? rawTheme;
|
|
3807
|
+
const theme = themeResult.data;
|
|
3732
3808
|
themeData = {
|
|
3733
3809
|
seed: theme.seed,
|
|
3734
3810
|
palette: theme.palette,
|
|
@@ -4256,7 +4332,7 @@ async function main() {
|
|
|
4256
4332
|
break;
|
|
4257
4333
|
}
|
|
4258
4334
|
case "upgrade": {
|
|
4259
|
-
const { cmdUpgrade } = await import("./upgrade-
|
|
4335
|
+
const { cmdUpgrade } = await import("./upgrade-PRABSTXX.js");
|
|
4260
4336
|
const applyFlag = args.includes("--apply");
|
|
4261
4337
|
await cmdUpgrade(process.cwd(), { apply: applyFlag });
|
|
4262
4338
|
break;
|
|
@@ -9,6 +9,8 @@ function generateTreatmentCSS(spatialTokens, treatmentOverrides, themeDecorators
|
|
|
9
9
|
const lines = [];
|
|
10
10
|
lines.push("/* Generated by @decantr/cli \u2014 Visual Treatment System */");
|
|
11
11
|
lines.push("");
|
|
12
|
+
lines.push("@layer treatments {");
|
|
13
|
+
lines.push("");
|
|
12
14
|
lines.push("/* \u2500\u2500 Layer 1: Base Treatments \u2500\u2500 */");
|
|
13
15
|
lines.push("");
|
|
14
16
|
function emitRule(selector, props) {
|
|
@@ -202,16 +204,6 @@ function generateTreatmentCSS(spatialTokens, treatmentOverrides, themeDecorators
|
|
|
202
204
|
["color", "var(--d-text-muted)"],
|
|
203
205
|
["font-family", "var(--d-font-mono, ui-monospace, monospace)"]
|
|
204
206
|
]);
|
|
205
|
-
if (themeDecorators && Object.keys(themeDecorators).length > 0) {
|
|
206
|
-
const label = themeName ? ` (${themeName})` : "";
|
|
207
|
-
lines.push(`/* \u2500\u2500 Layer 3: Theme Decorators${label} \u2500\u2500 */`);
|
|
208
|
-
lines.push("");
|
|
209
|
-
for (const [name, description] of Object.entries(themeDecorators)) {
|
|
210
|
-
const rule = generateDecoratorRule(name, description);
|
|
211
|
-
lines.push(rule);
|
|
212
|
-
lines.push("");
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
207
|
lines.push("/* \u2500\u2500 Keyframes \u2500\u2500 */");
|
|
216
208
|
lines.push("");
|
|
217
209
|
lines.push("@keyframes decantr-fade-in {");
|
|
@@ -223,6 +215,22 @@ function generateTreatmentCSS(spatialTokens, treatmentOverrides, themeDecorators
|
|
|
223
215
|
lines.push(" 0%, 100% { opacity: 1; }");
|
|
224
216
|
lines.push(" 50% { opacity: 0.5; }");
|
|
225
217
|
lines.push("}");
|
|
218
|
+
lines.push("");
|
|
219
|
+
lines.push("} /* end @layer treatments */");
|
|
220
|
+
if (themeDecorators && Object.keys(themeDecorators).length > 0) {
|
|
221
|
+
const label = themeName ? ` (${themeName})` : "";
|
|
222
|
+
lines.push("");
|
|
223
|
+
lines.push("@layer decorators {");
|
|
224
|
+
lines.push("");
|
|
225
|
+
lines.push(`/* \u2500\u2500 Layer 3: Theme Decorators${label} \u2500\u2500 */`);
|
|
226
|
+
lines.push("");
|
|
227
|
+
for (const [name, description] of Object.entries(themeDecorators)) {
|
|
228
|
+
const rule = generateDecoratorRule(name, description);
|
|
229
|
+
lines.push(rule);
|
|
230
|
+
lines.push("");
|
|
231
|
+
}
|
|
232
|
+
lines.push("} /* end @layer decorators */");
|
|
233
|
+
}
|
|
226
234
|
return lines.join("\n");
|
|
227
235
|
}
|
|
228
236
|
function generatePersonalityCSS(personality, themeData) {
|
|
@@ -252,7 +260,7 @@ function generatePersonalityCSS(personality, themeData) {
|
|
|
252
260
|
rules.push(`@keyframes decantr-entrance { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } }`);
|
|
253
261
|
}
|
|
254
262
|
if (rules.length === 0) return "";
|
|
255
|
-
return "\n/* \u2500\u2500 Personality-Derived Utilities \u2500\u2500 */\n\n" + rules.join("\n\n") + "\n";
|
|
263
|
+
return "\n@layer utilities {\n\n/* \u2500\u2500 Personality-Derived Utilities \u2500\u2500 */\n\n" + rules.join("\n\n") + "\n\n} /* end @layer utilities */\n";
|
|
256
264
|
}
|
|
257
265
|
|
|
258
266
|
// src/scaffold.ts
|
|
@@ -509,6 +517,7 @@ function generateTokensCSS(themeData, mode, spatialTokens) {
|
|
|
509
517
|
if (!themeData) {
|
|
510
518
|
const spatialLines2 = spatialTokens ? "\n" + Object.entries(spatialTokens).map(([k, v]) => ` ${k}: ${v};`).join("\n") : "";
|
|
511
519
|
return `/* No theme data available */
|
|
520
|
+
@layer tokens {
|
|
512
521
|
:root {
|
|
513
522
|
--d-primary: #6366f1;
|
|
514
523
|
--d-secondary: #a1a1aa;
|
|
@@ -520,6 +529,7 @@ function generateTokensCSS(themeData, mode, spatialTokens) {
|
|
|
520
529
|
--d-text: #fafafa;
|
|
521
530
|
--d-text-muted: #a1a1aa;${spatialLines2}
|
|
522
531
|
}
|
|
532
|
+
}
|
|
523
533
|
`;
|
|
524
534
|
}
|
|
525
535
|
const seed = themeData.seed || {};
|
|
@@ -584,6 +594,7 @@ function generateTokensCSS(themeData, mode, spatialTokens) {
|
|
|
584
594
|
const lines = Object.entries(tokens).map(([key, value]) => ` ${key}: ${value};`).join("\n");
|
|
585
595
|
const spatialLines = spatialTokens ? "\n" + Object.entries(spatialTokens).map(([k, v]) => ` ${k}: ${v};`).join("\n") : "";
|
|
586
596
|
let css = `/* Generated by @decantr/cli */
|
|
597
|
+
@layer tokens {
|
|
587
598
|
:root {
|
|
588
599
|
${lines}${spatialLines}
|
|
589
600
|
}
|
|
@@ -612,9 +623,11 @@ ${lightLines}
|
|
|
612
623
|
}
|
|
613
624
|
`;
|
|
614
625
|
}
|
|
626
|
+
css += `}
|
|
627
|
+
`;
|
|
615
628
|
return css;
|
|
616
629
|
}
|
|
617
|
-
function generateGlobalCSS(personality) {
|
|
630
|
+
function generateGlobalCSS(personality, essence) {
|
|
618
631
|
const personalityText = personality.join(" ").toLowerCase();
|
|
619
632
|
let fontBody = "system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif";
|
|
620
633
|
if (personalityText.includes("inter")) {
|
|
@@ -622,7 +635,12 @@ function generateGlobalCSS(personality) {
|
|
|
622
635
|
} else if (personalityText.includes("geist")) {
|
|
623
636
|
fontBody = `'Geist', ${fontBody}`;
|
|
624
637
|
}
|
|
638
|
+
const mode = essence?.dna?.theme?.mode || "dark";
|
|
639
|
+
const colorScheme = mode === "auto" ? "light dark" : mode;
|
|
625
640
|
return `/* Generated by @decantr/cli \u2014 global reset + body styles */
|
|
641
|
+
@layer reset, tokens, treatments, decorators, utilities, app;
|
|
642
|
+
|
|
643
|
+
@layer reset {
|
|
626
644
|
|
|
627
645
|
*, *::before, *::after {
|
|
628
646
|
box-sizing: border-box;
|
|
@@ -631,7 +649,7 @@ function generateGlobalCSS(personality) {
|
|
|
631
649
|
}
|
|
632
650
|
|
|
633
651
|
html {
|
|
634
|
-
color-scheme:
|
|
652
|
+
color-scheme: ${colorScheme};
|
|
635
653
|
-webkit-font-smoothing: antialiased;
|
|
636
654
|
-moz-osx-font-smoothing: grayscale;
|
|
637
655
|
text-rendering: optimizeLegibility;
|
|
@@ -671,6 +689,8 @@ input, button, textarea, select {
|
|
|
671
689
|
white-space: nowrap;
|
|
672
690
|
border-width: 0;
|
|
673
691
|
}
|
|
692
|
+
|
|
693
|
+
}
|
|
674
694
|
`;
|
|
675
695
|
}
|
|
676
696
|
function generateDecoratorRule(name, description) {
|
|
@@ -1081,22 +1101,173 @@ Atoms + treatment + theme decorator:
|
|
|
1081
1101
|
- **Theme decorators:** \`carbon-glass\`, \`carbon-code\` \u2014 theme-specific decoration from treatments.css
|
|
1082
1102
|
- **Combined:** \`css('_flex _col') + ' d-surface carbon-card'\`
|
|
1083
1103
|
|
|
1084
|
-
###
|
|
1104
|
+
### Atom Reference
|
|
1105
|
+
|
|
1106
|
+
#### Display
|
|
1107
|
+
| Atom | CSS |
|
|
1108
|
+
|------|-----|
|
|
1109
|
+
| \`_flex\` | \`display:flex\` |
|
|
1110
|
+
| \`_grid\` | \`display:grid\` |
|
|
1111
|
+
| \`_block\` | \`display:block\` |
|
|
1112
|
+
| \`_inline\` | \`display:inline\` |
|
|
1113
|
+
| \`_inlineflex\` | \`display:inline-flex\` |
|
|
1114
|
+
| \`_none\` | \`display:none\` |
|
|
1115
|
+
| \`_contents\` | \`display:contents\` |
|
|
1116
|
+
|
|
1117
|
+
#### Flexbox
|
|
1118
|
+
| Atom | CSS |
|
|
1119
|
+
|------|-----|
|
|
1120
|
+
| \`_col\` | \`flex-direction:column\` |
|
|
1121
|
+
| \`_row\` | \`flex-direction:row\` |
|
|
1122
|
+
| \`_colrev\` | \`flex-direction:column-reverse\` |
|
|
1123
|
+
| \`_wrap\` | \`flex-wrap:wrap\` |
|
|
1124
|
+
| \`_nowrap\` | \`flex-wrap:nowrap\` |
|
|
1125
|
+
| \`_flex1\` | \`flex:1\` |
|
|
1126
|
+
| \`_flex0\` | \`flex:none\` |
|
|
1127
|
+
| \`_flexauto\` | \`flex:auto\` |
|
|
1128
|
+
| \`_grow\` | \`flex-grow:1\` |
|
|
1129
|
+
| \`_grow0\` | \`flex-grow:0\` |
|
|
1130
|
+
| \`_shrink0\` | \`flex-shrink:0\` |
|
|
1131
|
+
|
|
1132
|
+
#### Alignment
|
|
1133
|
+
| Atom | CSS |
|
|
1134
|
+
|------|-----|
|
|
1135
|
+
| \`_aic\` | \`align-items:center\` |
|
|
1136
|
+
| \`_aifs\` | \`align-items:flex-start\` |
|
|
1137
|
+
| \`_aife\` | \`align-items:flex-end\` |
|
|
1138
|
+
| \`_aist\` | \`align-items:stretch\` |
|
|
1139
|
+
| \`_aibl\` | \`align-items:baseline\` |
|
|
1140
|
+
| \`_jcc\` | \`justify-content:center\` |
|
|
1141
|
+
| \`_jcfs\` | \`justify-content:flex-start\` |
|
|
1142
|
+
| \`_jcfe\` | \`justify-content:flex-end\` |
|
|
1143
|
+
| \`_jcsb\` | \`justify-content:space-between\` |
|
|
1144
|
+
| \`_jcsa\` | \`justify-content:space-around\` |
|
|
1145
|
+
| \`_jcse\` | \`justify-content:space-evenly\` |
|
|
1146
|
+
| \`_pic\` | \`place-items:center\` |
|
|
1147
|
+
| \`_pcc\` | \`place-content:center\` |
|
|
1148
|
+
|
|
1149
|
+
#### Spacing (scale: 0, 1, 2, 3, 4, 5, 6, 8, 10, 12, 16, 20, 24, ...)
|
|
1150
|
+
| Atom | CSS | Notes |
|
|
1151
|
+
|------|-----|-------|
|
|
1152
|
+
| \`_gap{n}\` | \`gap:{scale}\` | e.g. \`_gap4\` = \`gap:1rem\` |
|
|
1153
|
+
| \`_gx{n}\` | \`column-gap:{scale}\` | horizontal gap |
|
|
1154
|
+
| \`_gy{n}\` | \`row-gap:{scale}\` | vertical gap |
|
|
1155
|
+
| \`_p{n}\` | \`padding:{scale}\` | all sides |
|
|
1156
|
+
| \`_pt{n}\`, \`_pr{n}\`, \`_pb{n}\`, \`_pl{n}\` | directional padding | top/right/bottom/left |
|
|
1157
|
+
| \`_px{n}\` | \`padding-inline:{scale}\` | horizontal |
|
|
1158
|
+
| \`_py{n}\` | \`padding-block:{scale}\` | vertical |
|
|
1159
|
+
| \`_m{n}\` | \`margin:{scale}\` | same as padding variants |
|
|
1160
|
+
| \`_mx{n}\`, \`_my{n}\` | inline/block margin | horizontal/vertical |
|
|
1085
1161
|
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
|
1090
|
-
|
|
|
1091
|
-
|
|
|
1092
|
-
|
|
|
1093
|
-
|
|
|
1094
|
-
|
|
|
1095
|
-
|
|
|
1096
|
-
|
|
|
1097
|
-
|
|
|
1162
|
+
#### Sizing
|
|
1163
|
+
| Atom | CSS |
|
|
1164
|
+
|------|-----|
|
|
1165
|
+
| \`_wfull\` / \`_w100\` | \`width:100%\` |
|
|
1166
|
+
| \`_hfull\` / \`_h100\` | \`height:100%\` |
|
|
1167
|
+
| \`_wscreen\` | \`width:100vw\` |
|
|
1168
|
+
| \`_hscreen\` | \`height:100vh\` |
|
|
1169
|
+
| \`_wfit\` | \`width:fit-content\` |
|
|
1170
|
+
| \`_hfit\` | \`height:fit-content\` |
|
|
1171
|
+
| \`_wauto\` | \`width:auto\` |
|
|
1172
|
+
| \`_minw0\` | \`min-width:0\` |
|
|
1173
|
+
| \`_minh0\` | \`min-height:0\` |
|
|
1174
|
+
| \`_w{n}\`, \`_h{n}\` | width/height from spacing scale |
|
|
1175
|
+
| \`_minw{n}\`, \`_maxw{n}\` | min/max width from scale |
|
|
1098
1176
|
|
|
1099
|
-
|
|
1177
|
+
#### Text Size
|
|
1178
|
+
| Atom | Size | Line-height |
|
|
1179
|
+
|------|------|-------------|
|
|
1180
|
+
| \`_textxs\` | 0.75rem | 1rem |
|
|
1181
|
+
| \`_textsm\` | 0.875rem | 1.25rem |
|
|
1182
|
+
| \`_textbase\` | 1rem | 1.5rem |
|
|
1183
|
+
| \`_textlg\` | 1.125rem | 1.75rem |
|
|
1184
|
+
| \`_textxl\` | 1.25rem | 1.75rem |
|
|
1185
|
+
| \`_text2xl\` | 1.5rem | 2rem |
|
|
1186
|
+
| \`_text3xl\` | 1.875rem | 2.25rem |
|
|
1187
|
+
| \`_heading1\`-\`_heading6\` | Heading presets (size + weight) |
|
|
1188
|
+
|
|
1189
|
+
#### Text Style
|
|
1190
|
+
| Atom | CSS |
|
|
1191
|
+
|------|-----|
|
|
1192
|
+
| \`_fontbold\` | \`font-weight:700\` |
|
|
1193
|
+
| \`_fontsemi\` | \`font-weight:600\` |
|
|
1194
|
+
| \`_fontmedium\` | \`font-weight:500\` |
|
|
1195
|
+
| \`_fontlight\` | \`font-weight:300\` |
|
|
1196
|
+
| \`_italic\` | \`font-style:italic\` |
|
|
1197
|
+
| \`_underline\` | \`text-decoration:underline\` |
|
|
1198
|
+
| \`_uppercase\` | \`text-transform:uppercase\` |
|
|
1199
|
+
| \`_truncate\` | overflow ellipsis + nowrap |
|
|
1200
|
+
| \`_textl\`, \`_textc\`, \`_textr\` | text-align left/center/right |
|
|
1201
|
+
|
|
1202
|
+
#### Color (theme variable based)
|
|
1203
|
+
| Atom | CSS |
|
|
1204
|
+
|------|-----|
|
|
1205
|
+
| \`_bgprimary\` | \`background:var(--d-primary)\` |
|
|
1206
|
+
| \`_bgsurface\` | \`background:var(--d-surface)\` |
|
|
1207
|
+
| \`_bgsurface0\`-\`_bgsurface2\` | surface elevation layers |
|
|
1208
|
+
| \`_bgmuted\` | \`background:var(--d-muted)\` |
|
|
1209
|
+
| \`_bgbg\` | \`background:var(--d-bg)\` |
|
|
1210
|
+
| \`_bgsuccess\`, \`_bgerror\`, \`_bgwarning\`, \`_bginfo\` | status backgrounds |
|
|
1211
|
+
| \`_fgprimary\` | \`color:var(--d-primary)\` |
|
|
1212
|
+
| \`_fgtext\` | \`color:var(--d-text)\` |
|
|
1213
|
+
| \`_fgmuted\` | \`color:var(--d-text-muted)\` |
|
|
1214
|
+
| \`_fgsuccess\`, \`_fgerror\`, \`_fgwarning\`, \`_fginfo\` | status text |
|
|
1215
|
+
| \`_bcborder\` | \`border-color:var(--d-border)\` |
|
|
1216
|
+
|
|
1217
|
+
#### Overflow & Whitespace
|
|
1218
|
+
| Atom | CSS |
|
|
1219
|
+
|------|-----|
|
|
1220
|
+
| \`_overhidden\` | \`overflow:hidden\` |
|
|
1221
|
+
| \`_overauto\` | \`overflow:auto\` |
|
|
1222
|
+
| \`_overscroll\` | \`overflow:scroll\` |
|
|
1223
|
+
| \`_overxauto\`, \`_overyauto\` | axis-specific overflow |
|
|
1224
|
+
| \`_nowraptext\` | \`white-space:nowrap\` |
|
|
1225
|
+
| \`_prewrap\` | \`white-space:pre-wrap\` |
|
|
1226
|
+
| \`_breakword\` | \`overflow-wrap:break-word\` |
|
|
1227
|
+
|
|
1228
|
+
#### Cursor & Interaction
|
|
1229
|
+
| Atom | CSS |
|
|
1230
|
+
|------|-----|
|
|
1231
|
+
| \`_pointer\` | \`cursor:pointer\` |
|
|
1232
|
+
| \`_cursordefault\` | \`cursor:default\` |
|
|
1233
|
+
| \`_notallowed\` | \`cursor:not-allowed\` |
|
|
1234
|
+
| \`_grab\` | \`cursor:grab\` |
|
|
1235
|
+
| \`_selectnone\` | \`user-select:none\` |
|
|
1236
|
+
| \`_ptrnone\` | \`pointer-events:none\` |
|
|
1237
|
+
|
|
1238
|
+
#### Position & Layout
|
|
1239
|
+
| Atom | CSS |
|
|
1240
|
+
|------|-----|
|
|
1241
|
+
| \`_rel\` | \`position:relative\` |
|
|
1242
|
+
| \`_abs\` | \`position:absolute\` |
|
|
1243
|
+
| \`_fixed\` | \`position:fixed\` |
|
|
1244
|
+
| \`_sticky\` | \`position:sticky\` |
|
|
1245
|
+
| \`_inset0\` | \`inset:0\` |
|
|
1246
|
+
| \`_top0\`, \`_right0\`, \`_bottom0\`, \`_left0\` | edge positioning |
|
|
1247
|
+
| \`_z10\`-\`_z50\` | z-index scale |
|
|
1248
|
+
|
|
1249
|
+
#### Grid
|
|
1250
|
+
| Atom | CSS |
|
|
1251
|
+
|------|-----|
|
|
1252
|
+
| \`_gc1\`-\`_gc12\` | \`grid-template-columns:repeat(N,...)\` |
|
|
1253
|
+
| \`_gr1\`-\`_gr6\` | \`grid-template-rows:repeat(N,...)\` |
|
|
1254
|
+
| \`_span1\`-\`_span12\`, \`_spanfull\` | column span |
|
|
1255
|
+
| \`_rowspan1\`-\`_rowspan6\` | row span |
|
|
1256
|
+
|
|
1257
|
+
#### Visual
|
|
1258
|
+
| Atom | CSS |
|
|
1259
|
+
|------|-----|
|
|
1260
|
+
| \`_rounded\` | \`border-radius:var(--d-radius)\` |
|
|
1261
|
+
| \`_roundedfull\` | \`border-radius:9999px\` |
|
|
1262
|
+
| \`_roundedsm\`, \`_roundedlg\`, \`_roundedxl\` | radius variants |
|
|
1263
|
+
| \`_shadow\`, \`_shadowmd\`, \`_shadowlg\` | box-shadow presets |
|
|
1264
|
+
| \`_bordernone\` | \`border:none\` |
|
|
1265
|
+
| \`_bw{n}\` | \`border-width:{n}px\` |
|
|
1266
|
+
| \`_op0\`-\`_op100\` | opacity (0, 25, 50, 75, 100) |
|
|
1267
|
+
| \`_trans\` | \`transition:all 0.15s ease\` |
|
|
1268
|
+
| \`_visible\`, \`_invisible\` | visibility |
|
|
1269
|
+
|
|
1270
|
+
Responsive prefixes: \`_sm:\`, \`_md:\`, \`_lg:\` (e.g. \`_md:gc2\`, \`_lg:gc4\`, \`_sm:flex\`).
|
|
1100
1271
|
|
|
1101
1272
|
### Section Labels
|
|
1102
1273
|
|
|
@@ -1140,12 +1311,44 @@ Check \`decantr.essence.json\` \u2192 \`meta.platform.routing\` for the routing
|
|
|
1140
1311
|
- \`"history"\` \u2192 use \`BrowserRouter\` (e.g., for server-rendered apps)
|
|
1141
1312
|
|
|
1142
1313
|
Routes are defined in \`decantr.essence.json\` \u2192 \`blueprint.routes\` and listed in \`.decantr/context/scaffold.md\`.`;
|
|
1143
|
-
function generateDecantrMdV31(
|
|
1314
|
+
function generateDecantrMdV31(params) {
|
|
1144
1315
|
const template = loadTemplate("DECANTR.md.template");
|
|
1145
|
-
|
|
1146
|
-
GUARD_MODE: guardMode,
|
|
1147
|
-
CSS_APPROACH: cssApproach
|
|
1316
|
+
const body = renderTemplate(template, {
|
|
1317
|
+
GUARD_MODE: params.guardMode,
|
|
1318
|
+
CSS_APPROACH: params.cssApproach
|
|
1148
1319
|
});
|
|
1320
|
+
const briefLines = [];
|
|
1321
|
+
briefLines.push("## Project Brief");
|
|
1322
|
+
briefLines.push("");
|
|
1323
|
+
briefLines.push(`- **Blueprint:** ${params.blueprintId || "custom"}`);
|
|
1324
|
+
const themeParts = [params.themeName || "default"];
|
|
1325
|
+
if (params.themeMode) themeParts.push(`${params.themeMode} mode`);
|
|
1326
|
+
if (params.themeShape) themeParts.push(params.themeShape);
|
|
1327
|
+
briefLines.push(`- **Theme:** ${themeParts.join(" (").replace(/ \($/, "") + (themeParts.length > 1 ? ")" : "")}`);
|
|
1328
|
+
if (params.personality && params.personality.length > 0) {
|
|
1329
|
+
briefLines.push(`- **Personality:** ${params.personality.join(". ")}`);
|
|
1330
|
+
}
|
|
1331
|
+
if (params.sections && params.sections.length > 0) {
|
|
1332
|
+
const sectionList = params.sections.map((s) => `${s.id} [${s.role}]`).join(", ");
|
|
1333
|
+
briefLines.push(`- **Sections:** ${params.sections.length} (${sectionList})`);
|
|
1334
|
+
}
|
|
1335
|
+
if (params.features && params.features.length > 0) {
|
|
1336
|
+
briefLines.push(`- **Features:** ${params.features.join(", ")}`);
|
|
1337
|
+
}
|
|
1338
|
+
briefLines.push(`- **Guard mode:** ${params.guardMode}`);
|
|
1339
|
+
briefLines.push("");
|
|
1340
|
+
if (params.decorators && params.decorators.length > 0) {
|
|
1341
|
+
briefLines.push("### Decorator Quick Reference");
|
|
1342
|
+
briefLines.push("| Class | Purpose |");
|
|
1343
|
+
briefLines.push("|-------|---------|");
|
|
1344
|
+
for (const d of params.decorators) {
|
|
1345
|
+
briefLines.push(`| \`.${d.name}\` | ${d.description} |`);
|
|
1346
|
+
}
|
|
1347
|
+
briefLines.push("");
|
|
1348
|
+
}
|
|
1349
|
+
briefLines.push("---");
|
|
1350
|
+
briefLines.push("");
|
|
1351
|
+
return briefLines.join("\n") + body;
|
|
1149
1352
|
}
|
|
1150
1353
|
function generateProjectJson(detected, options, registrySource) {
|
|
1151
1354
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -1555,8 +1758,7 @@ async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThe
|
|
|
1555
1758
|
if (!themeData) try {
|
|
1556
1759
|
const themeResult = await registry.fetchTheme(themeName);
|
|
1557
1760
|
if (themeResult?.data) {
|
|
1558
|
-
const
|
|
1559
|
-
const t = raw.data ?? raw;
|
|
1761
|
+
const t = themeResult.data;
|
|
1560
1762
|
themeData = {
|
|
1561
1763
|
seed: t.seed,
|
|
1562
1764
|
palette: t.palette,
|
|
@@ -1607,7 +1809,7 @@ async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThe
|
|
|
1607
1809
|
}
|
|
1608
1810
|
const stylesDir = join(projectRoot, "src", "styles");
|
|
1609
1811
|
mkdirSync(stylesDir, { recursive: true });
|
|
1610
|
-
const densityLevel =
|
|
1812
|
+
const densityLevel = essence.dna?.spacing?.density || "comfortable";
|
|
1611
1813
|
const spatialTokens = computeSpatialTokens(densityLevel, themeData?.spatial ? {
|
|
1612
1814
|
section_padding: themeData.spatial.section_padding ?? void 0,
|
|
1613
1815
|
density_bias: typeof themeData.spatial.density_bias === "number" ? themeData.spatial.density_bias : void 0,
|
|
@@ -1630,11 +1832,45 @@ async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThe
|
|
|
1630
1832
|
writeFileSync(treatmentsPath, treatmentCSS);
|
|
1631
1833
|
const globalPath = join(stylesDir, "global.css");
|
|
1632
1834
|
if (!existsSync(globalPath)) {
|
|
1633
|
-
writeFileSync(globalPath, generateGlobalCSS(personality));
|
|
1835
|
+
writeFileSync(globalPath, generateGlobalCSS(personality, essence));
|
|
1634
1836
|
}
|
|
1635
1837
|
const cssFiles = [tokensPath, treatmentsPath, globalPath];
|
|
1838
|
+
const earlyDecoratorList = [];
|
|
1839
|
+
if (themeData?.decorators) {
|
|
1840
|
+
for (const [name, desc] of Object.entries(themeData.decorators)) {
|
|
1841
|
+
earlyDecoratorList.push({ name, description: desc });
|
|
1842
|
+
}
|
|
1843
|
+
}
|
|
1844
|
+
const allFeatures = [];
|
|
1845
|
+
const sectionSummaries = [];
|
|
1846
|
+
if (essence.blueprint.sections && essence.blueprint.sections.length > 0) {
|
|
1847
|
+
for (const s of essence.blueprint.sections) {
|
|
1848
|
+
sectionSummaries.push({ id: s.id, role: s.role });
|
|
1849
|
+
if (s.features) {
|
|
1850
|
+
for (const f of s.features) {
|
|
1851
|
+
if (!allFeatures.includes(f)) allFeatures.push(f);
|
|
1852
|
+
}
|
|
1853
|
+
}
|
|
1854
|
+
}
|
|
1855
|
+
}
|
|
1856
|
+
if (essence.blueprint.features) {
|
|
1857
|
+
for (const f of essence.blueprint.features) {
|
|
1858
|
+
if (!allFeatures.includes(f)) allFeatures.push(f);
|
|
1859
|
+
}
|
|
1860
|
+
}
|
|
1636
1861
|
const decantrMdPath = join(projectRoot, "DECANTR.md");
|
|
1637
|
-
writeFileSync(decantrMdPath, generateDecantrMdV31(
|
|
1862
|
+
writeFileSync(decantrMdPath, generateDecantrMdV31({
|
|
1863
|
+
guardMode,
|
|
1864
|
+
cssApproach: CSS_APPROACH_CONTENT,
|
|
1865
|
+
blueprintId: essence.meta.blueprint || void 0,
|
|
1866
|
+
themeName,
|
|
1867
|
+
themeMode: mode,
|
|
1868
|
+
themeShape: essence.dna.theme.shape || void 0,
|
|
1869
|
+
personality,
|
|
1870
|
+
sections: sectionSummaries.length > 0 ? sectionSummaries : void 0,
|
|
1871
|
+
features: allFeatures.length > 0 ? allFeatures : void 0,
|
|
1872
|
+
decorators: earlyDecoratorList.length > 0 ? earlyDecoratorList : void 0
|
|
1873
|
+
}));
|
|
1638
1874
|
const hasSections = essence.blueprint.sections && essence.blueprint.sections.length > 0;
|
|
1639
1875
|
const contextFiles = [];
|
|
1640
1876
|
if (!hasSections) {
|
|
@@ -1671,8 +1907,7 @@ async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThe
|
|
|
1671
1907
|
try {
|
|
1672
1908
|
const patResult = await registry.fetchPattern(name);
|
|
1673
1909
|
if (patResult?.data) {
|
|
1674
|
-
const
|
|
1675
|
-
const inner = raw.data ?? raw;
|
|
1910
|
+
const inner = patResult.data;
|
|
1676
1911
|
const defaultPreset = inner.default_preset || "standard";
|
|
1677
1912
|
const preset = inner.presets?.[defaultPreset];
|
|
1678
1913
|
let slots = preset?.layout?.slots || {};
|
|
@@ -1685,7 +1920,13 @@ async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThe
|
|
|
1685
1920
|
const spec = {
|
|
1686
1921
|
description: inner.description || "",
|
|
1687
1922
|
components: inner.components || [],
|
|
1688
|
-
slots
|
|
1923
|
+
slots,
|
|
1924
|
+
layout_hints: inner.layout_hints,
|
|
1925
|
+
visual_brief: inner.visual_brief,
|
|
1926
|
+
composition: inner.composition,
|
|
1927
|
+
motion: inner.motion,
|
|
1928
|
+
responsive: inner.responsive,
|
|
1929
|
+
accessibility: inner.accessibility
|
|
1689
1930
|
};
|
|
1690
1931
|
if (!spec.components || spec.components.length === 0) {
|
|
1691
1932
|
const syntheticComps = generateSyntheticComponents(name, spec.description);
|
|
@@ -1738,19 +1979,6 @@ async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThe
|
|
|
1738
1979
|
for (const [name, desc] of Object.entries(themeData.decorators)) {
|
|
1739
1980
|
decoratorList.push({ name, description: desc });
|
|
1740
1981
|
}
|
|
1741
|
-
} else if (existsSync(decoratorsPath)) {
|
|
1742
|
-
const decoratorsCss = readFileSync(decoratorsPath, "utf-8");
|
|
1743
|
-
const classRegex = /\/\*\s*(.+?)\s*\*\/\s*\n\s*\.([\w-]+)\s*\{/g;
|
|
1744
|
-
let match;
|
|
1745
|
-
while ((match = classRegex.exec(decoratorsCss)) !== null) {
|
|
1746
|
-
decoratorList.push({ name: match[2], description: match[1] });
|
|
1747
|
-
}
|
|
1748
|
-
if (decoratorList.length === 0) {
|
|
1749
|
-
const simpleClassRegex = /^\.([\w-]+)\s*\{/gm;
|
|
1750
|
-
while ((match = simpleClassRegex.exec(decoratorsCss)) !== null) {
|
|
1751
|
-
decoratorList.push({ name: match[1], description: "" });
|
|
1752
|
-
}
|
|
1753
|
-
}
|
|
1754
1982
|
}
|
|
1755
1983
|
const shellInfoCache = {};
|
|
1756
1984
|
const seenShells = /* @__PURE__ */ new Set();
|
|
@@ -1761,8 +1989,7 @@ async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThe
|
|
|
1761
1989
|
try {
|
|
1762
1990
|
const shellResult = await registry.fetchShell(shellId);
|
|
1763
1991
|
if (shellResult?.data) {
|
|
1764
|
-
const
|
|
1765
|
-
const inner = raw.data ?? raw;
|
|
1992
|
+
const inner = shellResult.data;
|
|
1766
1993
|
shellInfoCache[shellId] = {
|
|
1767
1994
|
description: inner.description || "",
|
|
1768
1995
|
regions: inner.config?.regions || [],
|
|
@@ -1806,8 +2033,15 @@ async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThe
|
|
|
1806
2033
|
themeName,
|
|
1807
2034
|
zoneContext,
|
|
1808
2035
|
patternSpecs: sectionPatterns,
|
|
2036
|
+
themeHints: themeData ? {
|
|
2037
|
+
preferred: themeData.pattern_preferences?.prefer,
|
|
2038
|
+
compositions: themeData.compositions ? Object.entries(themeData.compositions).map(([k, v]) => `**${k}:** ${v.description || v}`).join("\n") : void 0,
|
|
2039
|
+
spatialHints: themeData.spatial ? `Density bias: ${themeData.spatial.density_bias || "none"}. Section padding: ${themeData.spatial.section_padding || "default"}. Card wrapping: ${themeData.spatial.card_wrapping || "default"}.` : void 0
|
|
2040
|
+
} : void 0,
|
|
1809
2041
|
constraints: essence.dna.constraints,
|
|
1810
|
-
shellInfo: shellInfoCache[section.shell]
|
|
2042
|
+
shellInfo: shellInfoCache[section.shell],
|
|
2043
|
+
themeData,
|
|
2044
|
+
themeMode: mode
|
|
1811
2045
|
});
|
|
1812
2046
|
const sectionContextPath = join(contextDir, `section-${section.id}.md`);
|
|
1813
2047
|
writeFileSync(sectionContextPath, contextContent);
|
|
@@ -1851,8 +2085,7 @@ async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThe
|
|
|
1851
2085
|
try {
|
|
1852
2086
|
const patResult = await registry.fetchPattern(name);
|
|
1853
2087
|
if (patResult?.data) {
|
|
1854
|
-
const
|
|
1855
|
-
const inner = raw.data ?? raw;
|
|
2088
|
+
const inner = patResult.data;
|
|
1856
2089
|
const defaultPreset = inner.default_preset || "standard";
|
|
1857
2090
|
const preset = inner.presets?.[defaultPreset];
|
|
1858
2091
|
let slots = preset?.layout?.slots || {};
|
|
@@ -1865,7 +2098,8 @@ async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThe
|
|
|
1865
2098
|
const spec = {
|
|
1866
2099
|
description: inner.description || "",
|
|
1867
2100
|
components: inner.components || [],
|
|
1868
|
-
slots
|
|
2101
|
+
slots,
|
|
2102
|
+
layout_hints: inner.layout_hints
|
|
1869
2103
|
};
|
|
1870
2104
|
if (!spec.components || spec.components.length === 0) {
|
|
1871
2105
|
const syntheticComps = generateSyntheticComponents(name, spec.description);
|
|
@@ -1896,26 +2130,12 @@ async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThe
|
|
|
1896
2130
|
for (const [name, desc] of Object.entries(themeData.decorators)) {
|
|
1897
2131
|
decoratorList.push({ name, description: desc });
|
|
1898
2132
|
}
|
|
1899
|
-
} else if (existsSync(decoratorsPath)) {
|
|
1900
|
-
const decoratorsCss = readFileSync(decoratorsPath, "utf-8");
|
|
1901
|
-
const classRegex = /\/\*\s*(.+?)\s*\*\/\s*\n\s*\.([\w-]+)\s*\{/g;
|
|
1902
|
-
let match;
|
|
1903
|
-
while ((match = classRegex.exec(decoratorsCss)) !== null) {
|
|
1904
|
-
decoratorList.push({ name: match[2], description: match[1] });
|
|
1905
|
-
}
|
|
1906
|
-
if (decoratorList.length === 0) {
|
|
1907
|
-
const simpleClassRegex = /^\.([\w-]+)\s*\{/gm;
|
|
1908
|
-
while ((match = simpleClassRegex.exec(decoratorsCss)) !== null) {
|
|
1909
|
-
decoratorList.push({ name: match[1], description: "" });
|
|
1910
|
-
}
|
|
1911
|
-
}
|
|
1912
2133
|
}
|
|
1913
2134
|
let v30ShellInfo;
|
|
1914
2135
|
try {
|
|
1915
2136
|
const shellResult = await registry.fetchShell(shell);
|
|
1916
2137
|
if (shellResult?.data) {
|
|
1917
|
-
const
|
|
1918
|
-
const inner = raw.data ?? raw;
|
|
2138
|
+
const inner = shellResult.data;
|
|
1919
2139
|
v30ShellInfo = {
|
|
1920
2140
|
description: inner.description || "",
|
|
1921
2141
|
regions: inner.config?.regions || [],
|
|
@@ -1934,8 +2154,15 @@ async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThe
|
|
|
1934
2154
|
themeName,
|
|
1935
2155
|
zoneContext: `This is the primary section (${shell} shell).`,
|
|
1936
2156
|
patternSpecs,
|
|
2157
|
+
themeHints: themeData ? {
|
|
2158
|
+
preferred: themeData.pattern_preferences?.prefer,
|
|
2159
|
+
compositions: themeData.compositions ? Object.entries(themeData.compositions).map(([k, v]) => `**${k}:** ${v.description || v}`).join("\n") : void 0,
|
|
2160
|
+
spatialHints: themeData.spatial ? `Density bias: ${themeData.spatial.density_bias || "none"}. Section padding: ${themeData.spatial.section_padding || "default"}. Card wrapping: ${themeData.spatial.card_wrapping || "default"}.` : void 0
|
|
2161
|
+
} : void 0,
|
|
1937
2162
|
constraints: essence.dna.constraints,
|
|
1938
|
-
shellInfo: v30ShellInfo
|
|
2163
|
+
shellInfo: v30ShellInfo,
|
|
2164
|
+
themeData,
|
|
2165
|
+
themeMode: mode
|
|
1939
2166
|
});
|
|
1940
2167
|
const sectionContextPath = join(contextDir, `section-${syntheticSection.id}.md`);
|
|
1941
2168
|
writeFileSync(sectionContextPath, contextContent);
|
|
@@ -2067,14 +2294,47 @@ function generateSectionContext(input) {
|
|
|
2067
2294
|
lines.push("");
|
|
2068
2295
|
lines.push(`**Guard:** ${guardConfig.mode} mode | DNA violations = ${guardConfig.dna_enforcement} | Blueprint violations = ${guardConfig.blueprint_enforcement}`);
|
|
2069
2296
|
lines.push("");
|
|
2070
|
-
lines.push(
|
|
2297
|
+
lines.push("**Key palette tokens:**");
|
|
2298
|
+
lines.push("");
|
|
2299
|
+
lines.push("| Token | Value | Role |");
|
|
2300
|
+
lines.push("|-------|-------|------|");
|
|
2301
|
+
const semanticRoles = {
|
|
2302
|
+
background: "Page canvas / base layer",
|
|
2303
|
+
surface: "Cards, panels, containers",
|
|
2304
|
+
"surface-raised": "Elevated containers, modals, popovers",
|
|
2305
|
+
border: "Dividers, card borders, separators",
|
|
2306
|
+
text: "Body text, headings, primary content",
|
|
2307
|
+
"text-muted": "Secondary text, placeholders, labels",
|
|
2308
|
+
primary: "Brand color, key interactive, selected states",
|
|
2309
|
+
"primary-hover": "Hover state for primary elements"
|
|
2310
|
+
};
|
|
2311
|
+
if (input.themeData?.palette) {
|
|
2312
|
+
const modeKey = input.themeMode || "dark";
|
|
2313
|
+
for (const [name, values] of Object.entries(input.themeData.palette)) {
|
|
2314
|
+
const val = values[modeKey] || values.dark || values.light || Object.values(values)[0];
|
|
2315
|
+
lines.push(`| \`--d-${name}\` | \`${val}\` | ${semanticRoles[name] || ""} |`);
|
|
2316
|
+
}
|
|
2317
|
+
}
|
|
2318
|
+
if (input.themeData?.seed?.accent) {
|
|
2319
|
+
lines.push(`| \`--d-accent\` | \`${input.themeData.seed.accent}\` | CTAs, links, active states, glow effects |`);
|
|
2320
|
+
}
|
|
2321
|
+
lines.push("");
|
|
2322
|
+
lines.push("Full token set: `src/styles/tokens.css`");
|
|
2071
2323
|
lines.push("");
|
|
2072
2324
|
lines.push("**Visual Treatments:** All 6 base treatments available (see DECANTR.md for usage).");
|
|
2073
2325
|
if (decorators.length > 0) {
|
|
2074
|
-
|
|
2075
|
-
lines.push(
|
|
2326
|
+
lines.push("**Theme decorators:**");
|
|
2327
|
+
lines.push("");
|
|
2328
|
+
lines.push("| Class | Usage |");
|
|
2329
|
+
lines.push("|-------|-------|");
|
|
2330
|
+
for (const d of decorators) {
|
|
2331
|
+
lines.push(`| \`.${d.name}\` | ${d.description} |`);
|
|
2332
|
+
}
|
|
2333
|
+
lines.push("");
|
|
2334
|
+
} else {
|
|
2335
|
+
lines.push("**Theme decorators:** None defined for this theme.");
|
|
2336
|
+
lines.push("");
|
|
2076
2337
|
}
|
|
2077
|
-
lines.push("");
|
|
2078
2338
|
if (themeHints) {
|
|
2079
2339
|
if (themeHints.preferred && themeHints.preferred.length > 0) {
|
|
2080
2340
|
lines.push(`**Preferred:** ${themeHints.preferred.join(", ")}`);
|
|
@@ -2087,6 +2347,10 @@ function generateSectionContext(input) {
|
|
|
2087
2347
|
}
|
|
2088
2348
|
lines.push("");
|
|
2089
2349
|
}
|
|
2350
|
+
const themePrefix = themeName.split("-")[0] || themeName;
|
|
2351
|
+
lines.push("");
|
|
2352
|
+
lines.push(`Usage: \`className={css('_flex _col _gap4') + ' d-surface ${themePrefix}-glass'}\` \u2014 atoms via css(), treatments and theme decorators as plain class strings.`);
|
|
2353
|
+
lines.push("");
|
|
2090
2354
|
lines.push("---");
|
|
2091
2355
|
lines.push("");
|
|
2092
2356
|
if (zoneContext) {
|
|
@@ -2103,8 +2367,24 @@ function generateSectionContext(input) {
|
|
|
2103
2367
|
lines.push("");
|
|
2104
2368
|
}
|
|
2105
2369
|
if (personality.length > 0) {
|
|
2106
|
-
|
|
2370
|
+
const personalityText = personality.join(". ");
|
|
2371
|
+
lines.push("## Visual Direction");
|
|
2107
2372
|
lines.push("");
|
|
2373
|
+
lines.push(`**Personality:** ${personalityText}`);
|
|
2374
|
+
lines.push("");
|
|
2375
|
+
const pLower = personalityText.toLowerCase();
|
|
2376
|
+
const utils = [];
|
|
2377
|
+
if (pLower.includes("neon") || pLower.includes("glow"))
|
|
2378
|
+
utils.push("`neon-glow`, `neon-glow-hover`, `neon-text-glow`, `neon-border-glow` \u2014 Apply to elements needing accent emphasis");
|
|
2379
|
+
if (pLower.includes("mono") || pLower.includes("monospace"))
|
|
2380
|
+
utils.push("`mono-data` \u2014 Monospace + tabular-nums for metrics, IDs, timestamps");
|
|
2381
|
+
if (pLower.includes("pulse") || pLower.includes("ring") || pLower.includes("status"))
|
|
2382
|
+
utils.push('`status-ring` with `data-status="active|idle|error|processing"` \u2014 Color-coded status with pulse animation');
|
|
2383
|
+
if (utils.length > 0) {
|
|
2384
|
+
lines.push("**Personality utilities available in treatments.css:**");
|
|
2385
|
+
for (const u of utils) lines.push(`- ${u}`);
|
|
2386
|
+
lines.push("");
|
|
2387
|
+
}
|
|
2108
2388
|
}
|
|
2109
2389
|
if (constraints && Object.keys(constraints).length > 0) {
|
|
2110
2390
|
lines.push("## Constraints");
|
|
@@ -2133,12 +2413,59 @@ function generateSectionContext(input) {
|
|
|
2133
2413
|
lines.push("");
|
|
2134
2414
|
lines.push(spec.description);
|
|
2135
2415
|
lines.push("");
|
|
2416
|
+
if (spec.visual_brief) {
|
|
2417
|
+
lines.push(`**Visual brief:** ${spec.visual_brief}`);
|
|
2418
|
+
lines.push("");
|
|
2419
|
+
}
|
|
2136
2420
|
lines.push(`**Components:** ${spec.components.join(", ")}`);
|
|
2137
2421
|
lines.push("");
|
|
2422
|
+
if (spec.composition && Object.keys(spec.composition).length > 0) {
|
|
2423
|
+
lines.push("**Composition:**");
|
|
2424
|
+
lines.push("```");
|
|
2425
|
+
for (const [name, expr] of Object.entries(spec.composition)) {
|
|
2426
|
+
lines.push(`${name} = ${expr}`);
|
|
2427
|
+
}
|
|
2428
|
+
lines.push("```");
|
|
2429
|
+
lines.push("");
|
|
2430
|
+
}
|
|
2138
2431
|
lines.push("**Layout slots:**");
|
|
2139
2432
|
for (const [slot, desc] of Object.entries(spec.slots)) {
|
|
2140
2433
|
lines.push(`- \`${slot}\`: ${desc}`);
|
|
2141
2434
|
}
|
|
2435
|
+
if (spec.layout_hints && Object.keys(spec.layout_hints).length > 0) {
|
|
2436
|
+
lines.push(` **Layout guidance:**`);
|
|
2437
|
+
for (const [key, value] of Object.entries(spec.layout_hints)) {
|
|
2438
|
+
lines.push(` - ${key}: ${value}`);
|
|
2439
|
+
}
|
|
2440
|
+
}
|
|
2441
|
+
if (spec.motion) {
|
|
2442
|
+
const entries = [];
|
|
2443
|
+
if (spec.motion.micro) for (const [k, v] of Object.entries(spec.motion.micro)) entries.push([k, v]);
|
|
2444
|
+
if (spec.motion.transitions) for (const [k, v] of Object.entries(spec.motion.transitions)) entries.push([k, v]);
|
|
2445
|
+
if (spec.motion.ambient) for (const [k, v] of Object.entries(spec.motion.ambient)) entries.push([k, v]);
|
|
2446
|
+
if (entries.length > 0) {
|
|
2447
|
+
lines.push("**Motion:**");
|
|
2448
|
+
lines.push("| Interaction | Animation |");
|
|
2449
|
+
lines.push("|-------------|-----------|");
|
|
2450
|
+
for (const [k, v] of entries) lines.push(`| ${k} | ${v} |`);
|
|
2451
|
+
lines.push("");
|
|
2452
|
+
}
|
|
2453
|
+
}
|
|
2454
|
+
if (spec.responsive) {
|
|
2455
|
+
lines.push("**Responsive:**");
|
|
2456
|
+
if (spec.responsive.mobile) lines.push(`- **Mobile (<640px):** ${spec.responsive.mobile}`);
|
|
2457
|
+
if (spec.responsive.tablet) lines.push(`- **Tablet (640-1024px):** ${spec.responsive.tablet}`);
|
|
2458
|
+
if (spec.responsive.desktop) lines.push(`- **Desktop (>1024px):** ${spec.responsive.desktop}`);
|
|
2459
|
+
lines.push("");
|
|
2460
|
+
}
|
|
2461
|
+
if (spec.accessibility) {
|
|
2462
|
+
lines.push("**Accessibility:**");
|
|
2463
|
+
if (spec.accessibility.role) lines.push(`- Role: \`${spec.accessibility.role}\``);
|
|
2464
|
+
if (spec.accessibility.keyboard?.length) lines.push(`- Keyboard: ${spec.accessibility.keyboard.join("; ")}`);
|
|
2465
|
+
if (spec.accessibility.announcements?.length) lines.push(`- Announcements: ${spec.accessibility.announcements.join("; ")}`);
|
|
2466
|
+
if (spec.accessibility.focus_management) lines.push(`- Focus: ${spec.accessibility.focus_management}`);
|
|
2467
|
+
lines.push("");
|
|
2468
|
+
}
|
|
2142
2469
|
lines.push("");
|
|
2143
2470
|
}
|
|
2144
2471
|
lines.push("---");
|
|
@@ -2177,6 +2504,18 @@ function generateScaffoldContext(input) {
|
|
|
2177
2504
|
lines.push(`**Personality:** ${personality.join(", ")}`);
|
|
2178
2505
|
lines.push("**Guard mode:** creative (no enforcement during initial scaffolding)");
|
|
2179
2506
|
lines.push("");
|
|
2507
|
+
if (input.voice) {
|
|
2508
|
+
lines.push("## Voice & Copy");
|
|
2509
|
+
lines.push("");
|
|
2510
|
+
if (input.voice.tone) lines.push(`**Tone:** ${input.voice.tone}`);
|
|
2511
|
+
if (input.voice.cta_verbs?.length) lines.push(`**CTA verbs:** ${input.voice.cta_verbs.join(", ")}`);
|
|
2512
|
+
if (input.voice.avoid?.length) lines.push(`**Avoid:** ${input.voice.avoid.join(", ")}`);
|
|
2513
|
+
if (input.voice.empty_states) lines.push(`**Empty states:** ${input.voice.empty_states}`);
|
|
2514
|
+
if (input.voice.errors) lines.push(`**Errors:** ${input.voice.errors}`);
|
|
2515
|
+
if (input.voice.loading) lines.push(`**Loading states:** ${input.voice.loading}`);
|
|
2516
|
+
if (input.voice.metrics_format) lines.push(`**Metrics format:** ${input.voice.metrics_format}`);
|
|
2517
|
+
lines.push("");
|
|
2518
|
+
}
|
|
2180
2519
|
lines.push("## App Topology");
|
|
2181
2520
|
lines.push("");
|
|
2182
2521
|
lines.push(topologyMarkdown);
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import "./chunk-
|
|
2
|
-
import "./chunk-
|
|
1
|
+
import "./chunk-G76RSQRX.js";
|
|
2
|
+
import "./chunk-RG7F5APP.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@decantr/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
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": {
|
|
@@ -22,13 +22,13 @@
|
|
|
22
22
|
"publishConfig": {
|
|
23
23
|
"access": "public"
|
|
24
24
|
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@decantr/essence-spec": "1.0.0-beta.11",
|
|
27
|
+
"@decantr/registry": "1.0.0-beta.11"
|
|
28
|
+
},
|
|
25
29
|
"scripts": {
|
|
26
30
|
"build": "tsup",
|
|
27
31
|
"test": "vitest run",
|
|
28
32
|
"test:watch": "vitest"
|
|
29
|
-
},
|
|
30
|
-
"dependencies": {
|
|
31
|
-
"@decantr/essence-spec": "workspace:*",
|
|
32
|
-
"@decantr/registry": "workspace:*"
|
|
33
33
|
}
|
|
34
|
-
}
|
|
34
|
+
}
|