@decantr/cli 3.1.0 → 3.4.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/dist/bin.js +4 -4
- package/dist/{chunk-TXNLMAN5.js → chunk-EL4KSW7E.js} +1 -1
- package/dist/{chunk-GPN2THFD.js → chunk-XINHWP4T.js} +30 -2
- package/dist/{chunk-BY6S6IWG.js → chunk-XUHPMETF.js} +483 -28
- package/dist/{chunk-WSL6ZSTZ.js → chunk-ZBGL7RID.js} +11 -11
- package/dist/{heal-2DKBFWB6.js → heal-ZY4BX5HU.js} +1 -1
- package/dist/{health-IOTIZT7Z.js → health-H2256NIM.js} +2 -2
- package/dist/index.js +4 -4
- package/dist/{studio-DLWUMCC3.js → studio-UKSCSRX7.js} +3 -3
- package/dist/{workspace-72SJI3MW.js → workspace-SR6ZGG2E.js} +3 -3
- package/package.json +6 -6
package/dist/bin.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import "./chunk-
|
|
2
|
+
import "./chunk-ZBGL7RID.js";
|
|
3
3
|
import "./chunk-SIDKK73N.js";
|
|
4
|
-
import "./chunk-
|
|
5
|
-
import "./chunk-
|
|
6
|
-
import "./chunk-
|
|
4
|
+
import "./chunk-EL4KSW7E.js";
|
|
5
|
+
import "./chunk-XUHPMETF.js";
|
|
6
|
+
import "./chunk-XINHWP4T.js";
|
|
@@ -737,8 +737,8 @@ function extractCSSVariables(content) {
|
|
|
737
737
|
const colors = {};
|
|
738
738
|
const variables = [];
|
|
739
739
|
const varRegex = /--([\w-]+)\s*:\s*([^;]+)/g;
|
|
740
|
-
let match;
|
|
741
|
-
while (
|
|
740
|
+
let match = varRegex.exec(content);
|
|
741
|
+
while (match !== null) {
|
|
742
742
|
const name = match[1];
|
|
743
743
|
const value = match[2].trim();
|
|
744
744
|
variables.push(`--${name}`);
|
|
@@ -758,6 +758,24 @@ function extractCSSVariables(content) {
|
|
|
758
758
|
if (value.startsWith("#") || value.startsWith("rgb") || value.startsWith("hsl") || colorPatterns.some((p) => name.includes(p))) {
|
|
759
759
|
colors[name] = value;
|
|
760
760
|
}
|
|
761
|
+
match = varRegex.exec(content);
|
|
762
|
+
}
|
|
763
|
+
return { colors, variables };
|
|
764
|
+
}
|
|
765
|
+
function extractTailwindThemeTokens(content) {
|
|
766
|
+
const colors = {};
|
|
767
|
+
const variables = [];
|
|
768
|
+
for (const match of content.matchAll(
|
|
769
|
+
/\b([a-zA-Z][\w-]*)\s*:\s*['"`](#[0-9a-fA-F]{3,8}|rgba?\([^)]+\)|hsla?\([^)]+\)|oklch\([^)]+\)|var\(--[^)]+\))['"`]/g
|
|
770
|
+
)) {
|
|
771
|
+
const name = match[1];
|
|
772
|
+
const value = match[2];
|
|
773
|
+
if (/color|bg|background|surface|text|foreground|border|primary|secondary|accent|muted|danger|error|success|warning/i.test(
|
|
774
|
+
name
|
|
775
|
+
) || /^#|^(?:rgba?|hsla?|oklch)\(/i.test(value) || /^var\(--/i.test(value)) {
|
|
776
|
+
colors[name] = value;
|
|
777
|
+
variables.push(`theme.colors.${name}`);
|
|
778
|
+
}
|
|
761
779
|
}
|
|
762
780
|
return { colors, variables };
|
|
763
781
|
}
|
|
@@ -919,6 +937,16 @@ function scanStyling(projectRoot) {
|
|
|
919
937
|
colors = { ...colors, ...extracted.colors };
|
|
920
938
|
cssVariables.push(...extracted.variables);
|
|
921
939
|
}
|
|
940
|
+
for (const cfg of TAILWIND_CONFIGS) {
|
|
941
|
+
const configPath = join3(projectRoot, cfg);
|
|
942
|
+
if (!existsSync3(configPath)) continue;
|
|
943
|
+
try {
|
|
944
|
+
const extracted = extractTailwindThemeTokens(readFileSync3(configPath, "utf-8"));
|
|
945
|
+
colors = { ...colors, ...extracted.colors };
|
|
946
|
+
cssVariables.push(...extracted.variables);
|
|
947
|
+
} catch {
|
|
948
|
+
}
|
|
949
|
+
}
|
|
922
950
|
cssVariables = [...new Set(cssVariables)];
|
|
923
951
|
const darkMode = detectDarkMode(projectRoot, cssContents);
|
|
924
952
|
if (approach === "unknown" && cssContents.length > 0) {
|
|
@@ -3,12 +3,12 @@ import {
|
|
|
3
3
|
sendProjectHealthCiFailedTelemetry,
|
|
4
4
|
sendProjectHealthPromptTelemetry,
|
|
5
5
|
sendProjectHealthReportTelemetry
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-XINHWP4T.js";
|
|
7
7
|
|
|
8
8
|
// src/commands/health.ts
|
|
9
9
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
10
10
|
import { createHash as createHash2 } from "crypto";
|
|
11
|
-
import { existsSync as existsSync5, mkdirSync as mkdirSync4, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "fs";
|
|
11
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync4, readFileSync as readFileSync5, realpathSync, writeFileSync as writeFileSync4 } from "fs";
|
|
12
12
|
import { createRequire } from "module";
|
|
13
13
|
import { dirname as dirname3, isAbsolute as isAbsolute4, join as join5, relative as relative3, resolve as resolve3 } from "path";
|
|
14
14
|
import { fileURLToPath } from "url";
|
|
@@ -1261,6 +1261,19 @@ function colorTokenNames(styling) {
|
|
|
1261
1261
|
}
|
|
1262
1262
|
return [...names].slice(0, 40);
|
|
1263
1263
|
}
|
|
1264
|
+
function firstCssVariable(styling, terms) {
|
|
1265
|
+
return styling.cssVariables.find((name) => terms.test(name)) ?? null;
|
|
1266
|
+
}
|
|
1267
|
+
function firstClassHint(projectRoot, ids) {
|
|
1268
|
+
return classHintsForPattern(projectRoot, ids)[0] ?? null;
|
|
1269
|
+
}
|
|
1270
|
+
function nativeRefForMapping(input) {
|
|
1271
|
+
const cssVariable = firstCssVariable(input.styling, input.tokenTerms);
|
|
1272
|
+
if (cssVariable) return { kind: "css-var", ref: cssVariable };
|
|
1273
|
+
const classHint = firstClassHint(input.projectRoot, input.patternIds);
|
|
1274
|
+
if (classHint) return { kind: "class", ref: classHint };
|
|
1275
|
+
return { kind: "class", ref: input.fallbackClass };
|
|
1276
|
+
}
|
|
1264
1277
|
function createStyleBridgeProposal(input) {
|
|
1265
1278
|
const generatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1266
1279
|
const theme = readThemeInventory(input.projectRoot);
|
|
@@ -1272,7 +1285,7 @@ function createStyleBridgeProposal(input) {
|
|
|
1272
1285
|
const themeModes = theme.modes.length > 0 ? theme.modes : darkModeDetected ? ["base", "dark"] : ["base"];
|
|
1273
1286
|
const themeVariantIds = theme.variantIds.length > 0 ? theme.variantIds : themeModes.filter((mode) => mode !== "base");
|
|
1274
1287
|
return {
|
|
1275
|
-
version:
|
|
1288
|
+
version: 2,
|
|
1276
1289
|
status: "proposal",
|
|
1277
1290
|
generatedAt,
|
|
1278
1291
|
source: "decantr codify --style-bridge",
|
|
@@ -1312,6 +1325,17 @@ function createStyleBridgeProposal(input) {
|
|
|
1312
1325
|
label: "Surfaces and cards",
|
|
1313
1326
|
decantrIntent: "surface background, card treatment, border, radius, depth, and hover state",
|
|
1314
1327
|
projectAuthority: "Use the app card/surface primitives, tokens, and accepted local law.",
|
|
1328
|
+
native: nativeRefForMapping({
|
|
1329
|
+
projectRoot: input.projectRoot,
|
|
1330
|
+
styling: input.styling,
|
|
1331
|
+
patternIds: ["surface-card"],
|
|
1332
|
+
tokenTerms: /surface|card|panel|bg|background|border|shadow|radius/i,
|
|
1333
|
+
fallbackClass: "surface-card"
|
|
1334
|
+
}),
|
|
1335
|
+
essence: { kind: "treatment", ref: "surface" },
|
|
1336
|
+
confidence: 0.7,
|
|
1337
|
+
source: "inferred",
|
|
1338
|
+
property: "surface",
|
|
1315
1339
|
tokenHints: tokenHints(
|
|
1316
1340
|
input.styling,
|
|
1317
1341
|
/surface|card|panel|bg|background|border|shadow|radius/i
|
|
@@ -1328,6 +1352,17 @@ function createStyleBridgeProposal(input) {
|
|
|
1328
1352
|
label: "Actions and buttons",
|
|
1329
1353
|
decantrIntent: "primary, secondary, tertiary, destructive, icon-only, loading, and disabled action states",
|
|
1330
1354
|
projectAuthority: "Use the app button/action primitives and local variant names.",
|
|
1355
|
+
native: nativeRefForMapping({
|
|
1356
|
+
projectRoot: input.projectRoot,
|
|
1357
|
+
styling: input.styling,
|
|
1358
|
+
patternIds: ["button"],
|
|
1359
|
+
tokenTerms: /primary|secondary|accent|danger|error|destructive|focus/i,
|
|
1360
|
+
fallbackClass: "button"
|
|
1361
|
+
}),
|
|
1362
|
+
essence: { kind: "treatment", ref: "action" },
|
|
1363
|
+
confidence: 0.72,
|
|
1364
|
+
source: "inferred",
|
|
1365
|
+
property: "color",
|
|
1331
1366
|
tokenHints: tokenHints(
|
|
1332
1367
|
input.styling,
|
|
1333
1368
|
/primary|secondary|accent|danger|error|destructive|focus/i
|
|
@@ -1344,6 +1379,17 @@ function createStyleBridgeProposal(input) {
|
|
|
1344
1379
|
label: "Focus and accessibility",
|
|
1345
1380
|
decantrIntent: "visible focus, keyboard clarity, contrast, and reduced-motion safety",
|
|
1346
1381
|
projectAuthority: "Use the app accessibility classes, focus tokens, and framework conventions.",
|
|
1382
|
+
native: nativeRefForMapping({
|
|
1383
|
+
projectRoot: input.projectRoot,
|
|
1384
|
+
styling: input.styling,
|
|
1385
|
+
patternIds: [],
|
|
1386
|
+
tokenTerms: /focus|ring|outline|contrast|motion|duration/i,
|
|
1387
|
+
fallbackClass: "focus-visible"
|
|
1388
|
+
}),
|
|
1389
|
+
essence: { kind: "behavior", ref: "focus-accessibility" },
|
|
1390
|
+
confidence: 0.66,
|
|
1391
|
+
source: "inferred",
|
|
1392
|
+
property: "focus",
|
|
1347
1393
|
tokenHints: tokenHints(input.styling, /focus|ring|outline|contrast|motion|duration/i),
|
|
1348
1394
|
classHints: [],
|
|
1349
1395
|
sourceEvidence: [],
|
|
@@ -1357,6 +1403,17 @@ function createStyleBridgeProposal(input) {
|
|
|
1357
1403
|
label: "Layout density and spacing",
|
|
1358
1404
|
decantrIntent: "route gutters, section gaps, component padding, density, and responsive rhythm",
|
|
1359
1405
|
projectAuthority: "Use existing layout wrappers, shell primitives, and spacing tokens/classes.",
|
|
1406
|
+
native: nativeRefForMapping({
|
|
1407
|
+
projectRoot: input.projectRoot,
|
|
1408
|
+
styling: input.styling,
|
|
1409
|
+
patternIds: ["page-shell"],
|
|
1410
|
+
tokenTerms: /space|spacing|gap|gutter|container|radius/i,
|
|
1411
|
+
fallbackClass: "page-shell"
|
|
1412
|
+
}),
|
|
1413
|
+
essence: { kind: "layout", ref: "density-spacing" },
|
|
1414
|
+
confidence: 0.68,
|
|
1415
|
+
source: "inferred",
|
|
1416
|
+
property: "spacing",
|
|
1360
1417
|
tokenHints: tokenHints(input.styling, /space|spacing|gap|gutter|container|radius/i),
|
|
1361
1418
|
classHints: classHintsForPattern(input.projectRoot, ["page-shell"]),
|
|
1362
1419
|
sourceEvidence: sourceEvidence(input.projectRoot, ["page-shell"]),
|
|
@@ -1370,6 +1427,17 @@ function createStyleBridgeProposal(input) {
|
|
|
1370
1427
|
label: "Theme variants",
|
|
1371
1428
|
decantrIntent: "light, dark, brand, tenant, seasonal, and density variants",
|
|
1372
1429
|
projectAuthority: "Use the app theme provider, data attributes, CSS variables, or Tailwind mode strategy.",
|
|
1430
|
+
native: nativeRefForMapping({
|
|
1431
|
+
projectRoot: input.projectRoot,
|
|
1432
|
+
styling: input.styling,
|
|
1433
|
+
patternIds: ["theme-variant"],
|
|
1434
|
+
tokenTerms: /theme|dark|light|brand|tenant|mode|color/i,
|
|
1435
|
+
fallbackClass: "theme-variant"
|
|
1436
|
+
}),
|
|
1437
|
+
essence: { kind: "token", ref: "theme-variant" },
|
|
1438
|
+
confidence: 0.64,
|
|
1439
|
+
source: "inferred",
|
|
1440
|
+
property: "theme",
|
|
1373
1441
|
tokenHints: tokenHints(input.styling, /theme|dark|light|brand|tenant|mode|color/i),
|
|
1374
1442
|
classHints: classHintsForPattern(input.projectRoot, ["theme-variant"]),
|
|
1375
1443
|
sourceEvidence: sourceEvidence(input.projectRoot, ["theme-variant"]),
|
|
@@ -1453,6 +1521,11 @@ function styleBridgeMatches(projectRoot, query) {
|
|
|
1453
1521
|
mapping.label,
|
|
1454
1522
|
mapping.decantrIntent,
|
|
1455
1523
|
mapping.projectAuthority,
|
|
1524
|
+
mapping.native?.ref,
|
|
1525
|
+
mapping.native?.kind,
|
|
1526
|
+
mapping.essence?.ref,
|
|
1527
|
+
mapping.essence?.kind,
|
|
1528
|
+
mapping.property,
|
|
1456
1529
|
...mapping.tokenHints,
|
|
1457
1530
|
...mapping.classHints,
|
|
1458
1531
|
...mapping.guardrails
|
|
@@ -3143,6 +3216,20 @@ var DEFAULT_HEALTH_CI_REPORT_PATH = "decantr-health.md";
|
|
|
3143
3216
|
var DEFAULT_HEALTH_CI_JSON_PATH = "decantr-health.json";
|
|
3144
3217
|
var DEFAULT_HEALTH_CI_CLI_VERSION = "latest";
|
|
3145
3218
|
var __dirname = dirname3(fileURLToPath(import.meta.url));
|
|
3219
|
+
var HEALTH_BROWSER_RUNTIME_DIAGNOSTICS = [
|
|
3220
|
+
{
|
|
3221
|
+
rule: "browser-runtime-probes-failed",
|
|
3222
|
+
code: "RUNTIME010",
|
|
3223
|
+
repairId: "repair-browser-runtime-probes",
|
|
3224
|
+
family: "RUNTIME"
|
|
3225
|
+
},
|
|
3226
|
+
{
|
|
3227
|
+
rule: "browser-axe-violations",
|
|
3228
|
+
code: "A11Y020",
|
|
3229
|
+
repairId: "fix-rendered-accessibility",
|
|
3230
|
+
family: "A11Y"
|
|
3231
|
+
}
|
|
3232
|
+
];
|
|
3146
3233
|
function readProjectMetadata(projectRoot) {
|
|
3147
3234
|
const projectJsonPath = join5(projectRoot, ".decantr", "project.json");
|
|
3148
3235
|
if (!existsSync5(projectJsonPath)) {
|
|
@@ -3861,6 +3948,304 @@ function loadProjectPlaywright(projectRoot) {
|
|
|
3861
3948
|
}
|
|
3862
3949
|
return null;
|
|
3863
3950
|
}
|
|
3951
|
+
var KNOWN_INTERACTION_STYLE_CLASSES = [
|
|
3952
|
+
"d-enter-fade",
|
|
3953
|
+
"d-enter-slide-up",
|
|
3954
|
+
"d-enter-scale",
|
|
3955
|
+
"d-stagger-children",
|
|
3956
|
+
"d-pulse",
|
|
3957
|
+
"d-pulse-ring",
|
|
3958
|
+
"d-shimmer",
|
|
3959
|
+
"d-float",
|
|
3960
|
+
"d-glow-hover",
|
|
3961
|
+
"d-lift-hover",
|
|
3962
|
+
"d-scale-hover",
|
|
3963
|
+
"d-ripple"
|
|
3964
|
+
];
|
|
3965
|
+
function compactBrowserEvidence(value) {
|
|
3966
|
+
return value.replace(/\s+/g, " ").trim().slice(0, 240);
|
|
3967
|
+
}
|
|
3968
|
+
function browserErrorMessage(error) {
|
|
3969
|
+
return compactBrowserEvidence(error instanceof Error ? error.message : String(error));
|
|
3970
|
+
}
|
|
3971
|
+
function isPathInside(parentPath, childPath) {
|
|
3972
|
+
const parentRealPath = realpathSync(parentPath);
|
|
3973
|
+
const childRealPath = realpathSync(childPath);
|
|
3974
|
+
const relativePath = relative3(parentRealPath, childRealPath);
|
|
3975
|
+
return relativePath === "" || !relativePath.startsWith("..") && !isAbsolute4(relativePath);
|
|
3976
|
+
}
|
|
3977
|
+
function loadProjectAxeCore(projectRoot) {
|
|
3978
|
+
try {
|
|
3979
|
+
const requireFromProject = createRequire(join5(projectRoot, "package.json"));
|
|
3980
|
+
const resolved = requireFromProject.resolve("axe-core");
|
|
3981
|
+
const workspaceRoot = resolveWorkspaceInfo(projectRoot).workspaceRoot;
|
|
3982
|
+
const resolvedInProject = [projectRoot, workspaceRoot].some(
|
|
3983
|
+
(root) => isPathInside(root, resolved)
|
|
3984
|
+
);
|
|
3985
|
+
if (!resolvedInProject) return null;
|
|
3986
|
+
const loaded = requireFromProject("axe-core");
|
|
3987
|
+
return typeof loaded.source === "string" && loaded.source.length > 0 ? { source: loaded.source } : null;
|
|
3988
|
+
} catch {
|
|
3989
|
+
return null;
|
|
3990
|
+
}
|
|
3991
|
+
}
|
|
3992
|
+
function consoleErrorMessage(message) {
|
|
3993
|
+
try {
|
|
3994
|
+
const type = typeof message.type === "function" ? message.type() : "error";
|
|
3995
|
+
if (type !== "error") return null;
|
|
3996
|
+
const text = typeof message.text === "function" ? message.text() : "Console error";
|
|
3997
|
+
return compactBrowserEvidence(text || "Console error");
|
|
3998
|
+
} catch {
|
|
3999
|
+
return "Console error event could not be read.";
|
|
4000
|
+
}
|
|
4001
|
+
}
|
|
4002
|
+
function consoleProbe(messages) {
|
|
4003
|
+
return {
|
|
4004
|
+
status: messages.length > 0 ? "failed" : "passed",
|
|
4005
|
+
count: messages.length,
|
|
4006
|
+
messages: messages.slice(0, 5)
|
|
4007
|
+
};
|
|
4008
|
+
}
|
|
4009
|
+
function fallbackRuntimeDomSnapshot(reason) {
|
|
4010
|
+
return {
|
|
4011
|
+
routeRendered: {
|
|
4012
|
+
status: "failed",
|
|
4013
|
+
readyState: null,
|
|
4014
|
+
url: null,
|
|
4015
|
+
title: null,
|
|
4016
|
+
bodyPresent: false,
|
|
4017
|
+
appRootPresent: false,
|
|
4018
|
+
bodyChildCount: 0,
|
|
4019
|
+
reason
|
|
4020
|
+
},
|
|
4021
|
+
nonblankDom: {
|
|
4022
|
+
status: "failed",
|
|
4023
|
+
textLength: 0,
|
|
4024
|
+
meaningfulElementCount: 0,
|
|
4025
|
+
mediaElementCount: 0,
|
|
4026
|
+
controlElementCount: 0,
|
|
4027
|
+
reason
|
|
4028
|
+
},
|
|
4029
|
+
interactionStyles: {
|
|
4030
|
+
status: "skipped",
|
|
4031
|
+
checked: 0,
|
|
4032
|
+
matchedClasses: [],
|
|
4033
|
+
animatedOrTransitioned: 0,
|
|
4034
|
+
missing: [],
|
|
4035
|
+
reason
|
|
4036
|
+
}
|
|
4037
|
+
};
|
|
4038
|
+
}
|
|
4039
|
+
async function collectRuntimeDomSnapshot(page) {
|
|
4040
|
+
try {
|
|
4041
|
+
return await page.evaluate((knownInteractionClasses) => {
|
|
4042
|
+
const global = globalThis;
|
|
4043
|
+
const document = global.document;
|
|
4044
|
+
const body = document?.body;
|
|
4045
|
+
const readyState = typeof document?.readyState === "string" ? document.readyState : null;
|
|
4046
|
+
const title = typeof document?.title === "string" ? document.title : null;
|
|
4047
|
+
const url = typeof global.location?.href === "string" ? global.location.href : null;
|
|
4048
|
+
const querySelector = typeof document?.querySelector === "function" ? document.querySelector : null;
|
|
4049
|
+
const querySelectorAll = typeof document?.querySelectorAll === "function" ? document.querySelectorAll : null;
|
|
4050
|
+
const bodyChildCount = typeof body?.childElementCount === "number" ? body.childElementCount : 0;
|
|
4051
|
+
const appRootPresent = Boolean(
|
|
4052
|
+
querySelector?.('[data-decantr-root], #root, #app, main, [role="main"], body > *')
|
|
4053
|
+
);
|
|
4054
|
+
const routeRendered = Boolean(body) && readyState !== "loading" && (appRootPresent || bodyChildCount > 0);
|
|
4055
|
+
const rawElements = querySelectorAll ? querySelectorAll("body *") : [];
|
|
4056
|
+
const elements = Array.from(rawElements);
|
|
4057
|
+
const text = String(body?.innerText ?? body?.textContent ?? "").replace(/\s+/g, " ").trim();
|
|
4058
|
+
const mediaTags = /* @__PURE__ */ new Set(["IMG", "SVG", "CANVAS", "VIDEO", "PICTURE"]);
|
|
4059
|
+
const controlTags = /* @__PURE__ */ new Set(["A", "BUTTON", "INPUT", "SELECT", "TEXTAREA", "SUMMARY"]);
|
|
4060
|
+
const elementTag = (element) => typeof element.tagName === "string" ? element.tagName.toUpperCase() : "";
|
|
4061
|
+
const elementText = (element) => String(element.textContent ?? "").replace(/\s+/g, " ").trim();
|
|
4062
|
+
const elementAttribute = (element, name) => typeof element.getAttribute === "function" ? String(element.getAttribute(name) ?? "").trim() : "";
|
|
4063
|
+
const mediaElementCount = elements.filter(
|
|
4064
|
+
(element) => mediaTags.has(elementTag(element))
|
|
4065
|
+
).length;
|
|
4066
|
+
const controlElementCount = elements.filter(
|
|
4067
|
+
(element) => controlTags.has(elementTag(element))
|
|
4068
|
+
).length;
|
|
4069
|
+
const meaningfulElementCount = elements.filter((element) => {
|
|
4070
|
+
const tag = elementTag(element);
|
|
4071
|
+
return elementText(element).length > 0 || mediaTags.has(tag) || controlTags.has(tag) || elementAttribute(element, "aria-label").length > 0 || elementAttribute(element, "alt").length > 0 || elementAttribute(element, "title").length > 0;
|
|
4072
|
+
}).length;
|
|
4073
|
+
const nonblank = text.length > 0 || meaningfulElementCount > 0 || mediaElementCount > 0 || controlElementCount > 0;
|
|
4074
|
+
const durationHasTime = (value) => String(value ?? "").split(",").some((part) => {
|
|
4075
|
+
const trimmed = part.trim();
|
|
4076
|
+
if (!trimmed) return false;
|
|
4077
|
+
if (trimmed.endsWith("ms")) return Number.parseFloat(trimmed) > 0;
|
|
4078
|
+
if (trimmed.endsWith("s")) return Number.parseFloat(trimmed) > 0;
|
|
4079
|
+
return Number.parseFloat(trimmed) > 0;
|
|
4080
|
+
});
|
|
4081
|
+
const classListContains = (element, className) => {
|
|
4082
|
+
const classList = element.classList;
|
|
4083
|
+
if (typeof classList?.contains === "function") return classList.contains(className);
|
|
4084
|
+
return String(element.className ?? "").split(/\s+/).includes(className);
|
|
4085
|
+
};
|
|
4086
|
+
const styleTargets = elements.map((element) => ({
|
|
4087
|
+
element,
|
|
4088
|
+
classes: knownInteractionClasses.filter(
|
|
4089
|
+
(className) => classListContains(element, className)
|
|
4090
|
+
)
|
|
4091
|
+
})).filter((entry) => entry.classes.length > 0);
|
|
4092
|
+
const matchedClasses = [...new Set(styleTargets.flatMap((entry) => entry.classes))].sort();
|
|
4093
|
+
const missing = /* @__PURE__ */ new Set();
|
|
4094
|
+
let animatedOrTransitioned = 0;
|
|
4095
|
+
for (const entry of styleTargets) {
|
|
4096
|
+
const computed = typeof global.getComputedStyle === "function" ? global.getComputedStyle(entry.element) : {};
|
|
4097
|
+
const animationName = String(computed.animationName ?? "none");
|
|
4098
|
+
const transitionProperty = String(computed.transitionProperty ?? "none");
|
|
4099
|
+
const hasAnimation = animationName !== "none" && durationHasTime(computed.animationDuration);
|
|
4100
|
+
const hasTransition = transitionProperty !== "none" && durationHasTime(computed.transitionDuration);
|
|
4101
|
+
if (hasAnimation || hasTransition) {
|
|
4102
|
+
animatedOrTransitioned += 1;
|
|
4103
|
+
} else {
|
|
4104
|
+
for (const className of entry.classes) missing.add(className);
|
|
4105
|
+
}
|
|
4106
|
+
}
|
|
4107
|
+
const interactionStatus = styleTargets.length === 0 ? "skipped" : missing.size === 0 ? "passed" : "failed";
|
|
4108
|
+
return {
|
|
4109
|
+
routeRendered: {
|
|
4110
|
+
status: routeRendered ? "passed" : "failed",
|
|
4111
|
+
readyState,
|
|
4112
|
+
url,
|
|
4113
|
+
title,
|
|
4114
|
+
bodyPresent: Boolean(body),
|
|
4115
|
+
appRootPresent,
|
|
4116
|
+
bodyChildCount,
|
|
4117
|
+
...routeRendered ? {} : { reason: "No rendered app root or body content was detected after navigation." }
|
|
4118
|
+
},
|
|
4119
|
+
nonblankDom: {
|
|
4120
|
+
status: nonblank ? "passed" : "failed",
|
|
4121
|
+
textLength: text.length,
|
|
4122
|
+
meaningfulElementCount,
|
|
4123
|
+
mediaElementCount,
|
|
4124
|
+
controlElementCount,
|
|
4125
|
+
...nonblank ? {} : {
|
|
4126
|
+
reason: "DOM rendered, but no meaningful text, media, controls, or labels were detected."
|
|
4127
|
+
}
|
|
4128
|
+
},
|
|
4129
|
+
interactionStyles: {
|
|
4130
|
+
status: interactionStatus,
|
|
4131
|
+
checked: styleTargets.length,
|
|
4132
|
+
matchedClasses,
|
|
4133
|
+
animatedOrTransitioned,
|
|
4134
|
+
missing: [...missing].slice(0, 8),
|
|
4135
|
+
...styleTargets.length === 0 ? { reason: "No known Decantr interaction classes were present on this route." } : {}
|
|
4136
|
+
}
|
|
4137
|
+
};
|
|
4138
|
+
}, KNOWN_INTERACTION_STYLE_CLASSES);
|
|
4139
|
+
} catch (error) {
|
|
4140
|
+
return fallbackRuntimeDomSnapshot(`Runtime DOM probe failed: ${browserErrorMessage(error)}`);
|
|
4141
|
+
}
|
|
4142
|
+
}
|
|
4143
|
+
function skippedAccessibilityProbe(reason) {
|
|
4144
|
+
return {
|
|
4145
|
+
status: "skipped",
|
|
4146
|
+
engine: "axe-core",
|
|
4147
|
+
violations: 0,
|
|
4148
|
+
incomplete: 0,
|
|
4149
|
+
messages: [],
|
|
4150
|
+
reason
|
|
4151
|
+
};
|
|
4152
|
+
}
|
|
4153
|
+
async function collectAccessibilityProbe(page, axeCore) {
|
|
4154
|
+
if (!axeCore) return skippedAccessibilityProbe("axe-core is not installed in this project.");
|
|
4155
|
+
if (!page.addScriptTag) {
|
|
4156
|
+
return skippedAccessibilityProbe("The local Playwright adapter does not expose addScriptTag.");
|
|
4157
|
+
}
|
|
4158
|
+
try {
|
|
4159
|
+
await page.addScriptTag({ content: axeCore.source });
|
|
4160
|
+
const result = await page.evaluate(() => {
|
|
4161
|
+
const global = globalThis;
|
|
4162
|
+
if (!global.axe?.run) return { error: "axe-core did not expose window.axe.run." };
|
|
4163
|
+
return global.axe.run(global.document, { resultTypes: ["violations"] }).then((axeResult) => ({
|
|
4164
|
+
violations: (axeResult.violations ?? []).map((violation) => ({
|
|
4165
|
+
id: violation.id,
|
|
4166
|
+
impact: violation.impact,
|
|
4167
|
+
help: violation.help,
|
|
4168
|
+
description: violation.description,
|
|
4169
|
+
targets: (violation.nodes ?? []).flatMap((node) => node.target ?? []).slice(0, 3)
|
|
4170
|
+
})),
|
|
4171
|
+
incomplete: axeResult.incomplete?.length ?? 0
|
|
4172
|
+
}));
|
|
4173
|
+
});
|
|
4174
|
+
if (result.error) {
|
|
4175
|
+
return {
|
|
4176
|
+
status: "failed",
|
|
4177
|
+
engine: "axe-core",
|
|
4178
|
+
violations: 0,
|
|
4179
|
+
incomplete: 0,
|
|
4180
|
+
messages: [result.error],
|
|
4181
|
+
reason: result.error
|
|
4182
|
+
};
|
|
4183
|
+
}
|
|
4184
|
+
const violations = result.violations ?? [];
|
|
4185
|
+
const messages = violations.slice(0, 5).map((violation) => {
|
|
4186
|
+
const label = violation.id ?? "axe-violation";
|
|
4187
|
+
const detail = violation.help ?? violation.description ?? "Accessibility violation";
|
|
4188
|
+
const impact = violation.impact ? ` (${violation.impact})` : "";
|
|
4189
|
+
const targets = violation.targets && violation.targets.length > 0 ? ` [${violation.targets.join(", ")}]` : "";
|
|
4190
|
+
return compactBrowserEvidence(`${label}${impact}: ${detail}${targets}`);
|
|
4191
|
+
});
|
|
4192
|
+
return {
|
|
4193
|
+
status: violations.length > 0 ? "failed" : "passed",
|
|
4194
|
+
engine: "axe-core",
|
|
4195
|
+
violations: violations.length,
|
|
4196
|
+
incomplete: result.incomplete ?? 0,
|
|
4197
|
+
messages
|
|
4198
|
+
};
|
|
4199
|
+
} catch (error) {
|
|
4200
|
+
const message = `Axe probe failed: ${browserErrorMessage(error)}`;
|
|
4201
|
+
return {
|
|
4202
|
+
status: "failed",
|
|
4203
|
+
engine: "axe-core",
|
|
4204
|
+
violations: 0,
|
|
4205
|
+
incomplete: 0,
|
|
4206
|
+
messages: [message],
|
|
4207
|
+
reason: message
|
|
4208
|
+
};
|
|
4209
|
+
}
|
|
4210
|
+
}
|
|
4211
|
+
function browserRuntimeFailureMessages(route, runtime) {
|
|
4212
|
+
const messages = [];
|
|
4213
|
+
if (runtime.routeRendered.status === "failed") {
|
|
4214
|
+
messages.push(
|
|
4215
|
+
`${route}: route-rendered probe failed (${runtime.routeRendered.reason ?? "no rendered app root detected"})`
|
|
4216
|
+
);
|
|
4217
|
+
}
|
|
4218
|
+
if (runtime.nonblankDom.status === "failed") {
|
|
4219
|
+
messages.push(
|
|
4220
|
+
`${route}: nonblank DOM probe failed (${runtime.nonblankDom.reason ?? "blank DOM detected"})`
|
|
4221
|
+
);
|
|
4222
|
+
}
|
|
4223
|
+
if (runtime.consoleErrors.count > 0) {
|
|
4224
|
+
messages.push(
|
|
4225
|
+
`${route}: console errors (${runtime.consoleErrors.count}) ${runtime.consoleErrors.messages.join(" | ")}`
|
|
4226
|
+
);
|
|
4227
|
+
}
|
|
4228
|
+
if (runtime.pageErrors.count > 0) {
|
|
4229
|
+
messages.push(
|
|
4230
|
+
`${route}: page errors (${runtime.pageErrors.count}) ${runtime.pageErrors.messages.join(" | ")}`
|
|
4231
|
+
);
|
|
4232
|
+
}
|
|
4233
|
+
if (runtime.interactionStyles.status === "failed") {
|
|
4234
|
+
messages.push(
|
|
4235
|
+
`${route}: interaction style probe found known classes without computed animation/transition (${runtime.interactionStyles.missing.join(", ")})`
|
|
4236
|
+
);
|
|
4237
|
+
}
|
|
4238
|
+
return messages.map(compactBrowserEvidence);
|
|
4239
|
+
}
|
|
4240
|
+
function browserAccessibilityFailureMessages(route, runtime) {
|
|
4241
|
+
if (runtime.accessibility.status !== "failed") return [];
|
|
4242
|
+
const detail = runtime.accessibility.messages.length > 0 ? runtime.accessibility.messages.join(" | ") : runtime.accessibility.reason ?? "axe-core reported accessibility failures";
|
|
4243
|
+
return [
|
|
4244
|
+
compactBrowserEvidence(
|
|
4245
|
+
`${route}: axe-core violations (${runtime.accessibility.violations}) ${detail}`
|
|
4246
|
+
)
|
|
4247
|
+
];
|
|
4248
|
+
}
|
|
3864
4249
|
function browserRouteUrl(baseUrl, route) {
|
|
3865
4250
|
return new URL(route || "/", baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`).toString();
|
|
3866
4251
|
}
|
|
@@ -3882,7 +4267,7 @@ async function collectBrowserVerification(projectRoot, options, declaredRoutes)
|
|
|
3882
4267
|
baseId: "playwright-missing"
|
|
3883
4268
|
});
|
|
3884
4269
|
return {
|
|
3885
|
-
finding,
|
|
4270
|
+
findings: [finding],
|
|
3886
4271
|
evidence: {
|
|
3887
4272
|
enabled: true,
|
|
3888
4273
|
status: "unavailable",
|
|
@@ -3904,7 +4289,7 @@ async function collectBrowserVerification(projectRoot, options, declaredRoutes)
|
|
|
3904
4289
|
baseId: "base-url-missing"
|
|
3905
4290
|
});
|
|
3906
4291
|
return {
|
|
3907
|
-
finding,
|
|
4292
|
+
findings: [finding],
|
|
3908
4293
|
evidence: {
|
|
3909
4294
|
enabled: true,
|
|
3910
4295
|
status: "unavailable",
|
|
@@ -3927,7 +4312,7 @@ async function collectBrowserVerification(projectRoot, options, declaredRoutes)
|
|
|
3927
4312
|
baseId: "adapter-missing"
|
|
3928
4313
|
});
|
|
3929
4314
|
return {
|
|
3930
|
-
finding,
|
|
4315
|
+
findings: [finding],
|
|
3931
4316
|
evidence: {
|
|
3932
4317
|
enabled: true,
|
|
3933
4318
|
status: "unavailable",
|
|
@@ -3939,19 +4324,41 @@ async function collectBrowserVerification(projectRoot, options, declaredRoutes)
|
|
|
3939
4324
|
}
|
|
3940
4325
|
const routes = (declaredRoutes.length > 0 ? declaredRoutes : ["/"]).slice(0, 12);
|
|
3941
4326
|
const screenshots = [];
|
|
3942
|
-
const
|
|
4327
|
+
const routeFailures = [];
|
|
4328
|
+
const runtimeFailures = [];
|
|
4329
|
+
const accessibilityFailures = [];
|
|
3943
4330
|
const visualRoutes = [];
|
|
3944
4331
|
const screenshotDir = join5(projectRoot, ".decantr", "evidence", "screenshots");
|
|
3945
4332
|
mkdirSync4(screenshotDir, { recursive: true });
|
|
4333
|
+
const axeCore = loadProjectAxeCore(projectRoot);
|
|
3946
4334
|
let browser = null;
|
|
3947
4335
|
try {
|
|
3948
4336
|
browser = await playwright.chromium.launch({ headless: true });
|
|
3949
|
-
const page = await browser.newPage();
|
|
3950
4337
|
for (const route of routes) {
|
|
3951
4338
|
const url = browserRouteUrl(options.browserBaseUrl, route);
|
|
3952
4339
|
const relativePath = browserScreenshotRelativePath(route);
|
|
4340
|
+
let page = null;
|
|
4341
|
+
const consoleErrors = [];
|
|
4342
|
+
const pageErrors = [];
|
|
3953
4343
|
try {
|
|
4344
|
+
page = await browser.newPage();
|
|
4345
|
+
page.on?.("console", (message) => {
|
|
4346
|
+
const errorMessage = consoleErrorMessage(message);
|
|
4347
|
+
if (errorMessage) consoleErrors.push(errorMessage);
|
|
4348
|
+
});
|
|
4349
|
+
page.on?.("pageerror", (error) => {
|
|
4350
|
+
pageErrors.push(browserErrorMessage(error));
|
|
4351
|
+
});
|
|
3954
4352
|
await page.goto(url, { waitUntil: "networkidle", timeout: 15e3 });
|
|
4353
|
+
const domSnapshot = await collectRuntimeDomSnapshot(page);
|
|
4354
|
+
const runtime = {
|
|
4355
|
+
...domSnapshot,
|
|
4356
|
+
consoleErrors: consoleProbe(consoleErrors),
|
|
4357
|
+
pageErrors: consoleProbe(pageErrors),
|
|
4358
|
+
accessibility: await collectAccessibilityProbe(page, axeCore)
|
|
4359
|
+
};
|
|
4360
|
+
runtimeFailures.push(...browserRuntimeFailureMessages(route, runtime));
|
|
4361
|
+
accessibilityFailures.push(...browserAccessibilityFailureMessages(route, runtime));
|
|
3955
4362
|
const absoluteScreenshotPath = join5(projectRoot, relativePath);
|
|
3956
4363
|
await page.screenshot({ path: absoluteScreenshotPath, fullPage: true });
|
|
3957
4364
|
screenshots.push(relativePath);
|
|
@@ -3960,11 +4367,12 @@ async function collectBrowserVerification(projectRoot, options, declaredRoutes)
|
|
|
3960
4367
|
url,
|
|
3961
4368
|
screenshot: relativePath,
|
|
3962
4369
|
screenshotHash: hashFile2(absoluteScreenshotPath),
|
|
3963
|
-
status: "captured"
|
|
4370
|
+
status: "captured",
|
|
4371
|
+
runtime
|
|
3964
4372
|
});
|
|
3965
4373
|
} catch (error) {
|
|
3966
4374
|
const message = error.message;
|
|
3967
|
-
|
|
4375
|
+
routeFailures.push(`${route}: ${message}`);
|
|
3968
4376
|
visualRoutes.push({
|
|
3969
4377
|
route,
|
|
3970
4378
|
url,
|
|
@@ -3973,10 +4381,15 @@ async function collectBrowserVerification(projectRoot, options, declaredRoutes)
|
|
|
3973
4381
|
status: "failed",
|
|
3974
4382
|
error: message
|
|
3975
4383
|
});
|
|
4384
|
+
} finally {
|
|
4385
|
+
try {
|
|
4386
|
+
await page?.close?.();
|
|
4387
|
+
} catch {
|
|
4388
|
+
}
|
|
3976
4389
|
}
|
|
3977
4390
|
}
|
|
3978
4391
|
} catch (error) {
|
|
3979
|
-
|
|
4392
|
+
routeFailures.push(error.message);
|
|
3980
4393
|
} finally {
|
|
3981
4394
|
if (browser) await browser.close();
|
|
3982
4395
|
}
|
|
@@ -3990,30 +4403,68 @@ async function collectBrowserVerification(projectRoot, options, declaredRoutes)
|
|
|
3990
4403
|
const visualManifestPath = join5(projectRoot, ".decantr", "evidence", "visual-manifest.json");
|
|
3991
4404
|
mkdirSync4(dirname3(visualManifestPath), { recursive: true });
|
|
3992
4405
|
writeFileSync4(visualManifestPath, JSON.stringify(visualManifest, null, 2) + "\n", "utf-8");
|
|
3993
|
-
|
|
3994
|
-
|
|
3995
|
-
|
|
3996
|
-
|
|
3997
|
-
|
|
3998
|
-
|
|
3999
|
-
|
|
4000
|
-
|
|
4001
|
-
|
|
4002
|
-
|
|
4003
|
-
|
|
4406
|
+
const findings = [];
|
|
4407
|
+
if (routeFailures.length > 0) {
|
|
4408
|
+
findings.push(
|
|
4409
|
+
createHealthFinding({
|
|
4410
|
+
source: "browser",
|
|
4411
|
+
category: "Browser Verification",
|
|
4412
|
+
severity: options.requireBrowser ? "error" : "warn",
|
|
4413
|
+
message: "Browser verification could not render every declared route.",
|
|
4414
|
+
evidence: routeFailures.slice(0, 5),
|
|
4415
|
+
rule: "browser-route-verification-failed",
|
|
4416
|
+
suggestedFix: "Start the app at the provided base URL, fix route render errors, and rerun `decantr health --browser --evidence`.",
|
|
4417
|
+
baseId: "route-verification-failed"
|
|
4418
|
+
})
|
|
4419
|
+
);
|
|
4420
|
+
}
|
|
4421
|
+
if (runtimeFailures.length > 0) {
|
|
4422
|
+
findings.push(
|
|
4423
|
+
createHealthFinding({
|
|
4424
|
+
source: "browser",
|
|
4425
|
+
category: "Browser Runtime",
|
|
4426
|
+
severity: options.requireBrowser ? "error" : "warn",
|
|
4427
|
+
message: "Browser runtime probes failed for one or more rendered routes.",
|
|
4428
|
+
evidence: runtimeFailures.slice(0, 5),
|
|
4429
|
+
rule: "browser-runtime-probes-failed",
|
|
4430
|
+
suggestedFix: "Inspect console/page errors and rendered DOM state, repair the route runtime behavior, and rerun `decantr health --browser --evidence`.",
|
|
4431
|
+
code: "RUNTIME010",
|
|
4432
|
+
repair: { id: "repair-browser-runtime-probes" },
|
|
4433
|
+
baseId: "runtime-probes-failed"
|
|
4434
|
+
})
|
|
4435
|
+
);
|
|
4436
|
+
}
|
|
4437
|
+
if (accessibilityFailures.length > 0) {
|
|
4438
|
+
findings.push(
|
|
4439
|
+
createHealthFinding({
|
|
4440
|
+
source: "browser",
|
|
4441
|
+
category: "Browser Accessibility",
|
|
4442
|
+
severity: options.requireBrowser ? "error" : "warn",
|
|
4443
|
+
message: "Axe reported accessibility violations in rendered browser evidence.",
|
|
4444
|
+
evidence: accessibilityFailures.slice(0, 5),
|
|
4445
|
+
rule: "browser-axe-violations",
|
|
4446
|
+
suggestedFix: "Repair the rendered accessibility violations and rerun `decantr health --browser --evidence`.",
|
|
4447
|
+
code: "A11Y020",
|
|
4448
|
+
repair: { id: "fix-rendered-accessibility" },
|
|
4449
|
+
baseId: "axe-violations"
|
|
4450
|
+
})
|
|
4451
|
+
);
|
|
4452
|
+
}
|
|
4453
|
+
if (findings.length > 0) {
|
|
4454
|
+
const evidenceFindings = [...routeFailures, ...runtimeFailures, ...accessibilityFailures];
|
|
4004
4455
|
return {
|
|
4005
|
-
|
|
4456
|
+
findings,
|
|
4006
4457
|
evidence: {
|
|
4007
4458
|
enabled: true,
|
|
4008
4459
|
status: "failed",
|
|
4009
4460
|
baseUrl: options.browserBaseUrl,
|
|
4010
4461
|
screenshots,
|
|
4011
|
-
findings:
|
|
4462
|
+
findings: evidenceFindings
|
|
4012
4463
|
}
|
|
4013
4464
|
};
|
|
4014
4465
|
}
|
|
4015
4466
|
return {
|
|
4016
|
-
|
|
4467
|
+
findings: [],
|
|
4017
4468
|
evidence: {
|
|
4018
4469
|
enabled: true,
|
|
4019
4470
|
status: "passed",
|
|
@@ -4398,8 +4849,8 @@ async function createProjectHealthReport(projectRoot = process.cwd(), options =
|
|
|
4398
4849
|
options,
|
|
4399
4850
|
declaredRoutes
|
|
4400
4851
|
);
|
|
4401
|
-
|
|
4402
|
-
findings.push(
|
|
4852
|
+
for (const browserFinding of browserVerification?.findings ?? []) {
|
|
4853
|
+
if (!isDuplicateFinding(seen, browserFinding)) findings.push(browserFinding);
|
|
4403
4854
|
}
|
|
4404
4855
|
const anchoredFindings = anchorProjectHealthFindings(projectRoot, findings);
|
|
4405
4856
|
const scopedFindings = scopeHealthFindingsToProject(projectRoot, anchoredFindings);
|
|
@@ -4561,8 +5012,12 @@ function formatProjectHealthJson(report) {
|
|
|
4561
5012
|
`;
|
|
4562
5013
|
}
|
|
4563
5014
|
function diagnosticCatalogPayload() {
|
|
5015
|
+
const diagnosticsByRule = /* @__PURE__ */ new Map();
|
|
5016
|
+
for (const entry of [...KNOWN_VERIFICATION_DIAGNOSTICS, ...HEALTH_BROWSER_RUNTIME_DIAGNOSTICS]) {
|
|
5017
|
+
diagnosticsByRule.set(entry.rule, entry);
|
|
5018
|
+
}
|
|
4564
5019
|
return {
|
|
4565
|
-
diagnostics:
|
|
5020
|
+
diagnostics: [...diagnosticsByRule.values()].map((entry) => ({
|
|
4566
5021
|
code: entry.code,
|
|
4567
5022
|
family: entry.family,
|
|
4568
5023
|
rule: entry.rule,
|
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
listWorkspaceCandidates,
|
|
23
23
|
listWorkspaceProjects,
|
|
24
24
|
shouldFailWorkspaceHealth
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-EL4KSW7E.js";
|
|
26
26
|
import {
|
|
27
27
|
acceptBrownfieldLocalLaw,
|
|
28
28
|
acceptStyleBridge,
|
|
@@ -52,7 +52,7 @@ import {
|
|
|
52
52
|
writeBrownfieldCodifyProposal,
|
|
53
53
|
writeHostedPatternMappingProposal,
|
|
54
54
|
writeStyleBridgeProposal
|
|
55
|
-
} from "./chunk-
|
|
55
|
+
} from "./chunk-XUHPMETF.js";
|
|
56
56
|
import {
|
|
57
57
|
buildGuardRegistryContext,
|
|
58
58
|
createDoctrineMap,
|
|
@@ -69,7 +69,7 @@ import {
|
|
|
69
69
|
sendCliCommandTelemetry,
|
|
70
70
|
sendNewProjectCompletedTelemetry,
|
|
71
71
|
writeDoctrineMap
|
|
72
|
-
} from "./chunk-
|
|
72
|
+
} from "./chunk-XINHWP4T.js";
|
|
73
73
|
|
|
74
74
|
// src/index.ts
|
|
75
75
|
import { existsSync as existsSync28, mkdirSync as mkdirSync15, readdirSync as readdirSync8, readFileSync as readFileSync21, writeFileSync as writeFileSync18 } from "fs";
|
|
@@ -10859,7 +10859,7 @@ async function cmdAdoptWorkflow(args) {
|
|
|
10859
10859
|
await cmdGraph(projectRoot, { displayRoot: process.cwd() });
|
|
10860
10860
|
if (process.exitCode && process.exitCode !== 0) return;
|
|
10861
10861
|
if (runVerify) {
|
|
10862
|
-
const { cmdHealth } = await import("./health-
|
|
10862
|
+
const { cmdHealth } = await import("./health-H2256NIM.js");
|
|
10863
10863
|
await cmdHealth(projectRoot, {
|
|
10864
10864
|
browser: runBrowser,
|
|
10865
10865
|
browserBaseUrl: baseUrl,
|
|
@@ -10930,7 +10930,7 @@ async function cmdVerifyWorkflow(args) {
|
|
|
10930
10930
|
return;
|
|
10931
10931
|
}
|
|
10932
10932
|
if (workspaceMode) {
|
|
10933
|
-
const { cmdWorkspace } = await import("./workspace-
|
|
10933
|
+
const { cmdWorkspace } = await import("./workspace-SR6ZGG2E.js");
|
|
10934
10934
|
await cmdWorkspace(process.cwd(), ["workspace", "health", ...withoutWorkflowOnlyFlags(args)]);
|
|
10935
10935
|
return;
|
|
10936
10936
|
}
|
|
@@ -10963,7 +10963,7 @@ async function cmdVerifyWorkflow(args) {
|
|
|
10963
10963
|
}
|
|
10964
10964
|
let guardExitCode;
|
|
10965
10965
|
if (brownfield) {
|
|
10966
|
-
const { cmdHeal, collectCheckIssues } = await import("./heal-
|
|
10966
|
+
const { cmdHeal, collectCheckIssues } = await import("./heal-ZY4BX5HU.js");
|
|
10967
10967
|
if (quietOutput) {
|
|
10968
10968
|
const result = collectCheckIssues(workspaceInfo.appRoot, { brownfield: true });
|
|
10969
10969
|
guardExitCode = result.issues.some((issue) => issue.type === "error") ? 1 : void 0;
|
|
@@ -10973,7 +10973,7 @@ async function cmdVerifyWorkflow(args) {
|
|
|
10973
10973
|
process.exitCode = void 0;
|
|
10974
10974
|
}
|
|
10975
10975
|
}
|
|
10976
|
-
const { cmdHealth, parseHealthArgs } = await import("./health-
|
|
10976
|
+
const { cmdHealth, parseHealthArgs } = await import("./health-H2256NIM.js");
|
|
10977
10977
|
await cmdHealth(workspaceInfo.appRoot, parseHealthArgs(healthArgs));
|
|
10978
10978
|
if (localPatterns) {
|
|
10979
10979
|
const validation = validateLocalLaw(workspaceInfo.appRoot);
|
|
@@ -12476,7 +12476,7 @@ async function main() {
|
|
|
12476
12476
|
`${YELLOW12}Note: \`decantr heal\` is deprecated. Use \`decantr check\` instead.${RESET16}`
|
|
12477
12477
|
);
|
|
12478
12478
|
}
|
|
12479
|
-
const { cmdHeal } = await import("./heal-
|
|
12479
|
+
const { cmdHeal } = await import("./heal-ZY4BX5HU.js");
|
|
12480
12480
|
const { flags } = parseLooseArgs(args);
|
|
12481
12481
|
const workspaceInfo = resolveWorkflowProject(flags, "check");
|
|
12482
12482
|
if (!workspaceInfo) break;
|
|
@@ -12501,7 +12501,7 @@ async function main() {
|
|
|
12501
12501
|
const { flags } = parseLooseArgs(args);
|
|
12502
12502
|
const workspaceInfo = resolveWorkflowProject(flags, "health");
|
|
12503
12503
|
if (!workspaceInfo) break;
|
|
12504
|
-
const { cmdHealth, parseHealthArgs } = await import("./health-
|
|
12504
|
+
const { cmdHealth, parseHealthArgs } = await import("./health-H2256NIM.js");
|
|
12505
12505
|
await cmdHealth(workspaceInfo.appRoot, parseHealthArgs(stripProjectArgs(args)));
|
|
12506
12506
|
} catch (e) {
|
|
12507
12507
|
console.error(error2(e.message));
|
|
@@ -12529,7 +12529,7 @@ async function main() {
|
|
|
12529
12529
|
cmdStudioHelp();
|
|
12530
12530
|
break;
|
|
12531
12531
|
}
|
|
12532
|
-
const { cmdStudio, parseStudioArgs } = await import("./studio-
|
|
12532
|
+
const { cmdStudio, parseStudioArgs } = await import("./studio-UKSCSRX7.js");
|
|
12533
12533
|
await cmdStudio(process.cwd(), parseStudioArgs(args));
|
|
12534
12534
|
} catch (e) {
|
|
12535
12535
|
console.error(error2(e.message));
|
|
@@ -12543,7 +12543,7 @@ async function main() {
|
|
|
12543
12543
|
cmdWorkspaceHelp();
|
|
12544
12544
|
break;
|
|
12545
12545
|
}
|
|
12546
|
-
const { cmdWorkspace } = await import("./workspace-
|
|
12546
|
+
const { cmdWorkspace } = await import("./workspace-SR6ZGG2E.js");
|
|
12547
12547
|
await cmdWorkspace(process.cwd(), args);
|
|
12548
12548
|
} catch (e) {
|
|
12549
12549
|
console.error(error2(e.message));
|
|
@@ -13,8 +13,8 @@ import {
|
|
|
13
13
|
renderProjectHealthCiWorkflow,
|
|
14
14
|
shouldFailHealth,
|
|
15
15
|
writeProjectHealthCiWorkflow
|
|
16
|
-
} from "./chunk-
|
|
17
|
-
import "./chunk-
|
|
16
|
+
} from "./chunk-XUHPMETF.js";
|
|
17
|
+
import "./chunk-XINHWP4T.js";
|
|
18
18
|
export {
|
|
19
19
|
cmdHealth,
|
|
20
20
|
collectDesignTokenEvidence,
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import "./chunk-
|
|
1
|
+
import "./chunk-ZBGL7RID.js";
|
|
2
2
|
import "./chunk-SIDKK73N.js";
|
|
3
|
-
import "./chunk-
|
|
4
|
-
import "./chunk-
|
|
5
|
-
import "./chunk-
|
|
3
|
+
import "./chunk-EL4KSW7E.js";
|
|
4
|
+
import "./chunk-XUHPMETF.js";
|
|
5
|
+
import "./chunk-XINHWP4T.js";
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createWorkspaceHealthReport
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-EL4KSW7E.js";
|
|
4
4
|
import {
|
|
5
5
|
createProjectHealthReport
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-XUHPMETF.js";
|
|
7
7
|
import {
|
|
8
8
|
sendStudioHealthRefreshedTelemetry,
|
|
9
9
|
sendStudioStartedTelemetry
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-XINHWP4T.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-EL4KSW7E.js";
|
|
11
|
+
import "./chunk-XUHPMETF.js";
|
|
12
|
+
import "./chunk-XINHWP4T.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": "3.
|
|
3
|
+
"version": "3.4.0",
|
|
4
4
|
"description": "Decantr CLI - adopt, verify, graph, and govern frontend codebases touched by AI agents",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"decantr",
|
|
@@ -49,11 +49,11 @@
|
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
51
|
"ajv": "^8.20.0",
|
|
52
|
-
"@decantr/core": "3.
|
|
53
|
-
"@decantr/
|
|
54
|
-
"@decantr/
|
|
55
|
-
"@decantr/
|
|
56
|
-
"@decantr/
|
|
52
|
+
"@decantr/core": "3.4.0",
|
|
53
|
+
"@decantr/telemetry": "3.4.0",
|
|
54
|
+
"@decantr/registry": "3.4.0",
|
|
55
|
+
"@decantr/verifier": "3.4.0",
|
|
56
|
+
"@decantr/essence-spec": "3.4.0"
|
|
57
57
|
},
|
|
58
58
|
"scripts": {
|
|
59
59
|
"build": "tsup",
|