Sign In

@decantr/cli

Package Overview
Dependencies
Maintainers
1
Versions
116
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@decantr/cli - npm Package Compare versions

Comparing version
3.5.2
to
3.5.3
dist/chunk-4WT6AVKO.js

Sorry, the diff of this file is too big to display

+380
import {
createProjectHealthReport,
listWorkspaceAppCandidates
} from "./chunk-SUB3F5RO.js";
// src/commands/workspace.ts
import { execFileSync } from "child_process";
import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from "fs";
import { dirname, join, relative, resolve } from "path";
import { WORKSPACE_HEALTH_REPORT_V2_SCHEMA_URL } from "@decantr/verifier";
var BOLD = "\x1B[1m";
var DIM = "\x1B[2m";
var GREEN = "\x1B[32m";
var RED = "\x1B[31m";
var YELLOW = "\x1B[33m";
var RESET = "\x1B[0m";
var WORKSPACE_HEALTH_SCHEMA_URL = WORKSPACE_HEALTH_REPORT_V2_SCHEMA_URL;
var DEFAULT_IGNORES = /* @__PURE__ */ new Set([
".git",
".next",
".turbo",
".vercel",
"coverage",
"dist",
"node_modules",
"playwright-report"
]);
function workspaceConfigPath(root) {
return join(root, ".decantr", "workspace.json");
}
function readWorkspaceConfig(root) {
const path = workspaceConfigPath(root);
if (!existsSync(path)) return null;
return JSON.parse(readFileSync(path, "utf-8"));
}
function normalizeProjectPath(raw) {
const normalized = raw.replace(/^\.\/+/, "").replace(/\/+$/, "");
if (!normalized || normalized.startsWith("/") || normalized.includes("..") || normalized.includes("\\") || /\s/.test(normalized)) {
throw new Error(`Invalid workspace project path: ${raw}`);
}
return normalized;
}
function projectIdFromPath(path) {
return path.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "project";
}
function discoverProjectPaths(root, config) {
const ignored = /* @__PURE__ */ new Set([...config?.ignore ?? [], ...DEFAULT_IGNORES]);
const results = /* @__PURE__ */ new Set();
function walk(dir, depth) {
if (depth > 6) return;
const rel = relative(root, dir).replace(/\\/g, "/");
if (rel && [...ignored].some((entry) => rel === entry || rel.startsWith(`${entry}/`))) return;
if (existsSync(join(dir, "decantr.essence.json"))) {
results.add(rel || ".");
return;
}
for (const entry of readdirSync(dir, { withFileTypes: true })) {
if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
if (ignored.has(entry.name)) continue;
walk(join(dir, entry.name), depth + 1);
}
}
walk(root, 0);
return [...results].sort();
}
function listWorkspaceProjects(root = process.cwd()) {
const workspaceRoot = resolve(root);
const config = readWorkspaceConfig(workspaceRoot);
const byPath = /* @__PURE__ */ new Map();
for (const project of config?.projects ?? []) {
const path = normalizeProjectPath(project.path);
byPath.set(path, {
id: project.id ?? projectIdFromPath(path),
path,
absolutePath: resolve(workspaceRoot, path),
owner: project.owner ?? null,
tags: project.tags ?? [],
criticality: project.criticality ?? "normal",
browser: project.browser ?? config?.browser ?? false,
source: "manifest"
});
}
for (const path of discoverProjectPaths(workspaceRoot, config)) {
if (byPath.has(path)) continue;
byPath.set(path, {
id: projectIdFromPath(path),
path,
absolutePath: resolve(workspaceRoot, path),
owner: null,
tags: [],
criticality: "normal",
browser: config?.browser ?? false,
source: "auto"
});
}
return [...byPath.values()].sort((a, b) => a.path.localeCompare(b.path));
}
function listWorkspaceCandidates(root = process.cwd(), projects = listWorkspaceProjects(root)) {
const attached = new Set(projects.map((project) => project.path));
return listWorkspaceAppCandidates(root).map((path) => ({
path,
attached: attached.has(path),
suggestedAdoptCommand: `decantr adopt --project ${path} --yes`
}));
}
function changedPaths(root, since) {
try {
const output = execFileSync("git", ["diff", "--name-only", since, "--"], {
cwd: root,
encoding: "utf-8",
stdio: ["ignore", "pipe", "ignore"]
});
return new Set(
output.split("\n").map((line) => line.trim()).filter(Boolean)
);
} catch {
return /* @__PURE__ */ new Set();
}
}
function projectChanged(project, changed) {
if (changed.size === 0) return false;
const prefix = project.path === "." ? "" : `${project.path}/`;
for (const path of changed) {
if (project.path === "." || path === project.path || path.startsWith(prefix)) return true;
}
return false;
}
async function withTimeout(promise, timeoutMs, label) {
let timeout;
const timer = new Promise((_, reject) => {
timeout = setTimeout(
() => reject(new Error(`${label} timed out after ${timeoutMs}ms`)),
timeoutMs
);
});
try {
return await Promise.race([promise, timer]);
} finally {
if (timeout) clearTimeout(timeout);
}
}
async function mapLimited(items, concurrency, fn) {
const results = new Array(items.length);
let next = 0;
async function worker() {
while (next < items.length) {
const index = next++;
results[index] = await fn(items[index]);
}
}
await Promise.all(Array.from({ length: Math.max(1, concurrency) }, () => worker()));
return results;
}
async function createWorkspaceHealthReport(root = process.cwd(), options = {}) {
const workspaceRoot = resolve(root);
const config = readWorkspaceConfig(workspaceRoot);
const since = options.since ?? "origin/main";
const changed = options.changedOnly ? changedPaths(workspaceRoot, since) : /* @__PURE__ */ new Set();
const allProjects = listWorkspaceProjects(workspaceRoot);
const projects = options.changedOnly ? allProjects.filter((project) => projectChanged(project, changed)) : allProjects;
const concurrency = options.concurrency ?? config?.concurrency ?? 4;
const timeoutMs = options.timeoutMs ?? config?.timeoutMs ?? 12e4;
const checked = await mapLimited(projects, concurrency, async (project) => {
const startedAt = Date.now();
try {
const report = await withTimeout(
createProjectHealthReport(project.absolutePath, {
browser: options.browser ?? project.browser
}),
timeoutMs,
project.path
);
return {
id: project.id,
path: project.path,
status: report.status,
score: report.score,
errorCount: report.summary.errorCount,
warnCount: report.summary.warnCount,
infoCount: report.summary.infoCount,
findingCount: report.summary.findingCount,
durationMs: Date.now() - startedAt,
changed: options.changedOnly ? projectChanged(project, changed) : false,
source: project.source,
error: null,
loopState: report.loop.state,
loopNextAction: report.loop.nextActions[0] ?? null
};
} catch (error) {
return {
id: project.id,
path: project.path,
status: "failed",
score: 0,
errorCount: 1,
warnCount: 0,
infoCount: 0,
findingCount: 1,
durationMs: Date.now() - startedAt,
changed: options.changedOnly ? projectChanged(project, changed) : false,
source: project.source,
error: error.message,
loopState: "blocked_missing_context",
loopNextAction: "Fix the project health failure, then rerun workspace health."
};
}
});
const summary = {
projectCount: allProjects.length,
checkedCount: checked.length,
healthyCount: checked.filter((project) => project.status === "healthy").length,
warningCount: checked.filter((project) => project.status === "warning").length,
errorCount: checked.filter((project) => project.status === "error").length,
failedCount: checked.filter((project) => project.status === "failed").length
};
const blockedCount = checked.filter(
(project) => project.loopState?.startsWith("blocked") || project.loopState === "human_resolution_required"
).length;
const repairRequiredCount = checked.filter(
(project) => project.loopState === "repair_required"
).length;
const workspaceLoopState = checked.length === 0 ? "needs_context" : blockedCount > 0 ? "human_resolution_required" : repairRequiredCount > 0 || summary.errorCount > 0 || summary.warningCount > 0 ? "repair_required" : "verified";
const workspaceLoopStatus = workspaceLoopState === "human_resolution_required" || workspaceLoopState.startsWith("blocked") ? "blocked" : summary.errorCount > 0 || summary.failedCount > 0 ? "error" : summary.warningCount > 0 ? "warning" : "healthy";
return {
$schema: WORKSPACE_HEALTH_SCHEMA_URL,
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
workspaceRoot,
changedOnly: options.changedOnly ?? false,
since: options.changedOnly ? since : null,
summary,
loop: {
state: workspaceLoopState,
status: workspaceLoopStatus,
projectCount: checked.length,
blockedCount,
repairRequiredCount,
nextActions: [
workspaceLoopState === "verified" ? "Workspace loop verified." : 'Open the highest-risk project, run `decantr task <route> "<intent>"`, repair, then rerun `decantr verify`.'
]
},
projects: checked
};
}
function formatWorkspaceHealthText(report) {
const lines = [
`${BOLD}Decantr Workspace Health${RESET}`,
"",
`Projects: ${report.summary.checkedCount}/${report.summary.projectCount}`,
`Healthy: ${report.summary.healthyCount} | Warnings: ${report.summary.warningCount} | Errors: ${report.summary.errorCount} | Failed: ${report.summary.failedCount}`,
`Loop: ${report.loop.state} | blocked ${report.loop.blockedCount} | repair ${report.loop.repairRequiredCount}`,
""
];
for (const project of report.projects) {
const color = project.status === "healthy" ? GREEN : project.status === "warning" ? YELLOW : RED;
lines.push(
`${color}${String(project.status).toUpperCase()}${RESET} ${project.path} score ${project.score}/100 findings ${project.findingCount}`
);
if (project.error) lines.push(` ${DIM}${project.error}${RESET}`);
}
return `${lines.join("\n")}
`;
}
function formatWorkspaceHealthMarkdown(report) {
const lines = [
"# Decantr Workspace Health",
"",
`- Projects checked: **${report.summary.checkedCount}/${report.summary.projectCount}**`,
`- Healthy: ${report.summary.healthyCount}`,
`- Warnings: ${report.summary.warningCount}`,
`- Errors: ${report.summary.errorCount}`,
`- Failed: ${report.summary.failedCount}`,
"",
"| Project | Status | Score | Findings | Source |",
"| --- | --- | ---: | ---: | --- |"
];
for (const project of report.projects) {
lines.push(
`| \`${project.path}\` | ${project.status} | ${project.score} | ${project.findingCount} | ${project.source} |`
);
}
return `${lines.join("\n")}
`;
}
function shouldFailWorkspaceHealth(report, failOn = "error") {
if (failOn === "none") return false;
if (report.summary.failedCount > 0 || report.summary.errorCount > 0) return true;
return failOn === "warn" && report.summary.warningCount > 0;
}
function parseHealthFailOn(value) {
if (value === "warn" || value === "none") return value;
return "error";
}
function parseWorkspaceArgs(args) {
const subcommand = args[1] === "health" ? "health" : "list";
const options = { subcommand };
for (let index = 2; index < args.length; index += 1) {
const arg = args[index];
if (arg === "--json") options.json = true;
else if (arg === "--markdown") options.markdown = true;
else if (arg === "--ci") options.ci = true;
else if (arg === "--browser") options.browser = true;
else if (arg === "--changed") options.changedOnly = true;
else if (arg === "--since" && args[index + 1]) options.since = args[++index];
else if (arg.startsWith("--since=")) options.since = arg.split("=")[1];
else if (arg === "--output" && args[index + 1]) options.output = args[++index];
else if (arg.startsWith("--output=")) options.output = arg.split("=")[1];
else if (arg === "--fail-on" && args[index + 1])
options.failOn = parseHealthFailOn(args[++index]);
else if (arg.startsWith("--fail-on=")) options.failOn = parseHealthFailOn(arg.split("=")[1]);
else if (arg === "--concurrency" && args[index + 1])
options.concurrency = Number(args[++index]);
else if (arg.startsWith("--concurrency=")) options.concurrency = Number(arg.split("=")[1]);
else if (arg === "--timeout-ms" && args[index + 1]) options.timeoutMs = Number(args[++index]);
else if (arg.startsWith("--timeout-ms=")) options.timeoutMs = Number(arg.split("=")[1]);
}
return options;
}
async function cmdWorkspace(workspaceRoot = process.cwd(), args = ["workspace"]) {
const options = parseWorkspaceArgs(args);
if (options.subcommand === "list") {
const projects = listWorkspaceProjects(workspaceRoot);
const candidates = listWorkspaceCandidates(workspaceRoot, projects);
const unattachedCandidates = candidates.filter((candidate) => !candidate.attached);
const payload2 = `${JSON.stringify({ projects, candidates }, null, 2)}
`;
if (options.json) {
process.stdout.write(payload2);
return;
}
console.log(`${BOLD}Decantr workspace projects${RESET}`);
console.log("");
console.log("Attached Decantr projects:");
if (projects.length === 0) {
console.log(` ${DIM}(none yet)${RESET}`);
} else {
for (const project of projects) {
console.log(` ${project.path} ${DIM}${project.source}${RESET}`);
}
}
if (candidates.length > 0) {
console.log("");
console.log("App candidates:");
for (const candidate of candidates) {
const status = candidate.attached ? `${GREEN}attached${RESET}` : `${YELLOW}unattached${RESET}`;
console.log(` ${candidate.path} ${DIM}${status}${RESET}`);
}
}
if (unattachedCandidates.length > 0) {
console.log("");
console.log(projects.length > 0 ? "Attach another app:" : "Start by attaching one app:");
console.log(` ${unattachedCandidates[0].suggestedAdoptCommand}`);
}
return;
}
const report = await createWorkspaceHealthReport(workspaceRoot, options);
const payload = options.json ? `${JSON.stringify(report, null, 2)}
` : options.markdown ? formatWorkspaceHealthMarkdown(report) : formatWorkspaceHealthText(report);
if (options.output) {
mkdirSync(dirname(resolve(workspaceRoot, options.output)), { recursive: true });
writeFileSync(resolve(workspaceRoot, options.output), payload, "utf-8");
if (!options.ci)
console.log(`${GREEN}Wrote Decantr workspace health:${RESET} ${options.output}`);
} else {
process.stdout.write(payload);
}
if (options.ci && shouldFailWorkspaceHealth(report, options.failOn ?? "error")) {
process.exitCode = 1;
}
}
export {
listWorkspaceProjects,
listWorkspaceCandidates,
createWorkspaceHealthReport,
formatWorkspaceHealthText,
formatWorkspaceHealthMarkdown,
shouldFailWorkspaceHealth,
parseWorkspaceArgs,
cmdWorkspace
};

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

import {
cmdHeal,
collectCheckIssues
} from "./chunk-4WT6AVKO.js";
export {
cmdHeal,
collectCheckIssues
};
import {
cmdHealth,
collectDesignTokenEvidence,
createProjectEvidenceBundle,
createProjectHealthReport,
formatDiagnosticCatalogJson,
formatDiagnosticCatalogMarkdown,
formatDiagnosticCatalogText,
formatProjectHealthJson,
formatProjectHealthMarkdown,
formatProjectHealthText,
parseHealthArgs,
renderProjectHealthCiWorkflow,
shouldFailHealth,
writeProjectHealthCiWorkflow
} from "./chunk-SUB3F5RO.js";
import "./chunk-4WT6AVKO.js";
export {
cmdHealth,
collectDesignTokenEvidence,
createProjectEvidenceBundle,
createProjectHealthReport,
formatDiagnosticCatalogJson,
formatDiagnosticCatalogMarkdown,
formatDiagnosticCatalogText,
formatProjectHealthJson,
formatProjectHealthMarkdown,
formatProjectHealthText,
parseHealthArgs,
renderProjectHealthCiWorkflow,
shouldFailHealth,
writeProjectHealthCiWorkflow
};

Sorry, the diff of this file is too big to display

import {
cmdWorkspace,
createWorkspaceHealthReport,
formatWorkspaceHealthMarkdown,
formatWorkspaceHealthText,
listWorkspaceCandidates,
listWorkspaceProjects,
parseWorkspaceArgs,
shouldFailWorkspaceHealth
} from "./chunk-FE3N5MAO.js";
import "./chunk-SUB3F5RO.js";
import "./chunk-4WT6AVKO.js";
export {
cmdWorkspace,
createWorkspaceHealthReport,
formatWorkspaceHealthMarkdown,
formatWorkspaceHealthText,
listWorkspaceCandidates,
listWorkspaceProjects,
parseWorkspaceArgs,
shouldFailWorkspaceHealth
};
+4
-4
#!/usr/bin/env node
import "./chunk-6FR73WZ6.js";
import "./chunk-KFGL6DVJ.js";
import "./chunk-SIDKK73N.js";
import "./chunk-GDPC7PCB.js";
import "./chunk-GJG3O4QS.js";
import "./chunk-PM7DKABI.js";
import "./chunk-FE3N5MAO.js";
import "./chunk-SUB3F5RO.js";
import "./chunk-4WT6AVKO.js";

@@ -1,5 +0,5 @@

import "./chunk-6FR73WZ6.js";
import "./chunk-KFGL6DVJ.js";
import "./chunk-SIDKK73N.js";
import "./chunk-GDPC7PCB.js";
import "./chunk-GJG3O4QS.js";
import "./chunk-PM7DKABI.js";
import "./chunk-FE3N5MAO.js";
import "./chunk-SUB3F5RO.js";
import "./chunk-4WT6AVKO.js";
{
"name": "@decantr/cli",
"version": "3.5.2",
"version": "3.5.3",
"description": "Decantr CLI - adopt, verify, graph, and govern frontend codebases touched by AI agents",

@@ -52,7 +52,7 @@ "keywords": [

"ajv": "^8.20.0",
"@decantr/essence-spec": "3.4.0",
"@decantr/core": "3.5.0",
"@decantr/essence-spec": "3.4.0",
"@decantr/telemetry": "3.4.0",
"@decantr/verifier": "3.5.3",
"@decantr/registry": "3.4.0",
"@decantr/verifier": "3.5.0"
"@decantr/telemetry": "3.4.0"
},

@@ -59,0 +59,0 @@ "scripts": {

Sorry, the diff of this file is too big to display

import {
createProjectHealthReport,
listWorkspaceAppCandidates
} from "./chunk-GJG3O4QS.js";
// src/commands/workspace.ts
import { execFileSync } from "child_process";
import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from "fs";
import { dirname, join, relative, resolve } from "path";
import { WORKSPACE_HEALTH_REPORT_V2_SCHEMA_URL } from "@decantr/verifier";
var BOLD = "\x1B[1m";
var DIM = "\x1B[2m";
var GREEN = "\x1B[32m";
var RED = "\x1B[31m";
var YELLOW = "\x1B[33m";
var RESET = "\x1B[0m";
var WORKSPACE_HEALTH_SCHEMA_URL = WORKSPACE_HEALTH_REPORT_V2_SCHEMA_URL;
var DEFAULT_IGNORES = /* @__PURE__ */ new Set([
".git",
".next",
".turbo",
".vercel",
"coverage",
"dist",
"node_modules",
"playwright-report"
]);
function workspaceConfigPath(root) {
return join(root, ".decantr", "workspace.json");
}
function readWorkspaceConfig(root) {
const path = workspaceConfigPath(root);
if (!existsSync(path)) return null;
return JSON.parse(readFileSync(path, "utf-8"));
}
function normalizeProjectPath(raw) {
const normalized = raw.replace(/^\.\/+/, "").replace(/\/+$/, "");
if (!normalized || normalized.startsWith("/") || normalized.includes("..") || normalized.includes("\\") || /\s/.test(normalized)) {
throw new Error(`Invalid workspace project path: ${raw}`);
}
return normalized;
}
function projectIdFromPath(path) {
return path.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "project";
}
function discoverProjectPaths(root, config) {
const ignored = /* @__PURE__ */ new Set([...config?.ignore ?? [], ...DEFAULT_IGNORES]);
const results = /* @__PURE__ */ new Set();
function walk(dir, depth) {
if (depth > 6) return;
const rel = relative(root, dir).replace(/\\/g, "/");
if (rel && [...ignored].some((entry) => rel === entry || rel.startsWith(`${entry}/`))) return;
if (existsSync(join(dir, "decantr.essence.json"))) {
results.add(rel || ".");
return;
}
for (const entry of readdirSync(dir, { withFileTypes: true })) {
if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
if (ignored.has(entry.name)) continue;
walk(join(dir, entry.name), depth + 1);
}
}
walk(root, 0);
return [...results].sort();
}
function listWorkspaceProjects(root = process.cwd()) {
const workspaceRoot = resolve(root);
const config = readWorkspaceConfig(workspaceRoot);
const byPath = /* @__PURE__ */ new Map();
for (const project of config?.projects ?? []) {
const path = normalizeProjectPath(project.path);
byPath.set(path, {
id: project.id ?? projectIdFromPath(path),
path,
absolutePath: resolve(workspaceRoot, path),
owner: project.owner ?? null,
tags: project.tags ?? [],
criticality: project.criticality ?? "normal",
browser: project.browser ?? config?.browser ?? false,
source: "manifest"
});
}
for (const path of discoverProjectPaths(workspaceRoot, config)) {
if (byPath.has(path)) continue;
byPath.set(path, {
id: projectIdFromPath(path),
path,
absolutePath: resolve(workspaceRoot, path),
owner: null,
tags: [],
criticality: "normal",
browser: config?.browser ?? false,
source: "auto"
});
}
return [...byPath.values()].sort((a, b) => a.path.localeCompare(b.path));
}
function listWorkspaceCandidates(root = process.cwd(), projects = listWorkspaceProjects(root)) {
const attached = new Set(projects.map((project) => project.path));
return listWorkspaceAppCandidates(root).map((path) => ({
path,
attached: attached.has(path),
suggestedAdoptCommand: `decantr adopt --project ${path} --yes`
}));
}
function changedPaths(root, since) {
try {
const output = execFileSync("git", ["diff", "--name-only", since, "--"], {
cwd: root,
encoding: "utf-8",
stdio: ["ignore", "pipe", "ignore"]
});
return new Set(
output.split("\n").map((line) => line.trim()).filter(Boolean)
);
} catch {
return /* @__PURE__ */ new Set();
}
}
function projectChanged(project, changed) {
if (changed.size === 0) return false;
const prefix = project.path === "." ? "" : `${project.path}/`;
for (const path of changed) {
if (project.path === "." || path === project.path || path.startsWith(prefix)) return true;
}
return false;
}
async function withTimeout(promise, timeoutMs, label) {
let timeout;
const timer = new Promise((_, reject) => {
timeout = setTimeout(
() => reject(new Error(`${label} timed out after ${timeoutMs}ms`)),
timeoutMs
);
});
try {
return await Promise.race([promise, timer]);
} finally {
if (timeout) clearTimeout(timeout);
}
}
async function mapLimited(items, concurrency, fn) {
const results = new Array(items.length);
let next = 0;
async function worker() {
while (next < items.length) {
const index = next++;
results[index] = await fn(items[index]);
}
}
await Promise.all(Array.from({ length: Math.max(1, concurrency) }, () => worker()));
return results;
}
async function createWorkspaceHealthReport(root = process.cwd(), options = {}) {
const workspaceRoot = resolve(root);
const config = readWorkspaceConfig(workspaceRoot);
const since = options.since ?? "origin/main";
const changed = options.changedOnly ? changedPaths(workspaceRoot, since) : /* @__PURE__ */ new Set();
const allProjects = listWorkspaceProjects(workspaceRoot);
const projects = options.changedOnly ? allProjects.filter((project) => projectChanged(project, changed)) : allProjects;
const concurrency = options.concurrency ?? config?.concurrency ?? 4;
const timeoutMs = options.timeoutMs ?? config?.timeoutMs ?? 12e4;
const checked = await mapLimited(projects, concurrency, async (project) => {
const startedAt = Date.now();
try {
const report = await withTimeout(
createProjectHealthReport(project.absolutePath, {
browser: options.browser ?? project.browser
}),
timeoutMs,
project.path
);
return {
id: project.id,
path: project.path,
status: report.status,
score: report.score,
errorCount: report.summary.errorCount,
warnCount: report.summary.warnCount,
infoCount: report.summary.infoCount,
findingCount: report.summary.findingCount,
durationMs: Date.now() - startedAt,
changed: options.changedOnly ? projectChanged(project, changed) : false,
source: project.source,
error: null,
loopState: report.loop.state,
loopNextAction: report.loop.nextActions[0] ?? null
};
} catch (error) {
return {
id: project.id,
path: project.path,
status: "failed",
score: 0,
errorCount: 1,
warnCount: 0,
infoCount: 0,
findingCount: 1,
durationMs: Date.now() - startedAt,
changed: options.changedOnly ? projectChanged(project, changed) : false,
source: project.source,
error: error.message,
loopState: "blocked_missing_context",
loopNextAction: "Fix the project health failure, then rerun workspace health."
};
}
});
const summary = {
projectCount: allProjects.length,
checkedCount: checked.length,
healthyCount: checked.filter((project) => project.status === "healthy").length,
warningCount: checked.filter((project) => project.status === "warning").length,
errorCount: checked.filter((project) => project.status === "error").length,
failedCount: checked.filter((project) => project.status === "failed").length
};
const blockedCount = checked.filter(
(project) => project.loopState?.startsWith("blocked") || project.loopState === "human_resolution_required"
).length;
const repairRequiredCount = checked.filter(
(project) => project.loopState === "repair_required"
).length;
const workspaceLoopState = checked.length === 0 ? "needs_context" : blockedCount > 0 ? "human_resolution_required" : repairRequiredCount > 0 || summary.errorCount > 0 || summary.warningCount > 0 ? "repair_required" : "verified";
const workspaceLoopStatus = workspaceLoopState === "human_resolution_required" || workspaceLoopState.startsWith("blocked") ? "blocked" : summary.errorCount > 0 || summary.failedCount > 0 ? "error" : summary.warningCount > 0 ? "warning" : "healthy";
return {
$schema: WORKSPACE_HEALTH_SCHEMA_URL,
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
workspaceRoot,
changedOnly: options.changedOnly ?? false,
since: options.changedOnly ? since : null,
summary,
loop: {
state: workspaceLoopState,
status: workspaceLoopStatus,
projectCount: checked.length,
blockedCount,
repairRequiredCount,
nextActions: [
workspaceLoopState === "verified" ? "Workspace loop verified." : 'Open the highest-risk project, run `decantr task <route> "<intent>"`, repair, then rerun `decantr verify`.'
]
},
projects: checked
};
}
function formatWorkspaceHealthText(report) {
const lines = [
`${BOLD}Decantr Workspace Health${RESET}`,
"",
`Projects: ${report.summary.checkedCount}/${report.summary.projectCount}`,
`Healthy: ${report.summary.healthyCount} | Warnings: ${report.summary.warningCount} | Errors: ${report.summary.errorCount} | Failed: ${report.summary.failedCount}`,
`Loop: ${report.loop.state} | blocked ${report.loop.blockedCount} | repair ${report.loop.repairRequiredCount}`,
""
];
for (const project of report.projects) {
const color = project.status === "healthy" ? GREEN : project.status === "warning" ? YELLOW : RED;
lines.push(
`${color}${String(project.status).toUpperCase()}${RESET} ${project.path} score ${project.score}/100 findings ${project.findingCount}`
);
if (project.error) lines.push(` ${DIM}${project.error}${RESET}`);
}
return `${lines.join("\n")}
`;
}
function formatWorkspaceHealthMarkdown(report) {
const lines = [
"# Decantr Workspace Health",
"",
`- Projects checked: **${report.summary.checkedCount}/${report.summary.projectCount}**`,
`- Healthy: ${report.summary.healthyCount}`,
`- Warnings: ${report.summary.warningCount}`,
`- Errors: ${report.summary.errorCount}`,
`- Failed: ${report.summary.failedCount}`,
"",
"| Project | Status | Score | Findings | Source |",
"| --- | --- | ---: | ---: | --- |"
];
for (const project of report.projects) {
lines.push(
`| \`${project.path}\` | ${project.status} | ${project.score} | ${project.findingCount} | ${project.source} |`
);
}
return `${lines.join("\n")}
`;
}
function shouldFailWorkspaceHealth(report, failOn = "error") {
if (failOn === "none") return false;
if (report.summary.failedCount > 0 || report.summary.errorCount > 0) return true;
return failOn === "warn" && report.summary.warningCount > 0;
}
function parseHealthFailOn(value) {
if (value === "warn" || value === "none") return value;
return "error";
}
function parseWorkspaceArgs(args) {
const subcommand = args[1] === "health" ? "health" : "list";
const options = { subcommand };
for (let index = 2; index < args.length; index += 1) {
const arg = args[index];
if (arg === "--json") options.json = true;
else if (arg === "--markdown") options.markdown = true;
else if (arg === "--ci") options.ci = true;
else if (arg === "--browser") options.browser = true;
else if (arg === "--changed") options.changedOnly = true;
else if (arg === "--since" && args[index + 1]) options.since = args[++index];
else if (arg.startsWith("--since=")) options.since = arg.split("=")[1];
else if (arg === "--output" && args[index + 1]) options.output = args[++index];
else if (arg.startsWith("--output=")) options.output = arg.split("=")[1];
else if (arg === "--fail-on" && args[index + 1])
options.failOn = parseHealthFailOn(args[++index]);
else if (arg.startsWith("--fail-on=")) options.failOn = parseHealthFailOn(arg.split("=")[1]);
else if (arg === "--concurrency" && args[index + 1])
options.concurrency = Number(args[++index]);
else if (arg.startsWith("--concurrency=")) options.concurrency = Number(arg.split("=")[1]);
else if (arg === "--timeout-ms" && args[index + 1]) options.timeoutMs = Number(args[++index]);
else if (arg.startsWith("--timeout-ms=")) options.timeoutMs = Number(arg.split("=")[1]);
}
return options;
}
async function cmdWorkspace(workspaceRoot = process.cwd(), args = ["workspace"]) {
const options = parseWorkspaceArgs(args);
if (options.subcommand === "list") {
const projects = listWorkspaceProjects(workspaceRoot);
const candidates = listWorkspaceCandidates(workspaceRoot, projects);
const unattachedCandidates = candidates.filter((candidate) => !candidate.attached);
const payload2 = `${JSON.stringify({ projects, candidates }, null, 2)}
`;
if (options.json) {
process.stdout.write(payload2);
return;
}
console.log(`${BOLD}Decantr workspace projects${RESET}`);
console.log("");
console.log("Attached Decantr projects:");
if (projects.length === 0) {
console.log(` ${DIM}(none yet)${RESET}`);
} else {
for (const project of projects) {
console.log(` ${project.path} ${DIM}${project.source}${RESET}`);
}
}
if (candidates.length > 0) {
console.log("");
console.log("App candidates:");
for (const candidate of candidates) {
const status = candidate.attached ? `${GREEN}attached${RESET}` : `${YELLOW}unattached${RESET}`;
console.log(` ${candidate.path} ${DIM}${status}${RESET}`);
}
}
if (unattachedCandidates.length > 0) {
console.log("");
console.log(projects.length > 0 ? "Attach another app:" : "Start by attaching one app:");
console.log(` ${unattachedCandidates[0].suggestedAdoptCommand}`);
}
return;
}
const report = await createWorkspaceHealthReport(workspaceRoot, options);
const payload = options.json ? `${JSON.stringify(report, null, 2)}
` : options.markdown ? formatWorkspaceHealthMarkdown(report) : formatWorkspaceHealthText(report);
if (options.output) {
mkdirSync(dirname(resolve(workspaceRoot, options.output)), { recursive: true });
writeFileSync(resolve(workspaceRoot, options.output), payload, "utf-8");
if (!options.ci)
console.log(`${GREEN}Wrote Decantr workspace health:${RESET} ${options.output}`);
} else {
process.stdout.write(payload);
}
if (options.ci && shouldFailWorkspaceHealth(report, options.failOn ?? "error")) {
process.exitCode = 1;
}
}
export {
listWorkspaceProjects,
listWorkspaceCandidates,
createWorkspaceHealthReport,
formatWorkspaceHealthText,
formatWorkspaceHealthMarkdown,
shouldFailWorkspaceHealth,
parseWorkspaceArgs,
cmdWorkspace
};

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

import {
cmdHeal,
collectCheckIssues
} from "./chunk-PM7DKABI.js";
export {
cmdHeal,
collectCheckIssues
};
import {
cmdHealth,
collectDesignTokenEvidence,
createProjectEvidenceBundle,
createProjectHealthReport,
formatDiagnosticCatalogJson,
formatDiagnosticCatalogMarkdown,
formatDiagnosticCatalogText,
formatProjectHealthJson,
formatProjectHealthMarkdown,
formatProjectHealthText,
parseHealthArgs,
renderProjectHealthCiWorkflow,
shouldFailHealth,
writeProjectHealthCiWorkflow
} from "./chunk-GJG3O4QS.js";
import "./chunk-PM7DKABI.js";
export {
cmdHealth,
collectDesignTokenEvidence,
createProjectEvidenceBundle,
createProjectHealthReport,
formatDiagnosticCatalogJson,
formatDiagnosticCatalogMarkdown,
formatDiagnosticCatalogText,
formatProjectHealthJson,
formatProjectHealthMarkdown,
formatProjectHealthText,
parseHealthArgs,
renderProjectHealthCiWorkflow,
shouldFailHealth,
writeProjectHealthCiWorkflow
};

Sorry, the diff of this file is too big to display

import {
cmdWorkspace,
createWorkspaceHealthReport,
formatWorkspaceHealthMarkdown,
formatWorkspaceHealthText,
listWorkspaceCandidates,
listWorkspaceProjects,
parseWorkspaceArgs,
shouldFailWorkspaceHealth
} from "./chunk-GDPC7PCB.js";
import "./chunk-GJG3O4QS.js";
import "./chunk-PM7DKABI.js";
export {
cmdWorkspace,
createWorkspaceHealthReport,
formatWorkspaceHealthMarkdown,
formatWorkspaceHealthText,
listWorkspaceCandidates,
listWorkspaceProjects,
parseWorkspaceArgs,
shouldFailWorkspaceHealth
};