@decantr/cli 1.5.6 → 1.6.1
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-DESYSWLL.js";
|
|
3
|
+
import "./chunk-PMBLHVBX.js";
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
scaffoldMinimal,
|
|
10
10
|
scaffoldProject,
|
|
11
11
|
syncRegistry
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-PMBLHVBX.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-2OG7UKTR.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) {
|
|
@@ -1291,12 +1311,44 @@ Check \`decantr.essence.json\` \u2192 \`meta.platform.routing\` for the routing
|
|
|
1291
1311
|
- \`"history"\` \u2192 use \`BrowserRouter\` (e.g., for server-rendered apps)
|
|
1292
1312
|
|
|
1293
1313
|
Routes are defined in \`decantr.essence.json\` \u2192 \`blueprint.routes\` and listed in \`.decantr/context/scaffold.md\`.`;
|
|
1294
|
-
function generateDecantrMdV31(
|
|
1314
|
+
function generateDecantrMdV31(params) {
|
|
1295
1315
|
const template = loadTemplate("DECANTR.md.template");
|
|
1296
|
-
|
|
1297
|
-
GUARD_MODE: guardMode,
|
|
1298
|
-
CSS_APPROACH: cssApproach
|
|
1316
|
+
const body = renderTemplate(template, {
|
|
1317
|
+
GUARD_MODE: params.guardMode,
|
|
1318
|
+
CSS_APPROACH: params.cssApproach
|
|
1299
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;
|
|
1300
1352
|
}
|
|
1301
1353
|
function generateProjectJson(detected, options, registrySource) {
|
|
1302
1354
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -1706,8 +1758,7 @@ async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThe
|
|
|
1706
1758
|
if (!themeData) try {
|
|
1707
1759
|
const themeResult = await registry.fetchTheme(themeName);
|
|
1708
1760
|
if (themeResult?.data) {
|
|
1709
|
-
const
|
|
1710
|
-
const t = raw.data ?? raw;
|
|
1761
|
+
const t = themeResult.data;
|
|
1711
1762
|
themeData = {
|
|
1712
1763
|
seed: t.seed,
|
|
1713
1764
|
palette: t.palette,
|
|
@@ -1758,7 +1809,7 @@ async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThe
|
|
|
1758
1809
|
}
|
|
1759
1810
|
const stylesDir = join(projectRoot, "src", "styles");
|
|
1760
1811
|
mkdirSync(stylesDir, { recursive: true });
|
|
1761
|
-
const densityLevel =
|
|
1812
|
+
const densityLevel = essence.dna?.spacing?.density || "comfortable";
|
|
1762
1813
|
const spatialTokens = computeSpatialTokens(densityLevel, themeData?.spatial ? {
|
|
1763
1814
|
section_padding: themeData.spatial.section_padding ?? void 0,
|
|
1764
1815
|
density_bias: typeof themeData.spatial.density_bias === "number" ? themeData.spatial.density_bias : void 0,
|
|
@@ -1781,11 +1832,45 @@ async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThe
|
|
|
1781
1832
|
writeFileSync(treatmentsPath, treatmentCSS);
|
|
1782
1833
|
const globalPath = join(stylesDir, "global.css");
|
|
1783
1834
|
if (!existsSync(globalPath)) {
|
|
1784
|
-
writeFileSync(globalPath, generateGlobalCSS(personality));
|
|
1835
|
+
writeFileSync(globalPath, generateGlobalCSS(personality, essence));
|
|
1785
1836
|
}
|
|
1786
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
|
+
}
|
|
1787
1861
|
const decantrMdPath = join(projectRoot, "DECANTR.md");
|
|
1788
|
-
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
|
+
}));
|
|
1789
1874
|
const hasSections = essence.blueprint.sections && essence.blueprint.sections.length > 0;
|
|
1790
1875
|
const contextFiles = [];
|
|
1791
1876
|
if (!hasSections) {
|
|
@@ -1822,8 +1907,7 @@ async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThe
|
|
|
1822
1907
|
try {
|
|
1823
1908
|
const patResult = await registry.fetchPattern(name);
|
|
1824
1909
|
if (patResult?.data) {
|
|
1825
|
-
const
|
|
1826
|
-
const inner = raw.data ?? raw;
|
|
1910
|
+
const inner = patResult.data;
|
|
1827
1911
|
const defaultPreset = inner.default_preset || "standard";
|
|
1828
1912
|
const preset = inner.presets?.[defaultPreset];
|
|
1829
1913
|
let slots = preset?.layout?.slots || {};
|
|
@@ -1837,7 +1921,12 @@ async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThe
|
|
|
1837
1921
|
description: inner.description || "",
|
|
1838
1922
|
components: inner.components || [],
|
|
1839
1923
|
slots,
|
|
1840
|
-
layout_hints: inner.layout_hints
|
|
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
|
|
1841
1930
|
};
|
|
1842
1931
|
if (!spec.components || spec.components.length === 0) {
|
|
1843
1932
|
const syntheticComps = generateSyntheticComponents(name, spec.description);
|
|
@@ -1890,19 +1979,6 @@ async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThe
|
|
|
1890
1979
|
for (const [name, desc] of Object.entries(themeData.decorators)) {
|
|
1891
1980
|
decoratorList.push({ name, description: desc });
|
|
1892
1981
|
}
|
|
1893
|
-
} else if (existsSync(decoratorsPath)) {
|
|
1894
|
-
const decoratorsCss = readFileSync(decoratorsPath, "utf-8");
|
|
1895
|
-
const classRegex = /\/\*\s*(.+?)\s*\*\/\s*\n\s*\.([\w-]+)\s*\{/g;
|
|
1896
|
-
let match;
|
|
1897
|
-
while ((match = classRegex.exec(decoratorsCss)) !== null) {
|
|
1898
|
-
decoratorList.push({ name: match[2], description: match[1] });
|
|
1899
|
-
}
|
|
1900
|
-
if (decoratorList.length === 0) {
|
|
1901
|
-
const simpleClassRegex = /^\.([\w-]+)\s*\{/gm;
|
|
1902
|
-
while ((match = simpleClassRegex.exec(decoratorsCss)) !== null) {
|
|
1903
|
-
decoratorList.push({ name: match[1], description: "" });
|
|
1904
|
-
}
|
|
1905
|
-
}
|
|
1906
1982
|
}
|
|
1907
1983
|
const shellInfoCache = {};
|
|
1908
1984
|
const seenShells = /* @__PURE__ */ new Set();
|
|
@@ -1913,8 +1989,7 @@ async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThe
|
|
|
1913
1989
|
try {
|
|
1914
1990
|
const shellResult = await registry.fetchShell(shellId);
|
|
1915
1991
|
if (shellResult?.data) {
|
|
1916
|
-
const
|
|
1917
|
-
const inner = raw.data ?? raw;
|
|
1992
|
+
const inner = shellResult.data;
|
|
1918
1993
|
shellInfoCache[shellId] = {
|
|
1919
1994
|
description: inner.description || "",
|
|
1920
1995
|
regions: inner.config?.regions || [],
|
|
@@ -1958,8 +2033,15 @@ async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThe
|
|
|
1958
2033
|
themeName,
|
|
1959
2034
|
zoneContext,
|
|
1960
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,
|
|
1961
2041
|
constraints: essence.dna.constraints,
|
|
1962
|
-
shellInfo: shellInfoCache[section.shell]
|
|
2042
|
+
shellInfo: shellInfoCache[section.shell],
|
|
2043
|
+
themeData,
|
|
2044
|
+
themeMode: mode
|
|
1963
2045
|
});
|
|
1964
2046
|
const sectionContextPath = join(contextDir, `section-${section.id}.md`);
|
|
1965
2047
|
writeFileSync(sectionContextPath, contextContent);
|
|
@@ -2003,8 +2085,7 @@ async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThe
|
|
|
2003
2085
|
try {
|
|
2004
2086
|
const patResult = await registry.fetchPattern(name);
|
|
2005
2087
|
if (patResult?.data) {
|
|
2006
|
-
const
|
|
2007
|
-
const inner = raw.data ?? raw;
|
|
2088
|
+
const inner = patResult.data;
|
|
2008
2089
|
const defaultPreset = inner.default_preset || "standard";
|
|
2009
2090
|
const preset = inner.presets?.[defaultPreset];
|
|
2010
2091
|
let slots = preset?.layout?.slots || {};
|
|
@@ -2049,26 +2130,12 @@ async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThe
|
|
|
2049
2130
|
for (const [name, desc] of Object.entries(themeData.decorators)) {
|
|
2050
2131
|
decoratorList.push({ name, description: desc });
|
|
2051
2132
|
}
|
|
2052
|
-
} else if (existsSync(decoratorsPath)) {
|
|
2053
|
-
const decoratorsCss = readFileSync(decoratorsPath, "utf-8");
|
|
2054
|
-
const classRegex = /\/\*\s*(.+?)\s*\*\/\s*\n\s*\.([\w-]+)\s*\{/g;
|
|
2055
|
-
let match;
|
|
2056
|
-
while ((match = classRegex.exec(decoratorsCss)) !== null) {
|
|
2057
|
-
decoratorList.push({ name: match[2], description: match[1] });
|
|
2058
|
-
}
|
|
2059
|
-
if (decoratorList.length === 0) {
|
|
2060
|
-
const simpleClassRegex = /^\.([\w-]+)\s*\{/gm;
|
|
2061
|
-
while ((match = simpleClassRegex.exec(decoratorsCss)) !== null) {
|
|
2062
|
-
decoratorList.push({ name: match[1], description: "" });
|
|
2063
|
-
}
|
|
2064
|
-
}
|
|
2065
2133
|
}
|
|
2066
2134
|
let v30ShellInfo;
|
|
2067
2135
|
try {
|
|
2068
2136
|
const shellResult = await registry.fetchShell(shell);
|
|
2069
2137
|
if (shellResult?.data) {
|
|
2070
|
-
const
|
|
2071
|
-
const inner = raw.data ?? raw;
|
|
2138
|
+
const inner = shellResult.data;
|
|
2072
2139
|
v30ShellInfo = {
|
|
2073
2140
|
description: inner.description || "",
|
|
2074
2141
|
regions: inner.config?.regions || [],
|
|
@@ -2087,8 +2154,15 @@ async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThe
|
|
|
2087
2154
|
themeName,
|
|
2088
2155
|
zoneContext: `This is the primary section (${shell} shell).`,
|
|
2089
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,
|
|
2090
2162
|
constraints: essence.dna.constraints,
|
|
2091
|
-
shellInfo: v30ShellInfo
|
|
2163
|
+
shellInfo: v30ShellInfo,
|
|
2164
|
+
themeData,
|
|
2165
|
+
themeMode: mode
|
|
2092
2166
|
});
|
|
2093
2167
|
const sectionContextPath = join(contextDir, `section-${syntheticSection.id}.md`);
|
|
2094
2168
|
writeFileSync(sectionContextPath, contextContent);
|
|
@@ -2220,14 +2294,47 @@ function generateSectionContext(input) {
|
|
|
2220
2294
|
lines.push("");
|
|
2221
2295
|
lines.push(`**Guard:** ${guardConfig.mode} mode | DNA violations = ${guardConfig.dna_enforcement} | Blueprint violations = ${guardConfig.blueprint_enforcement}`);
|
|
2222
2296
|
lines.push("");
|
|
2223
|
-
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`");
|
|
2224
2323
|
lines.push("");
|
|
2225
2324
|
lines.push("**Visual Treatments:** All 6 base treatments available (see DECANTR.md for usage).");
|
|
2226
2325
|
if (decorators.length > 0) {
|
|
2227
|
-
|
|
2228
|
-
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("");
|
|
2229
2337
|
}
|
|
2230
|
-
lines.push("");
|
|
2231
2338
|
if (themeHints) {
|
|
2232
2339
|
if (themeHints.preferred && themeHints.preferred.length > 0) {
|
|
2233
2340
|
lines.push(`**Preferred:** ${themeHints.preferred.join(", ")}`);
|
|
@@ -2260,8 +2367,24 @@ function generateSectionContext(input) {
|
|
|
2260
2367
|
lines.push("");
|
|
2261
2368
|
}
|
|
2262
2369
|
if (personality.length > 0) {
|
|
2263
|
-
|
|
2370
|
+
const personalityText = personality.join(". ");
|
|
2371
|
+
lines.push("## Visual Direction");
|
|
2372
|
+
lines.push("");
|
|
2373
|
+
lines.push(`**Personality:** ${personalityText}`);
|
|
2264
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
|
+
}
|
|
2265
2388
|
}
|
|
2266
2389
|
if (constraints && Object.keys(constraints).length > 0) {
|
|
2267
2390
|
lines.push("## Constraints");
|
|
@@ -2290,8 +2413,21 @@ function generateSectionContext(input) {
|
|
|
2290
2413
|
lines.push("");
|
|
2291
2414
|
lines.push(spec.description);
|
|
2292
2415
|
lines.push("");
|
|
2416
|
+
if (spec.visual_brief) {
|
|
2417
|
+
lines.push(`**Visual brief:** ${spec.visual_brief}`);
|
|
2418
|
+
lines.push("");
|
|
2419
|
+
}
|
|
2293
2420
|
lines.push(`**Components:** ${spec.components.join(", ")}`);
|
|
2294
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
|
+
}
|
|
2295
2431
|
lines.push("**Layout slots:**");
|
|
2296
2432
|
for (const [slot, desc] of Object.entries(spec.slots)) {
|
|
2297
2433
|
lines.push(`- \`${slot}\`: ${desc}`);
|
|
@@ -2302,6 +2438,38 @@ function generateSectionContext(input) {
|
|
|
2302
2438
|
lines.push(` - ${key}: ${value}`);
|
|
2303
2439
|
}
|
|
2304
2440
|
}
|
|
2441
|
+
if (spec.motion) {
|
|
2442
|
+
const entries = [];
|
|
2443
|
+
const isObj = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
2444
|
+
if (isObj(spec.motion.micro)) for (const [k, v] of Object.entries(spec.motion.micro)) entries.push([k, v]);
|
|
2445
|
+
else if (typeof spec.motion.micro === "string") entries.push(["micro", spec.motion.micro]);
|
|
2446
|
+
if (isObj(spec.motion.transitions)) for (const [k, v] of Object.entries(spec.motion.transitions)) entries.push([k, v]);
|
|
2447
|
+
else if (typeof spec.motion.transitions === "string") entries.push(["transitions", spec.motion.transitions]);
|
|
2448
|
+
if (isObj(spec.motion.ambient)) for (const [k, v] of Object.entries(spec.motion.ambient)) entries.push([k, v]);
|
|
2449
|
+
else if (typeof spec.motion.ambient === "string") entries.push(["ambient", spec.motion.ambient]);
|
|
2450
|
+
if (entries.length > 0) {
|
|
2451
|
+
lines.push("**Motion:**");
|
|
2452
|
+
lines.push("| Interaction | Animation |");
|
|
2453
|
+
lines.push("|-------------|-----------|");
|
|
2454
|
+
for (const [k, v] of entries) lines.push(`| ${k} | ${v} |`);
|
|
2455
|
+
lines.push("");
|
|
2456
|
+
}
|
|
2457
|
+
}
|
|
2458
|
+
if (spec.responsive) {
|
|
2459
|
+
lines.push("**Responsive:**");
|
|
2460
|
+
if (spec.responsive.mobile) lines.push(`- **Mobile (<640px):** ${spec.responsive.mobile}`);
|
|
2461
|
+
if (spec.responsive.tablet) lines.push(`- **Tablet (640-1024px):** ${spec.responsive.tablet}`);
|
|
2462
|
+
if (spec.responsive.desktop) lines.push(`- **Desktop (>1024px):** ${spec.responsive.desktop}`);
|
|
2463
|
+
lines.push("");
|
|
2464
|
+
}
|
|
2465
|
+
if (spec.accessibility) {
|
|
2466
|
+
lines.push("**Accessibility:**");
|
|
2467
|
+
if (spec.accessibility.role) lines.push(`- Role: \`${spec.accessibility.role}\``);
|
|
2468
|
+
if (Array.isArray(spec.accessibility.keyboard) && spec.accessibility.keyboard.length) lines.push(`- Keyboard: ${spec.accessibility.keyboard.join("; ")}`);
|
|
2469
|
+
if (Array.isArray(spec.accessibility.announcements) && spec.accessibility.announcements.length) lines.push(`- Announcements: ${spec.accessibility.announcements.join("; ")}`);
|
|
2470
|
+
if (spec.accessibility.focus_management) lines.push(`- Focus: ${spec.accessibility.focus_management}`);
|
|
2471
|
+
lines.push("");
|
|
2472
|
+
}
|
|
2305
2473
|
lines.push("");
|
|
2306
2474
|
}
|
|
2307
2475
|
lines.push("---");
|
|
@@ -2340,6 +2508,18 @@ function generateScaffoldContext(input) {
|
|
|
2340
2508
|
lines.push(`**Personality:** ${personality.join(", ")}`);
|
|
2341
2509
|
lines.push("**Guard mode:** creative (no enforcement during initial scaffolding)");
|
|
2342
2510
|
lines.push("");
|
|
2511
|
+
if (input.voice) {
|
|
2512
|
+
lines.push("## Voice & Copy");
|
|
2513
|
+
lines.push("");
|
|
2514
|
+
if (input.voice.tone) lines.push(`**Tone:** ${input.voice.tone}`);
|
|
2515
|
+
if (input.voice.cta_verbs?.length) lines.push(`**CTA verbs:** ${input.voice.cta_verbs.join(", ")}`);
|
|
2516
|
+
if (input.voice.avoid?.length) lines.push(`**Avoid:** ${input.voice.avoid.join(", ")}`);
|
|
2517
|
+
if (input.voice.empty_states) lines.push(`**Empty states:** ${input.voice.empty_states}`);
|
|
2518
|
+
if (input.voice.errors) lines.push(`**Errors:** ${input.voice.errors}`);
|
|
2519
|
+
if (input.voice.loading) lines.push(`**Loading states:** ${input.voice.loading}`);
|
|
2520
|
+
if (input.voice.metrics_format) lines.push(`**Metrics format:** ${input.voice.metrics_format}`);
|
|
2521
|
+
lines.push("");
|
|
2522
|
+
}
|
|
2343
2523
|
lines.push("## App Topology");
|
|
2344
2524
|
lines.push("");
|
|
2345
2525
|
lines.push(topologyMarkdown);
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import "./chunk-
|
|
2
|
-
import "./chunk-
|
|
1
|
+
import "./chunk-DESYSWLL.js";
|
|
2
|
+
import "./chunk-PMBLHVBX.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@decantr/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.1",
|
|
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
|
+
}
|