@vyuhlabs/dxkit 2.4.8 → 2.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +312 -0
- package/README.md +360 -439
- package/dist/analyzers/security/aggregator.d.ts.map +1 -1
- package/dist/analyzers/security/aggregator.js +4 -46
- package/dist/analyzers/security/aggregator.js.map +1 -1
- package/dist/analyzers/tools/fingerprint.d.ts +91 -26
- package/dist/analyzers/tools/fingerprint.d.ts.map +1 -1
- package/dist/analyzers/tools/fingerprint.js +111 -22
- package/dist/analyzers/tools/fingerprint.js.map +1 -1
- package/dist/analyzers/tools/generic.d.ts.map +1 -1
- package/dist/analyzers/tools/generic.js +6 -1
- package/dist/analyzers/tools/generic.js.map +1 -1
- package/dist/analyzers/tools/gitleaks.d.ts +24 -1
- package/dist/analyzers/tools/gitleaks.d.ts.map +1 -1
- package/dist/analyzers/tools/gitleaks.js +20 -11
- package/dist/analyzers/tools/gitleaks.js.map +1 -1
- package/dist/analyzers/tools/graphify.d.ts.map +1 -1
- package/dist/analyzers/tools/graphify.js +9 -5
- package/dist/analyzers/tools/graphify.js.map +1 -1
- package/dist/analyzers/tools/tool-registry.d.ts +19 -1
- package/dist/analyzers/tools/tool-registry.d.ts.map +1 -1
- package/dist/analyzers/tools/tool-registry.js +25 -0
- package/dist/analyzers/tools/tool-registry.js.map +1 -1
- package/dist/analyzers/types.d.ts +6 -4
- package/dist/analyzers/types.d.ts.map +1 -1
- package/dist/baseline/baseline-file.d.ts +104 -0
- package/dist/baseline/baseline-file.d.ts.map +1 -0
- package/dist/baseline/baseline-file.js +110 -0
- package/dist/baseline/baseline-file.js.map +1 -0
- package/dist/baseline/check-renderers.d.ts +108 -0
- package/dist/baseline/check-renderers.d.ts.map +1 -0
- package/dist/baseline/check-renderers.js +379 -0
- package/dist/baseline/check-renderers.js.map +1 -0
- package/dist/baseline/check.d.ts +127 -0
- package/dist/baseline/check.d.ts.map +1 -0
- package/dist/baseline/check.js +462 -0
- package/dist/baseline/check.js.map +1 -0
- package/dist/baseline/content-hash.d.ts +83 -0
- package/dist/baseline/content-hash.d.ts.map +1 -0
- package/dist/baseline/content-hash.js +131 -0
- package/dist/baseline/content-hash.js.map +1 -0
- package/dist/baseline/create.d.ts +96 -0
- package/dist/baseline/create.d.ts.map +1 -0
- package/dist/baseline/create.js +339 -0
- package/dist/baseline/create.js.map +1 -0
- package/dist/baseline/entry-to-located.d.ts +35 -0
- package/dist/baseline/entry-to-located.d.ts.map +1 -0
- package/dist/baseline/entry-to-located.js +72 -0
- package/dist/baseline/entry-to-located.js.map +1 -0
- package/dist/baseline/finding-identity.d.ts +47 -0
- package/dist/baseline/finding-identity.d.ts.map +1 -0
- package/dist/baseline/finding-identity.js +292 -0
- package/dist/baseline/finding-identity.js.map +1 -0
- package/dist/baseline/git-aware-match.d.ts +146 -0
- package/dist/baseline/git-aware-match.d.ts.map +1 -0
- package/dist/baseline/git-aware-match.js +439 -0
- package/dist/baseline/git-aware-match.js.map +1 -0
- package/dist/baseline/policy.d.ts +171 -0
- package/dist/baseline/policy.d.ts.map +1 -0
- package/dist/baseline/policy.js +206 -0
- package/dist/baseline/policy.js.map +1 -0
- package/dist/baseline/producers/health.d.ts +30 -0
- package/dist/baseline/producers/health.d.ts.map +1 -0
- package/dist/baseline/producers/health.js +42 -0
- package/dist/baseline/producers/health.js.map +1 -0
- package/dist/baseline/producers/index.d.ts +164 -0
- package/dist/baseline/producers/index.d.ts.map +1 -0
- package/dist/baseline/producers/index.js +200 -0
- package/dist/baseline/producers/index.js.map +1 -0
- package/dist/baseline/producers/licenses.d.ts +23 -0
- package/dist/baseline/producers/licenses.d.ts.map +1 -0
- package/dist/baseline/producers/licenses.js +46 -0
- package/dist/baseline/producers/licenses.js.map +1 -0
- package/dist/baseline/producers/quality.d.ts +39 -0
- package/dist/baseline/producers/quality.d.ts.map +1 -0
- package/dist/baseline/producers/quality.js +84 -0
- package/dist/baseline/producers/quality.js.map +1 -0
- package/dist/baseline/producers/secret-hmac.d.ts +45 -0
- package/dist/baseline/producers/secret-hmac.d.ts.map +1 -0
- package/dist/baseline/producers/secret-hmac.js +70 -0
- package/dist/baseline/producers/secret-hmac.js.map +1 -0
- package/dist/baseline/producers/security.d.ts +59 -0
- package/dist/baseline/producers/security.d.ts.map +1 -0
- package/dist/baseline/producers/security.js +135 -0
- package/dist/baseline/producers/security.js.map +1 -0
- package/dist/baseline/producers/tests.d.ts +36 -0
- package/dist/baseline/producers/tests.d.ts.map +1 -0
- package/dist/baseline/producers/tests.js +69 -0
- package/dist/baseline/producers/tests.js.map +1 -0
- package/dist/baseline/salt.d.ts +45 -0
- package/dist/baseline/salt.d.ts.map +1 -0
- package/dist/baseline/salt.js +113 -0
- package/dist/baseline/salt.js.map +1 -0
- package/dist/baseline/show.d.ts +79 -0
- package/dist/baseline/show.d.ts.map +1 -0
- package/dist/baseline/show.js +233 -0
- package/dist/baseline/show.js.map +1 -0
- package/dist/baseline/types.d.ts +482 -0
- package/dist/baseline/types.d.ts.map +1 -0
- package/dist/baseline/types.js +53 -0
- package/dist/baseline/types.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +398 -82
- package/dist/cli.js.map +1 -1
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +0 -4
- package/dist/constants.js.map +1 -1
- package/dist/doctor.d.ts.map +1 -1
- package/dist/doctor.js +39 -35
- package/dist/doctor.js.map +1 -1
- package/dist/fail-on.d.ts +84 -0
- package/dist/fail-on.d.ts.map +1 -0
- package/dist/fail-on.js +128 -0
- package/dist/fail-on.js.map +1 -0
- package/dist/generator.d.ts +1 -1
- package/dist/generator.d.ts.map +1 -1
- package/dist/generator.js +81 -274
- package/dist/generator.js.map +1 -1
- package/dist/hooks-cli.d.ts +20 -0
- package/dist/hooks-cli.d.ts.map +1 -0
- package/dist/hooks-cli.js +145 -0
- package/dist/hooks-cli.js.map +1 -0
- package/dist/languages/csharp.d.ts.map +1 -1
- package/dist/languages/csharp.js +4 -9
- package/dist/languages/csharp.js.map +1 -1
- package/dist/languages/go.d.ts.map +1 -1
- package/dist/languages/go.js +3 -14
- package/dist/languages/go.js.map +1 -1
- package/dist/languages/index.d.ts +19 -1
- package/dist/languages/index.d.ts.map +1 -1
- package/dist/languages/index.js +32 -0
- package/dist/languages/index.js.map +1 -1
- package/dist/languages/java.d.ts.map +1 -1
- package/dist/languages/java.js +4 -6
- package/dist/languages/java.js.map +1 -1
- package/dist/languages/kotlin.d.ts.map +1 -1
- package/dist/languages/kotlin.js +9 -11
- package/dist/languages/kotlin.js.map +1 -1
- package/dist/languages/python.d.ts.map +1 -1
- package/dist/languages/python.js +4 -15
- package/dist/languages/python.js.map +1 -1
- package/dist/languages/ruby.d.ts.map +1 -1
- package/dist/languages/ruby.js +4 -6
- package/dist/languages/ruby.js.map +1 -1
- package/dist/languages/rust.d.ts.map +1 -1
- package/dist/languages/rust.js +4 -4
- package/dist/languages/rust.js.map +1 -1
- package/dist/languages/types.d.ts +29 -28
- package/dist/languages/types.d.ts.map +1 -1
- package/dist/languages/typescript.d.ts.map +1 -1
- package/dist/languages/typescript.js +31 -4
- package/dist/languages/typescript.js.map +1 -1
- package/dist/lib.d.ts +2 -3
- package/dist/lib.d.ts.map +1 -1
- package/dist/lib.js +3 -6
- package/dist/lib.js.map +1 -1
- package/dist/prompts.d.ts.map +1 -1
- package/dist/prompts.js +0 -10
- package/dist/prompts.js.map +1 -1
- package/dist/report-schema.d.ts +42 -0
- package/dist/report-schema.d.ts.map +1 -0
- package/dist/report-schema.js +54 -0
- package/dist/report-schema.js.map +1 -0
- package/dist/ship-installers.d.ts +112 -0
- package/dist/ship-installers.d.ts.map +1 -0
- package/dist/ship-installers.js +530 -0
- package/dist/ship-installers.js.map +1 -0
- package/dist/tools-cli.d.ts.map +1 -1
- package/dist/tools-cli.js +45 -9
- package/dist/tools-cli.js.map +1 -1
- package/dist/types.d.ts +0 -4
- package/dist/types.d.ts.map +1 -1
- package/dist/update.d.ts.map +1 -1
- package/dist/update.js +0 -4
- package/dist/update.js.map +1 -1
- package/package.json +17 -11
- package/templates/.claude/skills/dxkit-action/SKILL.md +150 -0
- package/templates/.claude/skills/dxkit-config/SKILL.md +124 -0
- package/templates/.claude/skills/dxkit-hooks/SKILL.md +109 -0
- package/templates/.claude/skills/dxkit-init/SKILL.md +93 -0
- package/templates/.claude/skills/dxkit-learn/SKILL.md +84 -0
- package/templates/.claude/skills/dxkit-reports/SKILL.md +111 -0
- package/templates/.devcontainer/devcontainer.json +55 -0
- package/templates/.devcontainer/install-agent-clis.sh +42 -0
- package/templates/.devcontainer/post-create.sh +81 -0
- package/templates/.githooks/pre-commit +55 -0
- package/templates/.githooks/pre-push +63 -0
- package/templates/.github/workflows/dxkit-baseline-refresh.yml +78 -0
- package/templates/.github/workflows/dxkit-guardrails.yml +98 -0
- package/templates/AGENTS.md.template +137 -0
- package/templates/CLAUDE.md.template +16 -245
- package/dist/codebase-scanner.d.ts +0 -36
- package/dist/codebase-scanner.d.ts.map +0 -1
- package/dist/codebase-scanner.js +0 -688
- package/dist/codebase-scanner.js.map +0 -1
- package/dist/project-yaml.d.ts +0 -13
- package/dist/project-yaml.d.ts.map +0 -1
- package/dist/project-yaml.js +0 -188
- package/dist/project-yaml.js.map +0 -1
- package/templates/.ai/README.md +0 -117
- package/templates/.ai/prompts/execution-prompt.md +0 -9
- package/templates/.ai/prompts/planning-prompt.md +0 -18
- package/templates/.ai/prompts/session-end-template.md +0 -182
- package/templates/.ai/prompts/session-end.md +0 -132
- package/templates/.ai/prompts/session-start.md +0 -109
- package/templates/.ai/prompts/step-by-step.md +0 -113
- package/templates/.ai/sessions/.gitkeep +0 -0
- package/templates/.claude/agents/doc-writer.md +0 -107
- package/templates/.claude/agents/knowledge-bot.md +0 -64
- package/templates/.claude/agents/onboarding.md +0 -61
- package/templates/.claude/agents/quality-reviewer.md +0 -85
- package/templates/.claude/agents-available/code-reviewer.md +0 -29
- package/templates/.claude/agents-available/codebase-explorer.md +0 -100
- package/templates/.claude/agents-available/dashboard-builder.md +0 -433
- package/templates/.claude/agents-available/debugger.md +0 -29
- package/templates/.claude/agents-available/dependency-mapper.md +0 -80
- package/templates/.claude/agents-available/dev-report.md +0 -108
- package/templates/.claude/agents-available/doc-writer.md +0 -107
- package/templates/.claude/agents-available/feature-builder.md +0 -163
- package/templates/.claude/agents-available/feature-planner.md +0 -185
- package/templates/.claude/agents-available/health-auditor.md +0 -95
- package/templates/.claude/agents-available/hooks-configurator.md +0 -211
- package/templates/.claude/agents-available/knowledge-bot.md +0 -62
- package/templates/.claude/agents-available/plan-executor.md +0 -133
- package/templates/.claude/agents-available/strategic-planner.md +0 -141
- package/templates/.claude/agents-available/test-gap-finder.md +0 -67
- package/templates/.claude/agents-available/test-writer.md +0 -34
- package/templates/.claude/agents-available/vulnerability-scanner.md +0 -173
- package/templates/.claude/commands/ask.md +0 -7
- package/templates/.claude/commands/build-feature.md +0 -26
- package/templates/.claude/commands/build.md.template +0 -30
- package/templates/.claude/commands/check.md.template +0 -43
- package/templates/.claude/commands/dashboard.md +0 -28
- package/templates/.claude/commands/deps.md +0 -15
- package/templates/.claude/commands/dev-report.md +0 -50
- package/templates/.claude/commands/docs.md +0 -21
- package/templates/.claude/commands/doctor.md +0 -21
- package/templates/.claude/commands/enable-agent.md +0 -12
- package/templates/.claude/commands/execute-plan.md +0 -25
- package/templates/.claude/commands/explore-codebase.md +0 -12
- package/templates/.claude/commands/export-pdf.md +0 -30
- package/templates/.claude/commands/feature.md +0 -25
- package/templates/.claude/commands/fix-issue.md +0 -12
- package/templates/.claude/commands/fix.md.template +0 -32
- package/templates/.claude/commands/health.md +0 -58
- package/templates/.claude/commands/help.md +0 -36
- package/templates/.claude/commands/learn.md +0 -48
- package/templates/.claude/commands/onboarding.md +0 -21
- package/templates/.claude/commands/plan.md +0 -20
- package/templates/.claude/commands/quality.md.template +0 -65
- package/templates/.claude/commands/session-end.md +0 -40
- package/templates/.claude/commands/session-start.md +0 -30
- package/templates/.claude/commands/setup-hooks.md +0 -18
- package/templates/.claude/commands/setup-pr-review.md +0 -72
- package/templates/.claude/commands/stealth-mode.md +0 -17
- package/templates/.claude/commands/test-gaps.md +0 -49
- package/templates/.claude/commands/test.md.template +0 -40
- package/templates/.claude/commands/vulnerabilities.md +0 -49
- package/templates/.claude/skills/build/SKILL.md.template +0 -98
- package/templates/.claude/skills/deploy/SKILL.md.template +0 -131
- package/templates/.claude/skills/deploy/references/gotchas.md +0 -5
- package/templates/.claude/skills/doctor/SKILL.md +0 -54
- package/templates/.claude/skills/gcloud/SKILL.md +0 -66
- package/templates/.claude/skills/gcloud/references/gotchas.md +0 -5
- package/templates/.claude/skills/learned/SKILL.md +0 -55
- package/templates/.claude/skills/learned/references/conventions.md +0 -11
- package/templates/.claude/skills/learned/references/deny-recommendations.md +0 -18
- package/templates/.claude/skills/learned/references/gotchas.md +0 -11
- package/templates/.claude/skills/pulumi/SKILL.md +0 -73
- package/templates/.claude/skills/quality/SKILL.md.template +0 -108
- package/templates/.claude/skills/quality/references/gotchas.md +0 -5
- package/templates/.claude/skills/review/SKILL.md.template +0 -73
- package/templates/.claude/skills/scaffold/SKILL.md.template +0 -123
- package/templates/.claude/skills/secrets/SKILL.md +0 -52
- package/templates/.claude/skills/session/SKILL.md +0 -43
- package/templates/.claude/skills/test/SKILL.md.template +0 -122
- package/templates/.claude/skills/test/references/gotchas.md +0 -5
- package/templates/.devcontainer/Dockerfile.dev.template +0 -89
- package/templates/.devcontainer/devcontainer.json.template +0 -184
- package/templates/.devcontainer/docker-compose.yml.template +0 -105
- package/templates/.devcontainer/init-scripts/01-init.sql.template +0 -12
- package/templates/.devcontainer/post-create.sh.template +0 -298
- package/templates/.github/workflows/ci.yml.template +0 -399
- package/templates/.github/workflows/quality.yml.template +0 -376
- package/templates/.pre-commit-config.yaml.template +0 -106
- package/templates/.project/config/edit_config.py +0 -275
- package/templates/.project/config/project_config.py +0 -894
- package/templates/.project/scripts/codegen/generate-all.sh +0 -20
- package/templates/.project/scripts/codegen/validate-all.sh +0 -17
- package/templates/.project/scripts/docs/generate-all.sh +0 -30
- package/templates/.project/scripts/docs/serve.sh +0 -20
- package/templates/.project/scripts/quality/fix-all.sh +0 -138
- package/templates/.project/scripts/quality/lint-go.sh +0 -34
- package/templates/.project/scripts/quality/lint-python.sh +0 -54
- package/templates/.project/scripts/quality/run-all.sh +0 -497
- package/templates/.project/scripts/session/commit.sh +0 -70
- package/templates/.project/scripts/session/create-pr.sh +0 -165
- package/templates/.project/scripts/session/end.sh +0 -207
- package/templates/.project/scripts/session/start.sh +0 -233
- package/templates/.project/scripts/setup/doctor.sh +0 -404
- package/templates/.project/scripts/setup/interactive-setup.sh +0 -585
- package/templates/.project/scripts/sync/sync-template.sh +0 -328
- package/templates/.project/scripts/test/run-all.sh +0 -179
- package/templates/.project/scripts/test/run-quick.sh +0 -25
- package/templates/Makefile +0 -514
- package/templates/config/versions.yaml +0 -57
- package/templates/configs/go/.golangci.yml.template +0 -172
- package/templates/configs/go/go.mod.template +0 -15
- package/templates/configs/java/README.md +0 -6
- package/templates/configs/kotlin/README.md +0 -6
- package/templates/configs/node/package.json.template +0 -67
- package/templates/configs/node/tsconfig.json.template +0 -53
- package/templates/configs/python/pyproject.toml.template +0 -92
- package/templates/configs/python/pytest.ini.template +0 -64
- package/templates/configs/python/ruff.toml.template +0 -79
- package/templates/configs/ruby/README.md +0 -6
- package/templates/configs/rust/Cargo.toml.template +0 -51
- package/templates/configs/shared/.editorconfig +0 -67
- package/templates/scripts/validate-templates.sh +0 -449
package/dist/cli.js
CHANGED
|
@@ -39,7 +39,6 @@ const vendored_advisor_1 = require("./analyzers/tools/vendored-advisor");
|
|
|
39
39
|
const detect_1 = require("./detect");
|
|
40
40
|
const generator_1 = require("./generator");
|
|
41
41
|
const prompts_1 = require("./prompts");
|
|
42
|
-
const project_yaml_1 = require("./project-yaml");
|
|
43
42
|
const update_1 = require("./update");
|
|
44
43
|
const doctor_1 = require("./doctor");
|
|
45
44
|
const constants_1 = require("./constants");
|
|
@@ -47,6 +46,9 @@ const logger = __importStar(require("./logger"));
|
|
|
47
46
|
const scoring_1 = require("./scoring");
|
|
48
47
|
const tools_unavailable_prose_1 = require("./analyzers/tools/tools-unavailable-prose");
|
|
49
48
|
const report_date_1 = require("./analyzers/tools/report-date");
|
|
49
|
+
const fail_on_1 = require("./fail-on");
|
|
50
|
+
const report_schema_1 = require("./report-schema");
|
|
51
|
+
const ship_installers_1 = require("./ship-installers");
|
|
50
52
|
const fs = __importStar(require("fs"));
|
|
51
53
|
const path = __importStar(require("path"));
|
|
52
54
|
// process.stdout.write returns false when the OS pipe buffer is full
|
|
@@ -60,12 +62,51 @@ async function emitJson(payload) {
|
|
|
60
62
|
await new Promise((resolve) => process.stdout.once('drain', resolve));
|
|
61
63
|
}
|
|
62
64
|
}
|
|
65
|
+
/**
|
|
66
|
+
* Apply `--fail-on-score` to a higher-is-better score. Exits with
|
|
67
|
+
* code 1 + a logged reason when the gate fires. Skips when the user
|
|
68
|
+
* didn't pass the flag. Centralized so every analyzer that supports
|
|
69
|
+
* the flag fires consistent messages.
|
|
70
|
+
*/
|
|
71
|
+
function applyFailOnScore(raw, score, scoreLabel) {
|
|
72
|
+
if (raw === undefined)
|
|
73
|
+
return;
|
|
74
|
+
const threshold = (0, fail_on_1.parseScoreThreshold)(raw);
|
|
75
|
+
if (threshold === null) {
|
|
76
|
+
logger.fail(`--fail-on-score: invalid value "${raw}". Expected a number in [0, 100].`);
|
|
77
|
+
process.exit(1);
|
|
78
|
+
}
|
|
79
|
+
const verdict = (0, fail_on_1.checkFailOnScore)(score, threshold);
|
|
80
|
+
if (verdict.fails) {
|
|
81
|
+
logger.fail(`${scoreLabel} ${verdict.reason}`);
|
|
82
|
+
process.exit(1);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Apply `--fail-on-severity` to a per-severity count map. Exits
|
|
87
|
+
* with code 1 + a logged reason when the gate fires. Skips when
|
|
88
|
+
* the user didn't pass the flag.
|
|
89
|
+
*/
|
|
90
|
+
function applyFailOnSeverity(raw, counts, countsLabel) {
|
|
91
|
+
if (raw === undefined)
|
|
92
|
+
return;
|
|
93
|
+
const tier = (0, fail_on_1.parseSeverityTier)(raw);
|
|
94
|
+
if (tier === null) {
|
|
95
|
+
logger.fail(`--fail-on-severity: invalid tier "${raw}". Expected one of: critical, high, medium, low.`);
|
|
96
|
+
process.exit(1);
|
|
97
|
+
}
|
|
98
|
+
const verdict = (0, fail_on_1.checkFailOnSeverity)(counts, tier);
|
|
99
|
+
if (verdict.fails) {
|
|
100
|
+
logger.fail(`${countsLabel}: ${verdict.reason}`);
|
|
101
|
+
process.exit(1);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
63
104
|
function printUsage() {
|
|
64
105
|
console.log(`
|
|
65
|
-
${logger.bold('vyuh-dxkit')} v${constants_1.VERSION} — AI-native developer experience toolkit
|
|
106
|
+
${logger.bold('vyuh-dxkit')} v${constants_1.VERSION} — AI-native developer experience toolkit for any codebase
|
|
66
107
|
|
|
67
108
|
${logger.bold('Usage:')}
|
|
68
|
-
vyuh-dxkit init [options]
|
|
109
|
+
vyuh-dxkit init [options] Install dxkit agent DX in this repo
|
|
69
110
|
vyuh-dxkit update [options] Re-generate (preserves evolved files)
|
|
70
111
|
vyuh-dxkit doctor Verify setup
|
|
71
112
|
vyuh-dxkit health [path] Run deterministic health analysis
|
|
@@ -81,23 +122,56 @@ function printUsage() {
|
|
|
81
122
|
vyuh-dxkit to-xlsx <json> Convert a dxkit JSON report to 15-col XLSX
|
|
82
123
|
vyuh-dxkit tools [path] Show required analysis tools status
|
|
83
124
|
vyuh-dxkit tools install Interactively install missing tools
|
|
125
|
+
vyuh-dxkit baseline create [path] [--name <name>] [--force]
|
|
126
|
+
Capture per-finding identities to .dxkit/baselines/<name>.json
|
|
127
|
+
(read later by guardrail check to gate new regressions)
|
|
128
|
+
vyuh-dxkit baseline show [path] [--name <n>] [--baseline <path>]
|
|
129
|
+
[--kind <kind>] [--json]
|
|
130
|
+
Pretty-print the on-disk baseline. Default: summary +
|
|
131
|
+
per-kind counts. --kind drills into one kind. --json
|
|
132
|
+
emits a schema-banner-wrapped payload.
|
|
133
|
+
vyuh-dxkit guardrail check [path] [--name <n>] [--baseline <path>]
|
|
134
|
+
[--changed-only] [--policy <path>]
|
|
135
|
+
[--json | --markdown]
|
|
136
|
+
Diff current scan against the named baseline; block on net-new
|
|
137
|
+
regressions per brownfield policy. Exit code 1 when blocked.
|
|
138
|
+
vyuh-dxkit hooks activate [path]
|
|
139
|
+
Idempotently set core.hooksPath = .githooks. Wired into
|
|
140
|
+
package.json postinstall by 'init --with-hooks' so every
|
|
141
|
+
clone + 'npm install' activates the dxkit hooks
|
|
142
|
+
automatically. Safe to run by hand; always exits 0.
|
|
84
143
|
|
|
85
144
|
${logger.bold('Init options:')}
|
|
86
|
-
--dx-only
|
|
87
|
-
--full
|
|
88
|
-
|
|
89
|
-
--
|
|
90
|
-
--
|
|
91
|
-
--
|
|
92
|
-
|
|
93
|
-
--
|
|
145
|
+
--dx-only Just .claude/ + CLAUDE.md (default)
|
|
146
|
+
--full Everything: DX + quality + hooks + devcontainer +
|
|
147
|
+
CI guardrails + baseline-refresh workflow
|
|
148
|
+
--with-hooks Install .githooks/pre-push guardrail hook (pre-commit opt-in)
|
|
149
|
+
--with-precommit-hook Also install .githooks/pre-commit (slow on large repos)
|
|
150
|
+
--with-devcontainer Install .devcontainer/ with pinned toolchains +
|
|
151
|
+
dxkit + Claude Code & Codex CLIs
|
|
152
|
+
--with-dxkit-agents Install AGENTS.md + CLAUDE.md shim + the 6 dxkit-
|
|
153
|
+
specific skills (learn/init/config/hooks/reports/
|
|
154
|
+
action) for Claude Code auto-discovery
|
|
155
|
+
--with-ci Install .github/workflows/dxkit-guardrails.yml
|
|
156
|
+
(PR-gate that posts a markdown summary comment)
|
|
157
|
+
--with-baseline-refresh Install .github/workflows/dxkit-baseline-refresh.yml
|
|
158
|
+
--with-pr-review Install .github/workflows/pr-review.yml (AI PR review; opt-in)
|
|
159
|
+
(post-merge auto-regen of .dxkit/baselines/main.json)
|
|
160
|
+
--detect Auto-detect stack, minimal prompts
|
|
161
|
+
--yes Accept all defaults, no prompts
|
|
162
|
+
--force Overwrite existing files (incl. existing hooks/
|
|
163
|
+
devcontainer instead of writing .dxkit sidecars)
|
|
164
|
+
--stealth Gitignore generated files (local-only, not committed)
|
|
165
|
+
--name <n> Override project name
|
|
166
|
+
--no-scan Skip codebase analysis
|
|
94
167
|
|
|
95
168
|
${logger.bold('Update options:')}
|
|
96
169
|
--force Overwrite modified files (except evolved)
|
|
97
170
|
--rescan Re-run codebase analysis
|
|
98
171
|
|
|
99
172
|
${logger.bold('Analyzer options (health, vulnerabilities, test-gaps, quality, dev-report, licenses, bom):')}
|
|
100
|
-
--json Print report as JSON to stdout
|
|
173
|
+
--json Print report as JSON to stdout (top-level 'schema' field
|
|
174
|
+
carries the dxkit.<kind>-report.v1 banner for version-gating)
|
|
101
175
|
--verbose Print per-tool timing to stderr
|
|
102
176
|
--no-save Skip writing the markdown report file
|
|
103
177
|
--detailed Also write <name>-detailed.md + .json with evidence + ranked actions
|
|
@@ -107,6 +181,12 @@ function printUsage() {
|
|
|
107
181
|
advisory rollup under byTopLevelDep still reflects transitives)
|
|
108
182
|
--with-coverage Health/test-gaps: materialize coverage artifacts via per-pack
|
|
109
183
|
runTests() before analysis (line-coverage truth vs filename match)
|
|
184
|
+
--fail-on-score <N> Exit 1 when the analyzer's headline score drops below N.
|
|
185
|
+
Applies to: health (overallScore), test-gaps (effectiveCoverage).
|
|
186
|
+
--fail-on-severity <tier>
|
|
187
|
+
Exit 1 when any finding at <tier> or higher exists.
|
|
188
|
+
tier ∈ critical|high|medium|low.
|
|
189
|
+
Applies to: vulnerabilities, bom.
|
|
110
190
|
|
|
111
191
|
${logger.bold('Examples:')}
|
|
112
192
|
npx vyuh-dxkit init # Interactive
|
|
@@ -147,6 +227,21 @@ async function run(argv) {
|
|
|
147
227
|
timeout: { type: 'string' },
|
|
148
228
|
'no-fail-fast': { type: 'boolean', default: false },
|
|
149
229
|
'with-coverage': { type: 'boolean', default: false },
|
|
230
|
+
'changed-only': { type: 'boolean', default: false },
|
|
231
|
+
baseline: { type: 'string' },
|
|
232
|
+
policy: { type: 'string' },
|
|
233
|
+
markdown: { type: 'boolean', default: false },
|
|
234
|
+
'fail-on-score': { type: 'string' },
|
|
235
|
+
'fail-on-severity': { type: 'string' },
|
|
236
|
+
summary: { type: 'boolean', default: false },
|
|
237
|
+
kind: { type: 'string' },
|
|
238
|
+
'with-hooks': { type: 'boolean', default: false },
|
|
239
|
+
'with-precommit-hook': { type: 'boolean', default: false },
|
|
240
|
+
'with-devcontainer': { type: 'boolean', default: false },
|
|
241
|
+
'with-dxkit-agents': { type: 'boolean', default: false },
|
|
242
|
+
'with-ci': { type: 'boolean', default: false },
|
|
243
|
+
'with-baseline-refresh': { type: 'boolean', default: false },
|
|
244
|
+
'with-pr-review': { type: 'boolean', default: false },
|
|
150
245
|
},
|
|
151
246
|
allowPositionals: true,
|
|
152
247
|
strict: false,
|
|
@@ -174,66 +269,117 @@ async function run(argv) {
|
|
|
174
269
|
switch (command) {
|
|
175
270
|
case 'init': {
|
|
176
271
|
logger.header('vyuh-dxkit init');
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
.map(([k]) => k);
|
|
188
|
-
const tools = Object.entries(config.tools)
|
|
189
|
-
.filter(([, v]) => v)
|
|
190
|
-
.map(([k]) => k);
|
|
191
|
-
if (langs.length)
|
|
192
|
-
logger.success(`Languages: ${langs.join(', ')}`);
|
|
193
|
-
if (tools.length)
|
|
194
|
-
logger.success(`Tools: ${tools.join(', ')}`);
|
|
195
|
-
console.log('');
|
|
196
|
-
// .project.yaml implies full mode (create-devstack handles the wizard)
|
|
197
|
-
finalMode = values['dx-only'] ? 'dx-only' : 'full';
|
|
198
|
-
}
|
|
199
|
-
else {
|
|
200
|
-
logger.warn('Found .project.yaml but it is malformed — falling back to detection.');
|
|
201
|
-
}
|
|
272
|
+
logger.info('Detecting stack...');
|
|
273
|
+
const detected = (0, detect_1.detect)(cwd);
|
|
274
|
+
const langs = Object.entries(detected.languages)
|
|
275
|
+
.filter(([, v]) => v)
|
|
276
|
+
.map(([k]) => k);
|
|
277
|
+
const tools = Object.entries(detected.tools)
|
|
278
|
+
.filter(([, v]) => v)
|
|
279
|
+
.map(([k]) => k);
|
|
280
|
+
if (langs.length === 0) {
|
|
281
|
+
logger.warn('No languages detected. Generating with minimal config.');
|
|
202
282
|
}
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
283
|
+
else {
|
|
284
|
+
logger.success(`Languages: ${langs.join(', ')}`);
|
|
285
|
+
}
|
|
286
|
+
if (tools.length)
|
|
287
|
+
logger.success(`Tools: ${tools.join(', ')}`);
|
|
288
|
+
if (detected.framework)
|
|
289
|
+
logger.success(`Framework: ${detected.framework}`);
|
|
290
|
+
if (detected.testRunner)
|
|
291
|
+
logger.success(`Tests: ${detected.testRunner.framework} (${detected.testRunner.command})`);
|
|
292
|
+
console.log(''); // slop-ok
|
|
293
|
+
const promptOpts = {
|
|
294
|
+
yes: !!(values.yes || values.detect),
|
|
295
|
+
detect: !!values.detect,
|
|
296
|
+
name: values.name,
|
|
297
|
+
};
|
|
298
|
+
const promptResult = await (0, prompts_1.promptForConfig)(detected, promptOpts);
|
|
299
|
+
const config = promptResult.config;
|
|
300
|
+
const finalMode = values.full
|
|
301
|
+
? 'full'
|
|
302
|
+
: values['dx-only']
|
|
303
|
+
? 'dx-only'
|
|
304
|
+
: promptResult.mode;
|
|
305
|
+
// The six dxkit-* skills + AGENTS.md + CLAUDE.md shim are the
|
|
306
|
+
// marquee 2.5.1 surface. Default-off on bare `init` (keep the
|
|
307
|
+
// first-install quiet); default-on under `--full` (matches the
|
|
308
|
+
// rest of the ship surface — hooks/devcontainer/CI all opt-in
|
|
309
|
+
// via flags but bundled under --full).
|
|
310
|
+
const wantDxkitAgents = !!values.full || !!values['with-dxkit-agents'];
|
|
311
|
+
const result = await (0, generator_1.generate)(cwd, config, finalMode, !!values.force, !!values['no-scan'], wantDxkitAgents);
|
|
312
|
+
// Phase Ship installers (additive). `--full` implies every flag
|
|
313
|
+
// so a one-command setup gets the full 2.5.0 ship surface.
|
|
314
|
+
const isFull = !!values.full;
|
|
315
|
+
// pre-commit hook stays opt-in even under --full because it
|
|
316
|
+
// re-runs every analyzer on every commit (slow on large
|
|
317
|
+
// codebases until incremental scanning lands). Pre-push +
|
|
318
|
+
// CI catch the same regressions before code leaves the
|
|
319
|
+
// developer's machine.
|
|
320
|
+
const wantPrecommitHook = !!values['with-precommit-hook'];
|
|
321
|
+
// --with-precommit-hook implies --with-hooks (so the
|
|
322
|
+
// installer actually runs to install pre-commit alongside
|
|
323
|
+
// pre-push).
|
|
324
|
+
const wantHooks = isFull || !!values['with-hooks'] || wantPrecommitHook;
|
|
325
|
+
const wantDevcontainer = isFull || !!values['with-devcontainer'];
|
|
326
|
+
const wantCi = isFull || !!values['with-ci'];
|
|
327
|
+
const wantBaselineRefresh = isFull || !!values['with-baseline-refresh'];
|
|
328
|
+
// pr-review is opt-in even under --full because the workflow
|
|
329
|
+
// is inert without `ANTHROPIC_API_KEY` + `ENABLE_AI_REVIEW=true`
|
|
330
|
+
// configured separately. Shipping it by default just clutters
|
|
331
|
+
// the Actions tab on repos that don't intend to enable it.
|
|
332
|
+
const wantPrReview = !!values['with-pr-review'];
|
|
333
|
+
const shipResults = [];
|
|
334
|
+
if (wantHooks) {
|
|
335
|
+
shipResults.push({
|
|
336
|
+
label: 'Git hooks',
|
|
337
|
+
result: (0, ship_installers_1.installHooks)(cwd, {
|
|
338
|
+
force: !!values.force,
|
|
339
|
+
withPrecommit: wantPrecommitHook,
|
|
340
|
+
}),
|
|
341
|
+
});
|
|
342
|
+
// Auto-activate hooksPath via package.json postinstall when a
|
|
343
|
+
// package.json is present. No-ops for non-Node repos. Skipping
|
|
344
|
+
// requires explicit user choice rather than a flag: customers
|
|
345
|
+
// who don't want automation can delete the line from
|
|
346
|
+
// scripts.postinstall after init.
|
|
347
|
+
shipResults.push({
|
|
348
|
+
label: 'Hooks auto-activation',
|
|
349
|
+
result: (0, ship_installers_1.installHooksPostinstall)(cwd, { force: !!values.force }),
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
if (wantDevcontainer) {
|
|
353
|
+
shipResults.push({
|
|
354
|
+
label: 'Devcontainer',
|
|
355
|
+
result: (0, ship_installers_1.installDevcontainer)(cwd, { force: !!values.force }),
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
if (wantCi) {
|
|
359
|
+
shipResults.push({
|
|
360
|
+
label: 'CI guardrails workflow',
|
|
361
|
+
result: (0, ship_installers_1.installCiGuardrails)(cwd, { force: !!values.force }),
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
if (wantBaselineRefresh) {
|
|
365
|
+
shipResults.push({
|
|
366
|
+
label: 'CI baseline-refresh workflow',
|
|
367
|
+
result: (0, ship_installers_1.installCiBaselineRefresh)(cwd, { force: !!values.force }),
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
if (wantPrReview) {
|
|
371
|
+
shipResults.push({
|
|
372
|
+
label: 'AI PR-review workflow',
|
|
373
|
+
result: (0, ship_installers_1.installPrReview)(cwd, { force: !!values.force }),
|
|
374
|
+
});
|
|
235
375
|
}
|
|
236
|
-
|
|
376
|
+
// .gitignore + .dxkit-ignore seeding: default-on, no flag.
|
|
377
|
+
// Additive (existing entries preserved); safe for both fresh
|
|
378
|
+
// installs and re-runs.
|
|
379
|
+
shipResults.push({
|
|
380
|
+
label: 'Ignore files',
|
|
381
|
+
result: (0, ship_installers_1.installIgnoreFiles)(cwd, { force: !!values.force }),
|
|
382
|
+
});
|
|
237
383
|
// Summary
|
|
238
384
|
console.log('');
|
|
239
385
|
logger.header('Summary');
|
|
@@ -243,6 +389,23 @@ async function run(argv) {
|
|
|
243
389
|
logger.warn(`Skipped: ${result.skipped.length} files (already exist)`);
|
|
244
390
|
if (result.overwritten.length)
|
|
245
391
|
logger.info(`Overwritten: ${result.overwritten.length} files`);
|
|
392
|
+
for (const { label, result: r } of shipResults) {
|
|
393
|
+
if (r.installed.length) {
|
|
394
|
+
logger.success(`${label}: installed ${r.installed.length} file(s)`);
|
|
395
|
+
for (const f of r.installed)
|
|
396
|
+
logger.dim(` ${f}`);
|
|
397
|
+
}
|
|
398
|
+
if (r.sidecars.length) {
|
|
399
|
+
logger.warn(`${label}: ${r.sidecars.length} sidecar(s) written (existing files preserved)`);
|
|
400
|
+
for (const f of r.sidecars)
|
|
401
|
+
logger.dim(` ${f}`);
|
|
402
|
+
}
|
|
403
|
+
if (r.skipped.length) {
|
|
404
|
+
logger.dim(`${label}: ${r.skipped.length} file(s) skipped (already present)`);
|
|
405
|
+
}
|
|
406
|
+
for (const note of r.notes)
|
|
407
|
+
logger.info(note);
|
|
408
|
+
}
|
|
246
409
|
console.log('');
|
|
247
410
|
logger.info('Manifest written to .vyuh-dxkit.json');
|
|
248
411
|
// Stealth mode: gitignore only files we just created
|
|
@@ -254,6 +417,9 @@ async function run(argv) {
|
|
|
254
417
|
console.log('');
|
|
255
418
|
logger.dim(' Run `vyuh-dxkit doctor` to verify setup');
|
|
256
419
|
logger.dim(' Run `vyuh-dxkit update` to re-generate after changes');
|
|
420
|
+
if (shipResults.length > 0) {
|
|
421
|
+
logger.dim(" Run `vyuh-dxkit baseline create` to capture today's state");
|
|
422
|
+
}
|
|
257
423
|
break;
|
|
258
424
|
}
|
|
259
425
|
case 'update': {
|
|
@@ -311,7 +477,7 @@ async function run(argv) {
|
|
|
311
477
|
const healthMetrics = healthResult.metrics;
|
|
312
478
|
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
|
|
313
479
|
if (values.json) {
|
|
314
|
-
await emitJson(report);
|
|
480
|
+
await emitJson((0, report_schema_1.stampSchema)(report, 'health'));
|
|
315
481
|
}
|
|
316
482
|
else {
|
|
317
483
|
// Console output
|
|
@@ -368,13 +534,17 @@ async function run(argv) {
|
|
|
368
534
|
const detailed = buildHealthDetailed(report, healthMetrics);
|
|
369
535
|
const detailedJsonPath = path.join(reportDir, `health-audit-${date}-detailed.json`);
|
|
370
536
|
const detailedMdPath = path.join(reportDir, `health-audit-${date}-detailed.md`);
|
|
371
|
-
fs.writeFileSync(detailedJsonPath, JSON.stringify(detailed, null, 2));
|
|
537
|
+
fs.writeFileSync(detailedJsonPath, JSON.stringify((0, report_schema_1.stampSchema)(detailed, 'health-detailed'), null, 2));
|
|
372
538
|
fs.writeFileSync(detailedMdPath, formatHealthDetailedMarkdown(detailed, elapsed));
|
|
373
539
|
if (values.detailed) {
|
|
374
540
|
logger.success(`Detailed report saved to ${path.relative(targetPath, detailedMdPath)}`);
|
|
375
541
|
logger.success(`Detailed JSON saved to ${path.relative(targetPath, detailedJsonPath)}`);
|
|
376
542
|
}
|
|
377
543
|
}
|
|
544
|
+
// --fail-on-score: applies to the overall health score. Runs
|
|
545
|
+
// after disk writes so a failure still leaves a complete
|
|
546
|
+
// report behind for inspection.
|
|
547
|
+
applyFailOnScore(values['fail-on-score'], report.summary.overallScore, 'health overallScore');
|
|
378
548
|
if (!values.json) {
|
|
379
549
|
// Hint about missing tools (exclude project-side config errors).
|
|
380
550
|
const PROJECT_ISSUES = ['config error', 'legacy .eslintrc', 'no eslint config'];
|
|
@@ -436,7 +606,7 @@ async function run(argv) {
|
|
|
436
606
|
const report = await analyzeSecurity(targetPath, { verbose: !!values.verbose });
|
|
437
607
|
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
|
|
438
608
|
if (values.json) {
|
|
439
|
-
await emitJson(report);
|
|
609
|
+
await emitJson((0, report_schema_1.stampSchema)(report, 'vulnerabilities'));
|
|
440
610
|
}
|
|
441
611
|
else {
|
|
442
612
|
const s = report.summary.findings;
|
|
@@ -470,13 +640,20 @@ async function run(argv) {
|
|
|
470
640
|
const securityDetailed = buildSecurityDetailed(report);
|
|
471
641
|
const securityDetailedJsonPath = path.join(reportDir, `vulnerability-scan-${date}-detailed.json`);
|
|
472
642
|
const securityDetailedMdPath = path.join(reportDir, `vulnerability-scan-${date}-detailed.md`);
|
|
473
|
-
fs.writeFileSync(securityDetailedJsonPath, JSON.stringify(securityDetailed, null, 2));
|
|
643
|
+
fs.writeFileSync(securityDetailedJsonPath, JSON.stringify((0, report_schema_1.stampSchema)(securityDetailed, 'vulnerabilities-detailed'), null, 2));
|
|
474
644
|
fs.writeFileSync(securityDetailedMdPath, formatSecurityDetailedMarkdown(securityDetailed, elapsed));
|
|
475
645
|
if (values.detailed) {
|
|
476
646
|
logger.success(`Detailed report saved to ${path.relative(targetPath, securityDetailedMdPath)}`);
|
|
477
647
|
logger.success(`Detailed JSON saved to ${path.relative(targetPath, securityDetailedJsonPath)}`);
|
|
478
648
|
}
|
|
479
649
|
}
|
|
650
|
+
// --fail-on-severity: applies to both code findings and
|
|
651
|
+
// dependency advisories. Code findings fire first because
|
|
652
|
+
// they're typically actionable (a SAST hit you wrote);
|
|
653
|
+
// dependency advisories second (transitive issue you may need
|
|
654
|
+
// to triage).
|
|
655
|
+
applyFailOnSeverity(values['fail-on-severity'], report.summary.findings, 'vulnerabilities (code)');
|
|
656
|
+
applyFailOnSeverity(values['fail-on-severity'], report.summary.dependencies, 'vulnerabilities (dependencies)');
|
|
480
657
|
break;
|
|
481
658
|
}
|
|
482
659
|
case 'test-gaps': {
|
|
@@ -510,7 +687,7 @@ async function run(argv) {
|
|
|
510
687
|
const report = await analyzeTestGaps(targetPath, { verbose: !!values.verbose });
|
|
511
688
|
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
|
|
512
689
|
if (values.json) {
|
|
513
|
-
await emitJson(report);
|
|
690
|
+
await emitJson((0, report_schema_1.stampSchema)(report, 'test-gaps'));
|
|
514
691
|
}
|
|
515
692
|
else {
|
|
516
693
|
const s = report.summary;
|
|
@@ -540,13 +717,18 @@ async function run(argv) {
|
|
|
540
717
|
const testGapsDetailed = buildTestGapsDetailed(report);
|
|
541
718
|
const testGapsDetailedJsonPath = path.join(reportDir, `test-gaps-${date}-detailed.json`);
|
|
542
719
|
const testGapsDetailedMdPath = path.join(reportDir, `test-gaps-${date}-detailed.md`);
|
|
543
|
-
fs.writeFileSync(testGapsDetailedJsonPath, JSON.stringify(testGapsDetailed, null, 2));
|
|
720
|
+
fs.writeFileSync(testGapsDetailedJsonPath, JSON.stringify((0, report_schema_1.stampSchema)(testGapsDetailed, 'test-gaps-detailed'), null, 2));
|
|
544
721
|
fs.writeFileSync(testGapsDetailedMdPath, formatTestGapsDetailedMarkdown(testGapsDetailed, elapsed));
|
|
545
722
|
if (values.detailed) {
|
|
546
723
|
logger.success(`Detailed report saved to ${path.relative(targetPath, testGapsDetailedMdPath)}`);
|
|
547
724
|
logger.success(`Detailed JSON saved to ${path.relative(targetPath, testGapsDetailedJsonPath)}`);
|
|
548
725
|
}
|
|
549
726
|
}
|
|
727
|
+
// --fail-on-score: applies to the headline effectiveCoverage
|
|
728
|
+
// percentage. Tests-gap reports use a higher-is-better
|
|
729
|
+
// coverage scale, so the same threshold semantics work as
|
|
730
|
+
// for the health overall score.
|
|
731
|
+
applyFailOnScore(values['fail-on-score'], report.summary.effectiveCoverage, 'test-gaps effectiveCoverage');
|
|
550
732
|
break;
|
|
551
733
|
}
|
|
552
734
|
case 'quality': {
|
|
@@ -561,7 +743,7 @@ async function run(argv) {
|
|
|
561
743
|
});
|
|
562
744
|
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
|
|
563
745
|
if (values.json) {
|
|
564
|
-
await emitJson(report);
|
|
746
|
+
await emitJson((0, report_schema_1.stampSchema)(report, 'quality'));
|
|
565
747
|
}
|
|
566
748
|
else {
|
|
567
749
|
const m = report.metrics;
|
|
@@ -633,7 +815,7 @@ async function run(argv) {
|
|
|
633
815
|
});
|
|
634
816
|
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
|
|
635
817
|
if (values.json) {
|
|
636
|
-
await emitJson(report);
|
|
818
|
+
await emitJson((0, report_schema_1.stampSchema)(report, 'dev-report'));
|
|
637
819
|
}
|
|
638
820
|
else {
|
|
639
821
|
const s = report.summary;
|
|
@@ -690,7 +872,7 @@ async function run(argv) {
|
|
|
690
872
|
const report = await analyzeLicenses(targetPath, { verbose: !!values.verbose });
|
|
691
873
|
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
|
|
692
874
|
if (values.json) {
|
|
693
|
-
await emitJson(report); // slop-ok
|
|
875
|
+
await emitJson((0, report_schema_1.stampSchema)(report, 'licenses')); // slop-ok
|
|
694
876
|
}
|
|
695
877
|
else {
|
|
696
878
|
const s = report.summary;
|
|
@@ -766,7 +948,7 @@ async function run(argv) {
|
|
|
766
948
|
});
|
|
767
949
|
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
|
|
768
950
|
if (values.json) {
|
|
769
|
-
await emitJson(report); // slop-ok
|
|
951
|
+
await emitJson((0, report_schema_1.stampSchema)(report, 'bom')); // slop-ok
|
|
770
952
|
}
|
|
771
953
|
else {
|
|
772
954
|
const s = report.summary;
|
|
@@ -835,6 +1017,12 @@ async function run(argv) {
|
|
|
835
1017
|
logger.success(`XLSX saved to ${path.relative(targetPath, xlsxPath)}`);
|
|
836
1018
|
}
|
|
837
1019
|
}
|
|
1020
|
+
// --fail-on-severity: BomReport.summary.bySeverity carries
|
|
1021
|
+
// per-package max-severity counts. A package with multiple
|
|
1022
|
+
// advisories is counted once at its highest severity, which
|
|
1023
|
+
// is what a "block at this tier" gate wants — not double
|
|
1024
|
+
// counting.
|
|
1025
|
+
applyFailOnSeverity(values['fail-on-severity'], report.summary.bySeverity, 'bom severity');
|
|
838
1026
|
break;
|
|
839
1027
|
}
|
|
840
1028
|
case 'dashboard': {
|
|
@@ -1118,6 +1306,130 @@ async function run(argv) {
|
|
|
1118
1306
|
logger.dim(`Converted in ${elapsed}s · report kind: ${kind}`);
|
|
1119
1307
|
break;
|
|
1120
1308
|
}
|
|
1309
|
+
case 'hooks': {
|
|
1310
|
+
const subCommand = positionals[1];
|
|
1311
|
+
if (subCommand === 'activate') {
|
|
1312
|
+
const targetPath = resolveRepoPath(positionals[2]);
|
|
1313
|
+
const { runHooksActivate } = await Promise.resolve().then(() => __importStar(require('./hooks-cli')));
|
|
1314
|
+
runHooksActivate(targetPath);
|
|
1315
|
+
break;
|
|
1316
|
+
}
|
|
1317
|
+
logger.fail(`Unknown hooks subcommand: ${subCommand ?? '(missing)'}. ` +
|
|
1318
|
+
`Available: vyuh-dxkit hooks activate [path]`);
|
|
1319
|
+
process.exit(1);
|
|
1320
|
+
break;
|
|
1321
|
+
}
|
|
1322
|
+
case 'baseline': {
|
|
1323
|
+
const subCommand = positionals[1];
|
|
1324
|
+
if (subCommand === 'create') {
|
|
1325
|
+
const targetPath = resolveRepoPath(positionals[2]);
|
|
1326
|
+
const { createBaseline } = await Promise.resolve().then(() => __importStar(require('./baseline/create')));
|
|
1327
|
+
logger.header('vyuh-dxkit baseline create');
|
|
1328
|
+
logger.info(`Capturing baseline for ${targetPath}...`);
|
|
1329
|
+
const startTime = Date.now();
|
|
1330
|
+
try {
|
|
1331
|
+
const result = await createBaseline({
|
|
1332
|
+
cwd: targetPath,
|
|
1333
|
+
name: values.name,
|
|
1334
|
+
force: !!values.force,
|
|
1335
|
+
verbose: !!values.verbose,
|
|
1336
|
+
});
|
|
1337
|
+
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
|
|
1338
|
+
const rel = path.relative(targetPath, result.path);
|
|
1339
|
+
logger.success(`Wrote ${rel} — ${result.file.findings.length} findings, salt: ${result.file.saltMode} (${elapsed}s)`);
|
|
1340
|
+
}
|
|
1341
|
+
catch (err) {
|
|
1342
|
+
logger.fail(err.message);
|
|
1343
|
+
process.exit(1);
|
|
1344
|
+
}
|
|
1345
|
+
break;
|
|
1346
|
+
}
|
|
1347
|
+
if (subCommand === 'show') {
|
|
1348
|
+
const targetPath = resolveRepoPath(positionals[2]);
|
|
1349
|
+
const { DEFAULT_BASELINE_NAME, pathForBaseline, readBaselineFile } = await Promise.resolve().then(() => __importStar(require('./baseline/baseline-file')));
|
|
1350
|
+
const { parseKindFilter, renderSummary, renderKind, renderJson, FILTER_KINDS } = await Promise.resolve().then(() => __importStar(require('./baseline/show')));
|
|
1351
|
+
const name = values.name ?? DEFAULT_BASELINE_NAME;
|
|
1352
|
+
const filePath = values.baseline ?? pathForBaseline(targetPath, name);
|
|
1353
|
+
let file;
|
|
1354
|
+
try {
|
|
1355
|
+
file = readBaselineFile(filePath);
|
|
1356
|
+
}
|
|
1357
|
+
catch (err) {
|
|
1358
|
+
logger.fail(err.message);
|
|
1359
|
+
process.exit(1);
|
|
1360
|
+
}
|
|
1361
|
+
// Optional kind filter. Validated up-front so a typo surfaces
|
|
1362
|
+
// a clear error rather than a silently-empty result.
|
|
1363
|
+
let kindFilter;
|
|
1364
|
+
if (values.kind !== undefined) {
|
|
1365
|
+
const parsed = parseKindFilter(values.kind);
|
|
1366
|
+
if (parsed === null) {
|
|
1367
|
+
logger.fail(`--kind: unknown value "${values.kind}". Expected one of: ${FILTER_KINDS.join(', ')}.`);
|
|
1368
|
+
process.exit(1);
|
|
1369
|
+
}
|
|
1370
|
+
kindFilter = parsed;
|
|
1371
|
+
}
|
|
1372
|
+
if (values.json) {
|
|
1373
|
+
await emitJson(renderJson(file, kindFilter ? { kind: kindFilter } : {}));
|
|
1374
|
+
}
|
|
1375
|
+
else if (kindFilter) {
|
|
1376
|
+
process.stdout.write(renderKind(file, kindFilter) + '\n');
|
|
1377
|
+
}
|
|
1378
|
+
else {
|
|
1379
|
+
process.stdout.write(renderSummary(file) + '\n');
|
|
1380
|
+
}
|
|
1381
|
+
break;
|
|
1382
|
+
}
|
|
1383
|
+
logger.fail(`Unknown baseline subcommand: ${subCommand ?? '(missing)'}. ` +
|
|
1384
|
+
`Available: vyuh-dxkit baseline create [path] [--name <name>] [--force] · ` +
|
|
1385
|
+
`vyuh-dxkit baseline show [path] [--name <name>] [--baseline <path>] [--kind <kind>] [--json]`);
|
|
1386
|
+
process.exit(1);
|
|
1387
|
+
break;
|
|
1388
|
+
}
|
|
1389
|
+
case 'guardrail': {
|
|
1390
|
+
const subCommand = positionals[1];
|
|
1391
|
+
if (subCommand !== 'check') {
|
|
1392
|
+
logger.fail(`Unknown guardrail subcommand: ${subCommand ?? '(missing)'}. ` +
|
|
1393
|
+
`Available: vyuh-dxkit guardrail check [path] [--name <n>] [--baseline <path>] ` +
|
|
1394
|
+
`[--changed-only] [--policy <path>] [--json | --markdown]`);
|
|
1395
|
+
process.exit(1);
|
|
1396
|
+
}
|
|
1397
|
+
const targetPath = resolveRepoPath(positionals[2]);
|
|
1398
|
+
const { runGuardrailCheck } = await Promise.resolve().then(() => __importStar(require('./baseline/check')));
|
|
1399
|
+
const { renderConsole, renderJson, renderMarkdown } = await Promise.resolve().then(() => __importStar(require('./baseline/check-renderers')));
|
|
1400
|
+
if (!values.json)
|
|
1401
|
+
logger.header('vyuh-dxkit guardrail check');
|
|
1402
|
+
if (!values.json)
|
|
1403
|
+
logger.info(`Checking ${targetPath} against baseline...`);
|
|
1404
|
+
const startTime = Date.now();
|
|
1405
|
+
try {
|
|
1406
|
+
const result = await runGuardrailCheck({
|
|
1407
|
+
cwd: targetPath,
|
|
1408
|
+
name: values.name,
|
|
1409
|
+
baselinePath: values.baseline,
|
|
1410
|
+
changedOnly: !!values['changed-only'],
|
|
1411
|
+
policyPath: values.policy,
|
|
1412
|
+
verbose: !!values.verbose,
|
|
1413
|
+
});
|
|
1414
|
+
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
|
|
1415
|
+
if (values.json) {
|
|
1416
|
+
await emitJson(renderJson(result));
|
|
1417
|
+
}
|
|
1418
|
+
else if (values.markdown) {
|
|
1419
|
+
process.stdout.write(renderMarkdown(result) + '\n');
|
|
1420
|
+
}
|
|
1421
|
+
else {
|
|
1422
|
+
process.stdout.write(renderConsole(result) + '\n');
|
|
1423
|
+
logger.dim(`Completed in ${elapsed}s`);
|
|
1424
|
+
}
|
|
1425
|
+
process.exit(result.blocks ? 1 : 0);
|
|
1426
|
+
}
|
|
1427
|
+
catch (err) {
|
|
1428
|
+
logger.fail(err.message);
|
|
1429
|
+
process.exit(1);
|
|
1430
|
+
}
|
|
1431
|
+
break;
|
|
1432
|
+
}
|
|
1121
1433
|
default:
|
|
1122
1434
|
console.error(`Unknown command: ${command}`);
|
|
1123
1435
|
printUsage();
|
|
@@ -1184,7 +1496,9 @@ function formatMarkdownReport(report, elapsed) {
|
|
|
1184
1496
|
lines.push('');
|
|
1185
1497
|
lines.push('| Rank | File | Lines |');
|
|
1186
1498
|
lines.push('|-----:|------|------:|');
|
|
1187
|
-
|
|
1499
|
+
// Top 10 is the render contract — the underlying metric carries
|
|
1500
|
+
// every file over the threshold (consumed by the baseline producer).
|
|
1501
|
+
report.largestFiles.slice(0, 10).forEach((f, i) => {
|
|
1188
1502
|
lines.push(`| ${i + 1} | \`${f.path}\` | ${f.lines.toLocaleString()} |`);
|
|
1189
1503
|
});
|
|
1190
1504
|
lines.push('');
|
|
@@ -1196,7 +1510,9 @@ function formatMarkdownReport(report, elapsed) {
|
|
|
1196
1510
|
// etc.; the remaining cases (most commonly `/libs/`) live in
|
|
1197
1511
|
// customer-specific paths that can't be defaulted-away without
|
|
1198
1512
|
// false-positives on first-party monorepo layouts.
|
|
1199
|
-
|
|
1513
|
+
// Scope the vendored advisor to the rendered top 10 — the tip
|
|
1514
|
+
// calls out files the user can see in the table above.
|
|
1515
|
+
const suspects = (0, vendored_advisor_1.suspectVendoredEntries)(report.largestFiles.slice(0, 10));
|
|
1200
1516
|
if (suspects.length > 0) {
|
|
1201
1517
|
lines.push(`> **Tip — possibly vendored:** ${suspects
|
|
1202
1518
|
.map((s) => `\`${s.path}\``)
|