@decantr/cli 3.4.2 → 3.5.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 +6 -4
- package/dist/bin.js +4 -4
- package/dist/{chunk-32WTNJQU.js → chunk-LTNGAAV4.js} +749 -465
- package/dist/{chunk-2GCVVEQC.js → chunk-PM7DKABI.js} +27 -9
- package/dist/{chunk-BDA6TWV3.js → chunk-RJ6PT7WP.js} +36 -11
- package/dist/{chunk-PQKTJGYL.js → chunk-T45GFC6F.js} +80 -5
- package/dist/{heal-OKZ5QZN7.js → heal-YXWB6LTI.js} +1 -1
- package/dist/{health-U7O6PCLZ.js → health-RKUKPG72.js} +2 -2
- package/dist/index.js +4 -4
- package/dist/{studio-X565XJKV.js → studio-C2F72QL6.js} +352 -9
- package/dist/{workspace-NE232D4K.js → workspace-RJCFPVBL.js} +3 -3
- package/package.json +4 -4
|
@@ -562,6 +562,11 @@ function detectPathnameBranchRoutes(content) {
|
|
|
562
562
|
if (strongMatches > 0 || hasPathnameSignal) {
|
|
563
563
|
collectRouteLiterals(/\b(?:href|to)\s*=\s*["'`](\/[^"'`]+)["'`]/g, content, routes);
|
|
564
564
|
}
|
|
565
|
+
if (hasPathnameSignal && (/\?\s*["'`]\/["'`]\s*:/.test(content) || /\|\|\s*["'`]\/["'`]/.test(content) || /\b(?:defaultRoute|defaultPath|fallbackRoute|fallbackPath)\s*[:=]\s*["'`]\/["'`]/.test(
|
|
566
|
+
content
|
|
567
|
+
))) {
|
|
568
|
+
routes.add("/");
|
|
569
|
+
}
|
|
565
570
|
return [...routes];
|
|
566
571
|
}
|
|
567
572
|
function hasReactRouterDependency(projectRoot) {
|
|
@@ -1441,6 +1446,18 @@ function loadJsonEntries(dir) {
|
|
|
1441
1446
|
return [];
|
|
1442
1447
|
}
|
|
1443
1448
|
}
|
|
1449
|
+
function readJson(path) {
|
|
1450
|
+
if (!existsSync7(path)) return null;
|
|
1451
|
+
try {
|
|
1452
|
+
return JSON.parse(readFileSync7(path, "utf-8"));
|
|
1453
|
+
} catch {
|
|
1454
|
+
return null;
|
|
1455
|
+
}
|
|
1456
|
+
}
|
|
1457
|
+
function addPattern(registry, id, source, data = null) {
|
|
1458
|
+
if (typeof id !== "string" || !id.trim() || registry.has(id)) return;
|
|
1459
|
+
registry.set(id, data ?? { id, source });
|
|
1460
|
+
}
|
|
1444
1461
|
function buildGuardRegistryContext(projectRoot = process.cwd()) {
|
|
1445
1462
|
const themeRegistry = /* @__PURE__ */ new Map();
|
|
1446
1463
|
const patternRegistry = /* @__PURE__ */ new Map();
|
|
@@ -1461,21 +1478,22 @@ function buildGuardRegistryContext(projectRoot = process.cwd()) {
|
|
|
1461
1478
|
}
|
|
1462
1479
|
}
|
|
1463
1480
|
for (const data of loadJsonEntries(join7(cacheDir, "@official", "patterns"))) {
|
|
1464
|
-
|
|
1465
|
-
patternRegistry.set(data.id, data);
|
|
1466
|
-
}
|
|
1481
|
+
addPattern(patternRegistry, data.id, "cache", data);
|
|
1467
1482
|
}
|
|
1468
1483
|
for (const entry of loadBundledContentList("patterns")) {
|
|
1469
1484
|
const data = entry.data;
|
|
1470
1485
|
const id = typeof data.id === "string" ? data.id : entry.id;
|
|
1471
|
-
|
|
1472
|
-
patternRegistry.set(id, data);
|
|
1473
|
-
}
|
|
1486
|
+
addPattern(patternRegistry, id, "bundled", data);
|
|
1474
1487
|
}
|
|
1475
1488
|
for (const data of loadJsonEntries(join7(customDir, "patterns"))) {
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1489
|
+
addPattern(patternRegistry, data.id, "custom", data);
|
|
1490
|
+
}
|
|
1491
|
+
const localPatterns = readJson(join7(projectRoot, ".decantr", "local-patterns.json"));
|
|
1492
|
+
const patterns = Array.isArray(localPatterns?.patterns) ? localPatterns.patterns : [];
|
|
1493
|
+
for (const pattern of patterns) {
|
|
1494
|
+
if (!pattern || typeof pattern !== "object") continue;
|
|
1495
|
+
const data = pattern;
|
|
1496
|
+
addPattern(patternRegistry, data.id, "local-law", data);
|
|
1479
1497
|
}
|
|
1480
1498
|
return { themeRegistry, patternRegistry };
|
|
1481
1499
|
}
|
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createProjectHealthReport,
|
|
3
3
|
listWorkspaceAppCandidates
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-T45GFC6F.js";
|
|
5
5
|
|
|
6
6
|
// src/commands/workspace.ts
|
|
7
7
|
import { execFileSync } from "child_process";
|
|
8
8
|
import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from "fs";
|
|
9
9
|
import { dirname, join, relative, resolve } from "path";
|
|
10
|
+
import { WORKSPACE_HEALTH_REPORT_V2_SCHEMA_URL } from "@decantr/verifier";
|
|
10
11
|
var BOLD = "\x1B[1m";
|
|
11
12
|
var DIM = "\x1B[2m";
|
|
12
13
|
var GREEN = "\x1B[32m";
|
|
13
14
|
var RED = "\x1B[31m";
|
|
14
15
|
var YELLOW = "\x1B[33m";
|
|
15
16
|
var RESET = "\x1B[0m";
|
|
16
|
-
var WORKSPACE_HEALTH_SCHEMA_URL =
|
|
17
|
+
var WORKSPACE_HEALTH_SCHEMA_URL = WORKSPACE_HEALTH_REPORT_V2_SCHEMA_URL;
|
|
17
18
|
var DEFAULT_IGNORES = /* @__PURE__ */ new Set([
|
|
18
19
|
".git",
|
|
19
20
|
".next",
|
|
@@ -181,7 +182,9 @@ async function createWorkspaceHealthReport(root = process.cwd(), options = {}) {
|
|
|
181
182
|
durationMs: Date.now() - startedAt,
|
|
182
183
|
changed: options.changedOnly ? projectChanged(project, changed) : false,
|
|
183
184
|
source: project.source,
|
|
184
|
-
error: null
|
|
185
|
+
error: null,
|
|
186
|
+
loopState: report.loop.state,
|
|
187
|
+
loopNextAction: report.loop.nextActions[0] ?? null
|
|
185
188
|
};
|
|
186
189
|
} catch (error) {
|
|
187
190
|
return {
|
|
@@ -196,23 +199,44 @@ async function createWorkspaceHealthReport(root = process.cwd(), options = {}) {
|
|
|
196
199
|
durationMs: Date.now() - startedAt,
|
|
197
200
|
changed: options.changedOnly ? projectChanged(project, changed) : false,
|
|
198
201
|
source: project.source,
|
|
199
|
-
error: error.message
|
|
202
|
+
error: error.message,
|
|
203
|
+
loopState: "blocked_missing_context",
|
|
204
|
+
loopNextAction: "Fix the project health failure, then rerun workspace health."
|
|
200
205
|
};
|
|
201
206
|
}
|
|
202
207
|
});
|
|
208
|
+
const summary = {
|
|
209
|
+
projectCount: allProjects.length,
|
|
210
|
+
checkedCount: checked.length,
|
|
211
|
+
healthyCount: checked.filter((project) => project.status === "healthy").length,
|
|
212
|
+
warningCount: checked.filter((project) => project.status === "warning").length,
|
|
213
|
+
errorCount: checked.filter((project) => project.status === "error").length,
|
|
214
|
+
failedCount: checked.filter((project) => project.status === "failed").length
|
|
215
|
+
};
|
|
216
|
+
const blockedCount = checked.filter(
|
|
217
|
+
(project) => project.loopState?.startsWith("blocked") || project.loopState === "human_resolution_required"
|
|
218
|
+
).length;
|
|
219
|
+
const repairRequiredCount = checked.filter(
|
|
220
|
+
(project) => project.loopState === "repair_required"
|
|
221
|
+
).length;
|
|
222
|
+
const workspaceLoopState = checked.length === 0 ? "needs_context" : blockedCount > 0 ? "human_resolution_required" : repairRequiredCount > 0 || summary.errorCount > 0 || summary.warningCount > 0 ? "repair_required" : "verified";
|
|
223
|
+
const workspaceLoopStatus = workspaceLoopState === "human_resolution_required" || workspaceLoopState.startsWith("blocked") ? "blocked" : summary.errorCount > 0 || summary.failedCount > 0 ? "error" : summary.warningCount > 0 ? "warning" : "healthy";
|
|
203
224
|
return {
|
|
204
225
|
$schema: WORKSPACE_HEALTH_SCHEMA_URL,
|
|
205
226
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
206
227
|
workspaceRoot,
|
|
207
228
|
changedOnly: options.changedOnly ?? false,
|
|
208
229
|
since: options.changedOnly ? since : null,
|
|
209
|
-
summary
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
230
|
+
summary,
|
|
231
|
+
loop: {
|
|
232
|
+
state: workspaceLoopState,
|
|
233
|
+
status: workspaceLoopStatus,
|
|
234
|
+
projectCount: checked.length,
|
|
235
|
+
blockedCount,
|
|
236
|
+
repairRequiredCount,
|
|
237
|
+
nextActions: [
|
|
238
|
+
workspaceLoopState === "verified" ? "Workspace loop verified." : 'Open the highest-risk project, run `decantr task <route> "<intent>"`, repair, then rerun `decantr verify`.'
|
|
239
|
+
]
|
|
216
240
|
},
|
|
217
241
|
projects: checked
|
|
218
242
|
};
|
|
@@ -223,6 +247,7 @@ function formatWorkspaceHealthText(report) {
|
|
|
223
247
|
"",
|
|
224
248
|
`Projects: ${report.summary.checkedCount}/${report.summary.projectCount}`,
|
|
225
249
|
`Healthy: ${report.summary.healthyCount} | Warnings: ${report.summary.warningCount} | Errors: ${report.summary.errorCount} | Failed: ${report.summary.failedCount}`,
|
|
250
|
+
`Loop: ${report.loop.state} | blocked ${report.loop.blockedCount} | repair ${report.loop.repairRequiredCount}`,
|
|
226
251
|
""
|
|
227
252
|
];
|
|
228
253
|
for (const project of report.projects) {
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
sendProjectHealthCiFailedTelemetry,
|
|
4
4
|
sendProjectHealthPromptTelemetry,
|
|
5
5
|
sendProjectHealthReportTelemetry
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-PM7DKABI.js";
|
|
7
7
|
|
|
8
8
|
// src/commands/health.ts
|
|
9
9
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
@@ -16,10 +16,14 @@ import {
|
|
|
16
16
|
anchorFindingsToGraph,
|
|
17
17
|
auditProject,
|
|
18
18
|
buildProjectHealthRepairPlan,
|
|
19
|
+
createAuthorityResolution,
|
|
19
20
|
createContractAssertions,
|
|
20
21
|
createEvidenceBundle,
|
|
22
|
+
createEvidenceTier,
|
|
23
|
+
createLoopReadiness,
|
|
21
24
|
deriveVerificationDiagnostic,
|
|
22
|
-
KNOWN_VERIFICATION_DIAGNOSTICS
|
|
25
|
+
KNOWN_VERIFICATION_DIAGNOSTICS,
|
|
26
|
+
PROJECT_HEALTH_REPORT_V2_SCHEMA_URL
|
|
23
27
|
} from "@decantr/verifier";
|
|
24
28
|
|
|
25
29
|
// src/workspace.ts
|
|
@@ -3210,7 +3214,7 @@ var RED2 = "\x1B[31m";
|
|
|
3210
3214
|
var GREEN2 = "\x1B[32m";
|
|
3211
3215
|
var CYAN = "\x1B[36m";
|
|
3212
3216
|
var YELLOW = "\x1B[33m";
|
|
3213
|
-
var PROJECT_HEALTH_SCHEMA_URL =
|
|
3217
|
+
var PROJECT_HEALTH_SCHEMA_URL = PROJECT_HEALTH_REPORT_V2_SCHEMA_URL;
|
|
3214
3218
|
var DEFAULT_HEALTH_CI_WORKFLOW_PATH = ".github/workflows/decantr-health.yml";
|
|
3215
3219
|
var DEFAULT_HEALTH_CI_REPORT_PATH = "decantr-health.md";
|
|
3216
3220
|
var DEFAULT_HEALTH_CI_JSON_PATH = "decantr-health.json";
|
|
@@ -4860,7 +4864,7 @@ async function createProjectHealthReport(projectRoot = process.cwd(), options =
|
|
|
4860
4864
|
}));
|
|
4861
4865
|
const finalCounts = countFindings(repairPlanFindings);
|
|
4862
4866
|
const commandContext = commandContextForProject(projectRoot);
|
|
4863
|
-
|
|
4867
|
+
const baseReport = {
|
|
4864
4868
|
$schema: PROJECT_HEALTH_SCHEMA_URL,
|
|
4865
4869
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4866
4870
|
projectRoot,
|
|
@@ -4901,6 +4905,33 @@ async function createProjectHealthReport(projectRoot = process.cwd(), options =
|
|
|
4901
4905
|
},
|
|
4902
4906
|
findings: repairPlanFindings
|
|
4903
4907
|
};
|
|
4908
|
+
const evidenceTier = createEvidenceTier(baseReport, {
|
|
4909
|
+
runtimeProbeCount: browserVerification ? Math.max(1, browserVerification.evidence.screenshots.length) : void 0,
|
|
4910
|
+
visualArtifactCount: browserVerification?.evidence.screenshots.length ?? 0
|
|
4911
|
+
});
|
|
4912
|
+
const authority = createAuthorityResolution(baseReport);
|
|
4913
|
+
const loop = createLoopReadiness(baseReport, authority, evidenceTier);
|
|
4914
|
+
return {
|
|
4915
|
+
...baseReport,
|
|
4916
|
+
evidenceTier,
|
|
4917
|
+
authority,
|
|
4918
|
+
loop,
|
|
4919
|
+
findings: repairPlanFindings.map((finding) => {
|
|
4920
|
+
const conflict = authority.conflicts.find((entry) => entry.id === finding.id);
|
|
4921
|
+
return {
|
|
4922
|
+
...finding,
|
|
4923
|
+
evidenceTier,
|
|
4924
|
+
authorityLane: conflict?.lane ?? authority.activeLane,
|
|
4925
|
+
resolutionActions: conflict?.recommendedActions,
|
|
4926
|
+
privacy: {
|
|
4927
|
+
sourceIncluded: false,
|
|
4928
|
+
redacted: true,
|
|
4929
|
+
localOnly: true
|
|
4930
|
+
},
|
|
4931
|
+
loopVerdict: loop.state
|
|
4932
|
+
};
|
|
4933
|
+
})
|
|
4934
|
+
};
|
|
4904
4935
|
}
|
|
4905
4936
|
function colorForStatus(status) {
|
|
4906
4937
|
if (status === "healthy") return GREEN2;
|
|
@@ -4954,6 +4985,11 @@ function formatProjectHealthText(report) {
|
|
|
4954
4985
|
` Packs: manifest ${report.packs.manifestPresent ? "present" : "missing"} | review ${report.packs.reviewPackPresent ? "present" : "missing"} | pages ${report.packs.pagePackCount}`,
|
|
4955
4986
|
` Graph: ${report.graph.current === null ? "not attached" : report.graph.current ? "current" : "stale"} | capsule ${report.graph.capsulePresent ? "present" : "missing"} | sources ${report.graph.sourceArtifactCount}`,
|
|
4956
4987
|
"",
|
|
4988
|
+
`${BOLD}Control loop:${RESET2}`,
|
|
4989
|
+
` State: ${report.loop.state} | evidence ${report.evidenceTier.confidence.level} (${report.evidenceTier.confidence.score})`,
|
|
4990
|
+
` Authority: ${report.authority.activeLane} \u2014 ${report.authority.summary}`,
|
|
4991
|
+
` Next: ${report.loop.nextActions[0] ?? report.loop.verifyCommand}`,
|
|
4992
|
+
"",
|
|
4957
4993
|
`${BOLD}Findings:${RESET2}`
|
|
4958
4994
|
];
|
|
4959
4995
|
if (report.findings.length === 0) {
|
|
@@ -4986,6 +5022,7 @@ function formatProjectHealthText(report) {
|
|
|
4986
5022
|
}
|
|
4987
5023
|
lines.push("");
|
|
4988
5024
|
lines.push(`${BOLD}CI:${RESET2} ${report.ci.recommendedCommand}`);
|
|
5025
|
+
lines.push(`${BOLD}Loop verify:${RESET2} ${report.loop.verifyCommand}`);
|
|
4989
5026
|
return `${lines.join("\n")}
|
|
4990
5027
|
`;
|
|
4991
5028
|
}
|
|
@@ -5001,6 +5038,9 @@ function formatProjectHealthMarkdown(report) {
|
|
|
5001
5038
|
`- Runtime audit: ${report.summary.runtimeAuditChecked ? report.summary.runtimePassed ? "passed" : "failed" : "not checked"}`,
|
|
5002
5039
|
`- Packs: manifest ${report.packs.manifestPresent ? "present" : "missing"}, review ${report.packs.reviewPackPresent ? "present" : "missing"}`,
|
|
5003
5040
|
`- Graph: ${report.graph.current === null ? "not attached" : report.graph.current ? "current" : "stale"}, capsule ${report.graph.capsulePresent ? "present" : "missing"}, sources ${report.graph.sourceArtifactCount}`,
|
|
5041
|
+
`- Loop: **${report.loop.state}** (${report.loop.status})`,
|
|
5042
|
+
`- Evidence tier: **${report.evidenceTier.stage}** / ${report.evidenceTier.confidence.level}`,
|
|
5043
|
+
`- Authority: **${report.authority.activeLane}**`,
|
|
5004
5044
|
"",
|
|
5005
5045
|
"## Findings",
|
|
5006
5046
|
""
|
|
@@ -5084,6 +5124,12 @@ function formatDiagnosticCatalogText() {
|
|
|
5084
5124
|
async function createProjectEvidenceBundle(projectRoot, report, options = {}) {
|
|
5085
5125
|
const audit = await auditProject(projectRoot);
|
|
5086
5126
|
const assertions = createContractAssertions(projectRoot, audit);
|
|
5127
|
+
const visualManifestPath = join5(projectRoot, ".decantr", "evidence", "visual-manifest.json");
|
|
5128
|
+
const browserEvidence = await browserEvidenceFromOptions(
|
|
5129
|
+
projectRoot,
|
|
5130
|
+
options,
|
|
5131
|
+
report.routes.declared
|
|
5132
|
+
);
|
|
5087
5133
|
return createEvidenceBundle({
|
|
5088
5134
|
projectRoot,
|
|
5089
5135
|
report,
|
|
@@ -5091,7 +5137,36 @@ async function createProjectEvidenceBundle(projectRoot, report, options = {}) {
|
|
|
5091
5137
|
assertions,
|
|
5092
5138
|
workspaceConfigPath: existsSync5(join5(projectRoot, ".decantr", "workspace.json")) ? join5(projectRoot, ".decantr", "workspace.json") : null,
|
|
5093
5139
|
designTokensPath: resolveOptionalPath(projectRoot, options.designTokensPath) ?? null,
|
|
5094
|
-
|
|
5140
|
+
visualManifestPath: existsSync5(visualManifestPath) ? visualManifestPath : null,
|
|
5141
|
+
artifacts: [
|
|
5142
|
+
{
|
|
5143
|
+
id: "artifact:evidence-bundle",
|
|
5144
|
+
kind: "evidence-bundle",
|
|
5145
|
+
path: ".decantr/evidence/evidence-bundle.json",
|
|
5146
|
+
hash: null,
|
|
5147
|
+
localOnly: true,
|
|
5148
|
+
redacted: true
|
|
5149
|
+
},
|
|
5150
|
+
...existsSync5(visualManifestPath) ? [
|
|
5151
|
+
{
|
|
5152
|
+
id: "artifact:visual-manifest",
|
|
5153
|
+
kind: "visual-manifest",
|
|
5154
|
+
path: ".decantr/evidence/visual-manifest.json",
|
|
5155
|
+
hash: null,
|
|
5156
|
+
localOnly: true,
|
|
5157
|
+
redacted: true
|
|
5158
|
+
}
|
|
5159
|
+
] : [],
|
|
5160
|
+
...(browserEvidence?.screenshots ?? []).map((screenshot, index) => ({
|
|
5161
|
+
id: `artifact:screenshot:${index + 1}`,
|
|
5162
|
+
kind: "screenshot",
|
|
5163
|
+
path: screenshot,
|
|
5164
|
+
hash: null,
|
|
5165
|
+
localOnly: true,
|
|
5166
|
+
redacted: false
|
|
5167
|
+
}))
|
|
5168
|
+
],
|
|
5169
|
+
browser: browserEvidence,
|
|
5095
5170
|
designTokens: collectDesignTokenEvidence(projectRoot, options.designTokensPath)
|
|
5096
5171
|
});
|
|
5097
5172
|
}
|
|
@@ -13,8 +13,8 @@ import {
|
|
|
13
13
|
renderProjectHealthCiWorkflow,
|
|
14
14
|
shouldFailHealth,
|
|
15
15
|
writeProjectHealthCiWorkflow
|
|
16
|
-
} from "./chunk-
|
|
17
|
-
import "./chunk-
|
|
16
|
+
} from "./chunk-T45GFC6F.js";
|
|
17
|
+
import "./chunk-PM7DKABI.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-LTNGAAV4.js";
|
|
2
2
|
import "./chunk-SIDKK73N.js";
|
|
3
|
-
import "./chunk-
|
|
4
|
-
import "./chunk-
|
|
5
|
-
import "./chunk-
|
|
3
|
+
import "./chunk-RJ6PT7WP.js";
|
|
4
|
+
import "./chunk-T45GFC6F.js";
|
|
5
|
+
import "./chunk-PM7DKABI.js";
|