@decantr/cli 2.11.0 → 2.13.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/README.md +17 -5
- package/dist/bin.js +5 -5
- package/dist/{chunk-5WPRTVNA.js → chunk-3A2DLR47.js} +8 -5
- package/dist/{chunk-ET4BG746.js → chunk-5MZH6XXQ.js} +1424 -429
- package/dist/{chunk-4SZ4SEKT.js → chunk-MNZKOZW7.js} +78 -30
- package/dist/{chunk-IQZCIMQJ.js → chunk-SIDKK73N.js} +24 -2
- package/dist/{chunk-NUNUW5IS.js → chunk-YBSBAJ3E.js} +1 -1
- package/dist/{heal-2UCSPRTK.js → heal-IRIDB7IZ.js} +1 -1
- package/dist/{health-ADHNLMX3.js → health-B4W7UJBZ.js} +2 -2
- package/dist/index.js +5 -5
- package/dist/{studio-GZFCCVSO.js → studio-JOEECLI6.js} +3 -3
- package/dist/{upgrade-7ZYWR2GH.js → upgrade-WBFE6EN7.js} +1 -1
- package/dist/{workspace-YYCRXJNB.js → workspace-7RU77ZZW.js} +3 -3
- package/package.json +4 -4
|
@@ -660,8 +660,8 @@ function scanRoutes(projectRoot) {
|
|
|
660
660
|
}
|
|
661
661
|
|
|
662
662
|
// src/analyzers/styling.ts
|
|
663
|
-
import { existsSync as existsSync3, readFileSync as readFileSync3 } from "fs";
|
|
664
|
-
import { join as join3 } from "path";
|
|
663
|
+
import { existsSync as existsSync3, readdirSync as readdirSync3, readFileSync as readFileSync3, statSync as statSync3 } from "fs";
|
|
664
|
+
import { join as join3, relative as relative3 } from "path";
|
|
665
665
|
var TAILWIND_CONFIGS = [
|
|
666
666
|
"tailwind.config.js",
|
|
667
667
|
"tailwind.config.ts",
|
|
@@ -674,8 +674,10 @@ var GLOBALS_CSS_PATHS = [
|
|
|
674
674
|
"src/styles/global.css",
|
|
675
675
|
"src/styles/globals.css",
|
|
676
676
|
"src/styles/main.css",
|
|
677
|
+
"src/styles/themes.css",
|
|
677
678
|
"src/styles.css",
|
|
678
679
|
"styles/globals.css",
|
|
680
|
+
"styles/themes.css",
|
|
679
681
|
"styles.css",
|
|
680
682
|
"assets/css/main.css",
|
|
681
683
|
"src/index.css",
|
|
@@ -716,8 +718,15 @@ function extractCSSVariables(content) {
|
|
|
716
718
|
return { colors, variables };
|
|
717
719
|
}
|
|
718
720
|
function detectDarkMode(projectRoot, cssContents) {
|
|
721
|
+
const darkSelectors = [
|
|
722
|
+
/\.dark\b/i,
|
|
723
|
+
/html\.dark\b/i,
|
|
724
|
+
/\[data-theme\s*=\s*["']dark["']\]/i,
|
|
725
|
+
/prefers-color-scheme\s*:\s*dark/i,
|
|
726
|
+
/color-scheme\s*:\s*dark/i
|
|
727
|
+
];
|
|
719
728
|
for (const cssContent of cssContents) {
|
|
720
|
-
if (
|
|
729
|
+
if (darkSelectors.some((selector) => selector.test(cssContent))) {
|
|
721
730
|
return true;
|
|
722
731
|
}
|
|
723
732
|
}
|
|
@@ -763,6 +772,46 @@ function detectDarkMode(projectRoot, cssContents) {
|
|
|
763
772
|
}
|
|
764
773
|
return false;
|
|
765
774
|
}
|
|
775
|
+
function collectCssFiles(projectRoot) {
|
|
776
|
+
const seen = /* @__PURE__ */ new Set();
|
|
777
|
+
const ordered = [];
|
|
778
|
+
const add = (path) => {
|
|
779
|
+
if (seen.has(path)) return;
|
|
780
|
+
if (!existsSync3(join3(projectRoot, path))) return;
|
|
781
|
+
seen.add(path);
|
|
782
|
+
ordered.push(path);
|
|
783
|
+
};
|
|
784
|
+
for (const rel of GLOBALS_CSS_PATHS) add(rel);
|
|
785
|
+
for (const rel of DECANTR_STYLE_PATHS) add(rel);
|
|
786
|
+
const roots = ["src/styles", "styles", "assets/css", "src/app", "app"];
|
|
787
|
+
const visit = (dir) => {
|
|
788
|
+
const absolute = join3(projectRoot, dir);
|
|
789
|
+
if (!existsSync3(absolute)) return;
|
|
790
|
+
let entries;
|
|
791
|
+
try {
|
|
792
|
+
entries = readdirSync3(absolute);
|
|
793
|
+
} catch {
|
|
794
|
+
return;
|
|
795
|
+
}
|
|
796
|
+
for (const entry of entries) {
|
|
797
|
+
const child = join3(absolute, entry);
|
|
798
|
+
let stat;
|
|
799
|
+
try {
|
|
800
|
+
stat = statSync3(child);
|
|
801
|
+
} catch {
|
|
802
|
+
continue;
|
|
803
|
+
}
|
|
804
|
+
if (stat.isDirectory()) {
|
|
805
|
+
if (entry === "node_modules" || entry === ".next" || entry === "dist") continue;
|
|
806
|
+
visit(relative3(projectRoot, child).replace(/\\/g, "/"));
|
|
807
|
+
} else if (stat.isFile() && /\.css$/i.test(entry)) {
|
|
808
|
+
add(relative3(projectRoot, child).replace(/\\/g, "/"));
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
};
|
|
812
|
+
for (const root of roots) visit(root);
|
|
813
|
+
return ordered.slice(0, 80);
|
|
814
|
+
}
|
|
766
815
|
function scanStyling(projectRoot) {
|
|
767
816
|
let approach = "unknown";
|
|
768
817
|
let configFile;
|
|
@@ -811,23 +860,12 @@ function scanStyling(projectRoot) {
|
|
|
811
860
|
configFile = decantrStyleFiles.join(" + ");
|
|
812
861
|
}
|
|
813
862
|
const cssContents = [];
|
|
814
|
-
|
|
863
|
+
const cssFiles = collectCssFiles(projectRoot);
|
|
864
|
+
for (const rel of cssFiles) {
|
|
815
865
|
const fullPath = join3(projectRoot, rel);
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
} catch {
|
|
820
|
-
}
|
|
821
|
-
}
|
|
822
|
-
}
|
|
823
|
-
for (const rel of DECANTR_STYLE_PATHS) {
|
|
824
|
-
if (GLOBALS_CSS_PATHS.includes(rel)) continue;
|
|
825
|
-
const fullPath = join3(projectRoot, rel);
|
|
826
|
-
if (existsSync3(fullPath)) {
|
|
827
|
-
try {
|
|
828
|
-
cssContents.push(readFileSync3(fullPath, "utf-8"));
|
|
829
|
-
} catch {
|
|
830
|
-
}
|
|
866
|
+
try {
|
|
867
|
+
cssContents.push(readFileSync3(fullPath, "utf-8"));
|
|
868
|
+
} catch {
|
|
831
869
|
}
|
|
832
870
|
}
|
|
833
871
|
let colors = {};
|
|
@@ -841,7 +879,7 @@ function scanStyling(projectRoot) {
|
|
|
841
879
|
const darkMode = detectDarkMode(projectRoot, cssContents);
|
|
842
880
|
if (approach === "unknown" && cssContents.length > 0) {
|
|
843
881
|
approach = "css";
|
|
844
|
-
configFile =
|
|
882
|
+
configFile = cssFiles[0];
|
|
845
883
|
}
|
|
846
884
|
return {
|
|
847
885
|
approach,
|
|
@@ -1045,6 +1083,14 @@ function routeLabel(routes) {
|
|
|
1045
1083
|
if (routes.length <= 6) return routes.join(", ");
|
|
1046
1084
|
return `${routes.slice(0, 6).join(", ")} (+${routes.length - 6} more)`;
|
|
1047
1085
|
}
|
|
1086
|
+
function routePathname(route) {
|
|
1087
|
+
const queryIndex = route.indexOf("?");
|
|
1088
|
+
if (queryIndex === -1) return route;
|
|
1089
|
+
return route.slice(0, queryIndex) || "/";
|
|
1090
|
+
}
|
|
1091
|
+
function declaredRouteObserved(route, observedRoutes) {
|
|
1092
|
+
return observedRoutes.has(route) || route.includes("?") && observedRoutes.has(routePathname(route));
|
|
1093
|
+
}
|
|
1048
1094
|
function hasDoctrineEffect(essence, key) {
|
|
1049
1095
|
const effects = essence.dna.constraints?.effects;
|
|
1050
1096
|
return Boolean(effects && effects[key]);
|
|
@@ -1088,7 +1134,9 @@ function scanBrownfieldIssues(projectRoot, essence) {
|
|
|
1088
1134
|
const declaredRoutes = essenceRoutes(essence);
|
|
1089
1135
|
const observedRoutes = new Set(routes.routes.map((route) => route.path));
|
|
1090
1136
|
const missingFromEssence = [...observedRoutes].filter((route) => !declaredRoutes.has(route));
|
|
1091
|
-
const missingFromSource = [...declaredRoutes].filter(
|
|
1137
|
+
const missingFromSource = [...declaredRoutes].filter(
|
|
1138
|
+
(route) => !declaredRouteObserved(route, observedRoutes)
|
|
1139
|
+
);
|
|
1092
1140
|
if (routes.routes.length > 0 && declaredRoutes.size === 0) {
|
|
1093
1141
|
issues.push({
|
|
1094
1142
|
type: "error",
|
|
@@ -1206,11 +1254,11 @@ function scanBrownfieldIssues(projectRoot, essence) {
|
|
|
1206
1254
|
}
|
|
1207
1255
|
|
|
1208
1256
|
// src/guard-context.ts
|
|
1209
|
-
import { existsSync as existsSync7, readdirSync as
|
|
1257
|
+
import { existsSync as existsSync7, readdirSync as readdirSync5, readFileSync as readFileSync7 } from "fs";
|
|
1210
1258
|
import { join as join7 } from "path";
|
|
1211
1259
|
|
|
1212
1260
|
// src/bundled-content.ts
|
|
1213
|
-
import { existsSync as existsSync6, readdirSync as
|
|
1261
|
+
import { existsSync as existsSync6, readdirSync as readdirSync4, readFileSync as readFileSync6 } from "fs";
|
|
1214
1262
|
import { dirname, join as join6 } from "path";
|
|
1215
1263
|
import { fileURLToPath } from "url";
|
|
1216
1264
|
function bundledDirCandidates(contentType) {
|
|
@@ -1244,7 +1292,7 @@ function loadBundledContentList(contentType) {
|
|
|
1244
1292
|
for (const dir of bundledDirCandidates(contentType)) {
|
|
1245
1293
|
if (!existsSync6(dir)) continue;
|
|
1246
1294
|
try {
|
|
1247
|
-
for (const file of
|
|
1295
|
+
for (const file of readdirSync4(dir).filter((name) => name.endsWith(".json"))) {
|
|
1248
1296
|
const id = file.replace(/\.json$/, "");
|
|
1249
1297
|
if (seen.has(id)) continue;
|
|
1250
1298
|
const path = join6(dir, file);
|
|
@@ -1262,7 +1310,7 @@ function loadBundledContentList(contentType) {
|
|
|
1262
1310
|
function loadJsonEntries(dir) {
|
|
1263
1311
|
if (!existsSync7(dir)) return [];
|
|
1264
1312
|
try {
|
|
1265
|
-
return
|
|
1313
|
+
return readdirSync5(dir).filter((file) => file.endsWith(".json") && file !== "index.json").map((file) => JSON.parse(readFileSync7(join7(dir, file), "utf-8")));
|
|
1266
1314
|
} catch {
|
|
1267
1315
|
return [];
|
|
1268
1316
|
}
|
|
@@ -1307,8 +1355,8 @@ function buildGuardRegistryContext(projectRoot = process.cwd()) {
|
|
|
1307
1355
|
}
|
|
1308
1356
|
|
|
1309
1357
|
// src/lib/scan-interactions.ts
|
|
1310
|
-
import { existsSync as existsSync8, readdirSync as
|
|
1311
|
-
import { extname as extname2, join as join8, relative as
|
|
1358
|
+
import { existsSync as existsSync8, readdirSync as readdirSync6, readFileSync as readFileSync8, statSync as statSync4 } from "fs";
|
|
1359
|
+
import { extname as extname2, join as join8, relative as relative4 } from "path";
|
|
1312
1360
|
import { verifyInteractionsInSource } from "@decantr/verifier";
|
|
1313
1361
|
var SCAN_EXTENSIONS = /* @__PURE__ */ new Set([".tsx", ".jsx", ".ts", ".js", ".html", ".mdx"]);
|
|
1314
1362
|
var SKIP_DIRECTORIES = /* @__PURE__ */ new Set([
|
|
@@ -1344,7 +1392,7 @@ function walkSourceTree(rootDir) {
|
|
|
1344
1392
|
function walk2(dir) {
|
|
1345
1393
|
let entries;
|
|
1346
1394
|
try {
|
|
1347
|
-
entries =
|
|
1395
|
+
entries = readdirSync6(dir);
|
|
1348
1396
|
} catch {
|
|
1349
1397
|
return;
|
|
1350
1398
|
}
|
|
@@ -1353,11 +1401,11 @@ function walkSourceTree(rootDir) {
|
|
|
1353
1401
|
const fullPath = join8(dir, entry);
|
|
1354
1402
|
let s;
|
|
1355
1403
|
try {
|
|
1356
|
-
s =
|
|
1404
|
+
s = statSync4(fullPath);
|
|
1357
1405
|
} catch {
|
|
1358
1406
|
continue;
|
|
1359
1407
|
}
|
|
1360
|
-
const relativePath =
|
|
1408
|
+
const relativePath = relative4(rootDir, fullPath) || entry;
|
|
1361
1409
|
if (s.isDirectory()) {
|
|
1362
1410
|
walk2(fullPath);
|
|
1363
1411
|
} else if (s.isFile() && SCAN_EXTENSIONS.has(extname2(entry))) {
|
|
@@ -3780,14 +3780,36 @@ This project uses Decantr as a **contract and governance layer only**.
|
|
|
3780
3780
|
|
|
3781
3781
|
Do not install \`@decantr/css\`, rewrite the styling system, or add generated Decantr CSS files unless the task explicitly changes the adoption mode. Preserve the existing framework styling conventions and map them into the Decantr context before changing implementation files.
|
|
3782
3782
|
|
|
3783
|
-
Use \`.decantr/context/scaffold-pack.md\` and the matching section/page packs to understand visual intent, shell structure, and route contracts. Implement those contracts through the project's current CSS, component library, tokens, or design-system primitives
|
|
3783
|
+
Use \`.decantr/context/scaffold-pack.md\` and the matching section/page packs to understand visual intent, shell structure, and route contracts. Implement those contracts through the project's current CSS, component library, tokens, or design-system primitives.
|
|
3784
|
+
|
|
3785
|
+
### Interaction Requirements
|
|
3786
|
+
|
|
3787
|
+
Every pattern declares its required interactions in its page-pack \`Interactions\` checklist. A declared interaction must be implemented in source through the project's existing component library, CSS, or event-handler patterns.
|
|
3788
|
+
|
|
3789
|
+
| Declared interaction | Canonical implementation shape |
|
|
3790
|
+
|----------------------|--------------------------------|
|
|
3791
|
+
| \`animate-on-mount\` | Entrance animation class or component transition on the pattern root |
|
|
3792
|
+
| \`stagger-children\` | Parent stagger class or animation delay driven by child index |
|
|
3793
|
+
| \`keyboard-navigation\` | Arrow-key/Enter/Space handlers with visible focus state |
|
|
3794
|
+
| \`ripple-click\` | \`d-ripple\` or an equivalent click feedback class on the interactive surface |`;
|
|
3784
3795
|
var STYLE_BRIDGE_CSS_APPROACH = `## Styling Adoption
|
|
3785
3796
|
|
|
3786
3797
|
This project uses Decantr in **style-bridge** mode.
|
|
3787
3798
|
|
|
3788
3799
|
Decantr may generate lightweight bridge files such as \`src/styles/tokens.css\` and \`src/styles/decantr-bridge.css\`, but \`@decantr/css\` is not required. Treat these files as a mapping layer between Decantr context and the app's existing styling system.
|
|
3789
3800
|
|
|
3790
|
-
Preserve the current CSS framework/component library. Use Decantr tokens and bridge classes only where they clarify design intent without replacing the app's established styling conventions
|
|
3801
|
+
Preserve the current CSS framework/component library. Use Decantr tokens and bridge classes only where they clarify design intent without replacing the app's established styling conventions.
|
|
3802
|
+
|
|
3803
|
+
### Interaction Requirements
|
|
3804
|
+
|
|
3805
|
+
Every pattern declares its required interactions in its page-pack \`Interactions\` checklist. A declared interaction must be implemented in source through the project's existing component library, CSS, or event-handler patterns.
|
|
3806
|
+
|
|
3807
|
+
| Declared interaction | Canonical implementation shape |
|
|
3808
|
+
|----------------------|--------------------------------|
|
|
3809
|
+
| \`animate-on-mount\` | Entrance animation class or component transition on the pattern root |
|
|
3810
|
+
| \`stagger-children\` | Parent stagger class or animation delay driven by child index |
|
|
3811
|
+
| \`keyboard-navigation\` | Arrow-key/Enter/Space handlers with visible focus state |
|
|
3812
|
+
| \`ripple-click\` | \`d-ripple\` or an equivalent click feedback class on the interactive surface |`;
|
|
3791
3813
|
function getCssApproachContent(adoptionMode) {
|
|
3792
3814
|
if (adoptionMode === "contract-only") return CONTRACT_ONLY_CSS_APPROACH;
|
|
3793
3815
|
if (adoptionMode === "style-bridge") return STYLE_BRIDGE_CSS_APPROACH;
|
|
@@ -10,8 +10,8 @@ import {
|
|
|
10
10
|
renderProjectHealthCiWorkflow,
|
|
11
11
|
shouldFailHealth,
|
|
12
12
|
writeProjectHealthCiWorkflow
|
|
13
|
-
} from "./chunk-
|
|
14
|
-
import "./chunk-
|
|
13
|
+
} from "./chunk-3A2DLR47.js";
|
|
14
|
+
import "./chunk-MNZKOZW7.js";
|
|
15
15
|
export {
|
|
16
16
|
cmdHealth,
|
|
17
17
|
collectDesignTokenEvidence,
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import "./chunk-
|
|
2
|
-
import "./chunk-
|
|
3
|
-
import "./chunk-
|
|
4
|
-
import "./chunk-
|
|
5
|
-
import "./chunk-
|
|
1
|
+
import "./chunk-5MZH6XXQ.js";
|
|
2
|
+
import "./chunk-SIDKK73N.js";
|
|
3
|
+
import "./chunk-YBSBAJ3E.js";
|
|
4
|
+
import "./chunk-3A2DLR47.js";
|
|
5
|
+
import "./chunk-MNZKOZW7.js";
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createWorkspaceHealthReport
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-YBSBAJ3E.js";
|
|
4
4
|
import {
|
|
5
5
|
createProjectHealthReport
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-3A2DLR47.js";
|
|
7
7
|
import {
|
|
8
8
|
sendStudioHealthRefreshedTelemetry,
|
|
9
9
|
sendStudioStartedTelemetry
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-MNZKOZW7.js";
|
|
11
11
|
|
|
12
12
|
// src/commands/studio.ts
|
|
13
13
|
import { readFileSync } from "fs";
|
|
@@ -7,9 +7,9 @@ import {
|
|
|
7
7
|
listWorkspaceProjects,
|
|
8
8
|
parseWorkspaceArgs,
|
|
9
9
|
shouldFailWorkspaceHealth
|
|
10
|
-
} from "./chunk-
|
|
11
|
-
import "./chunk-
|
|
12
|
-
import "./chunk-
|
|
10
|
+
} from "./chunk-YBSBAJ3E.js";
|
|
11
|
+
import "./chunk-3A2DLR47.js";
|
|
12
|
+
import "./chunk-MNZKOZW7.js";
|
|
13
13
|
export {
|
|
14
14
|
cmdWorkspace,
|
|
15
15
|
createWorkspaceHealthReport,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@decantr/cli",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.13.0",
|
|
4
4
|
"description": "Decantr CLI - scaffold, audit, inspect Project Health, and maintain Decantr projects from the terminal",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"decantr",
|
|
@@ -49,10 +49,10 @@
|
|
|
49
49
|
"dependencies": {
|
|
50
50
|
"ajv": "^8.20.0",
|
|
51
51
|
"@decantr/core": "2.1.0",
|
|
52
|
-
"@decantr/telemetry": "2.2.1",
|
|
53
52
|
"@decantr/essence-spec": "2.0.1",
|
|
54
|
-
"@decantr/
|
|
55
|
-
"@decantr/registry": "2.2.0"
|
|
53
|
+
"@decantr/telemetry": "2.2.1",
|
|
54
|
+
"@decantr/registry": "2.2.0",
|
|
55
|
+
"@decantr/verifier": "2.5.0"
|
|
56
56
|
},
|
|
57
57
|
"scripts": {
|
|
58
58
|
"build": "tsup",
|