@kevinrabun/judges 3.105.0 → 3.106.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/CHANGELOG.md +13 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +63 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/finding-priority-rank.d.ts +2 -0
- package/dist/commands/finding-priority-rank.d.ts.map +1 -0
- package/dist/commands/finding-priority-rank.js +83 -0
- package/dist/commands/finding-priority-rank.js.map +1 -0
- package/dist/commands/finding-regression-detect.d.ts +2 -0
- package/dist/commands/finding-regression-detect.d.ts.map +1 -0
- package/dist/commands/finding-regression-detect.js +87 -0
- package/dist/commands/finding-regression-detect.js.map +1 -0
- package/dist/commands/finding-reopen-detect.d.ts +2 -0
- package/dist/commands/finding-reopen-detect.d.ts.map +1 -0
- package/dist/commands/finding-reopen-detect.js +78 -0
- package/dist/commands/finding-reopen-detect.js.map +1 -0
- package/dist/commands/review-dependency-review.d.ts +2 -0
- package/dist/commands/review-dependency-review.d.ts.map +1 -0
- package/dist/commands/review-dependency-review.js +105 -0
- package/dist/commands/review-dependency-review.js.map +1 -0
- package/dist/commands/review-knowledge-capture.d.ts +2 -0
- package/dist/commands/review-knowledge-capture.d.ts.map +1 -0
- package/dist/commands/review-knowledge-capture.js +95 -0
- package/dist/commands/review-knowledge-capture.js.map +1 -0
- package/dist/commands/review-merge-readiness.d.ts +2 -0
- package/dist/commands/review-merge-readiness.d.ts.map +1 -0
- package/dist/commands/review-merge-readiness.js +91 -0
- package/dist/commands/review-merge-readiness.js.map +1 -0
- package/dist/commands/review-onboarding-check.d.ts +2 -0
- package/dist/commands/review-onboarding-check.d.ts.map +1 -0
- package/dist/commands/review-onboarding-check.js +94 -0
- package/dist/commands/review-onboarding-check.js.map +1 -0
- package/dist/commands/review-quality-gate.d.ts +2 -0
- package/dist/commands/review-quality-gate.d.ts.map +1 -0
- package/dist/commands/review-quality-gate.js +87 -0
- package/dist/commands/review-quality-gate.js.map +1 -0
- package/dist/commands/review-security-posture.d.ts +2 -0
- package/dist/commands/review-security-posture.d.ts.map +1 -0
- package/dist/commands/review-security-posture.js +106 -0
- package/dist/commands/review-security-posture.js.map +1 -0
- package/package.json +1 -1
- package/server.json +2 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"finding-priority-rank.d.ts","sourceRoot":"","sources":["../../src/commands/finding-priority-rank.ts"],"names":[],"mappings":"AA0DA,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAuD3D"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { readFileSync, existsSync } from "fs";
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
const SEVERITY_WEIGHT = {
|
|
4
|
+
critical: 100,
|
|
5
|
+
high: 75,
|
|
6
|
+
medium: 50,
|
|
7
|
+
low: 25,
|
|
8
|
+
info: 10,
|
|
9
|
+
};
|
|
10
|
+
function rankFindings(findings) {
|
|
11
|
+
const scored = findings.map((f) => {
|
|
12
|
+
const sevWeight = SEVERITY_WEIGHT[f.severity] ?? 10;
|
|
13
|
+
const conf = f.confidence ?? 0.5;
|
|
14
|
+
const hasFix = f.patch !== undefined && f.patch !== null ? 15 : 0;
|
|
15
|
+
const priorityScore = Math.round(sevWeight * conf + hasFix);
|
|
16
|
+
let rationale = `${f.severity} severity`;
|
|
17
|
+
if (conf >= 0.8)
|
|
18
|
+
rationale += ", high confidence";
|
|
19
|
+
if (hasFix > 0)
|
|
20
|
+
rationale += ", fix available";
|
|
21
|
+
return {
|
|
22
|
+
rank: 0,
|
|
23
|
+
ruleId: f.ruleId,
|
|
24
|
+
title: f.title,
|
|
25
|
+
severity: f.severity,
|
|
26
|
+
confidence: Math.round(conf * 100),
|
|
27
|
+
priorityScore,
|
|
28
|
+
rationale,
|
|
29
|
+
};
|
|
30
|
+
});
|
|
31
|
+
scored.sort((a, b) => b.priorityScore - a.priorityScore);
|
|
32
|
+
for (let i = 0; i < scored.length; i++) {
|
|
33
|
+
scored[i].rank = i + 1;
|
|
34
|
+
}
|
|
35
|
+
return scored;
|
|
36
|
+
}
|
|
37
|
+
export function runFindingPriorityRank(argv) {
|
|
38
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
39
|
+
console.log(`Usage: judges finding-priority-rank [options]
|
|
40
|
+
|
|
41
|
+
Rank findings by actionable priority.
|
|
42
|
+
|
|
43
|
+
Options:
|
|
44
|
+
--report <path> Path to verdict JSON file
|
|
45
|
+
--top <n> Show top N findings (default: all)
|
|
46
|
+
--format <fmt> Output format: table (default) or json
|
|
47
|
+
-h, --help Show this help message`);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const formatIdx = argv.indexOf("--format");
|
|
51
|
+
const format = formatIdx !== -1 && argv[formatIdx + 1] ? argv[formatIdx + 1] : "table";
|
|
52
|
+
const reportIdx = argv.indexOf("--report");
|
|
53
|
+
const reportPath = reportIdx !== -1 && argv[reportIdx + 1]
|
|
54
|
+
? join(process.cwd(), argv[reportIdx + 1])
|
|
55
|
+
: join(process.cwd(), ".judges", "last-verdict.json");
|
|
56
|
+
const topIdx = argv.indexOf("--top");
|
|
57
|
+
const topN = topIdx !== -1 && argv[topIdx + 1] ? parseInt(argv[topIdx + 1], 10) : 0;
|
|
58
|
+
if (!existsSync(reportPath)) {
|
|
59
|
+
console.log(`No report found at: ${reportPath}`);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
const data = JSON.parse(readFileSync(reportPath, "utf-8"));
|
|
63
|
+
const findings = data.findings ?? [];
|
|
64
|
+
if (findings.length === 0) {
|
|
65
|
+
console.log("No findings to rank.");
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
let ranked = rankFindings(findings);
|
|
69
|
+
if (topN > 0) {
|
|
70
|
+
ranked = ranked.slice(0, topN);
|
|
71
|
+
}
|
|
72
|
+
if (format === "json") {
|
|
73
|
+
console.log(JSON.stringify(ranked, null, 2));
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
console.log("\n=== Finding Priority Ranking ===\n");
|
|
77
|
+
for (const r of ranked) {
|
|
78
|
+
console.log(`#${r.rank} [Score: ${r.priorityScore}] ${r.ruleId}: ${r.title}`);
|
|
79
|
+
console.log(` ${r.severity} | ${r.confidence}% confidence | ${r.rationale}`);
|
|
80
|
+
console.log();
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=finding-priority-rank.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"finding-priority-rank.js","sourceRoot":"","sources":["../../src/commands/finding-priority-rank.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"finding-regression-detect.d.ts","sourceRoot":"","sources":["../../src/commands/finding-regression-detect.ts"],"names":[],"mappings":"AAgDA,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAsE/D"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { readFileSync, existsSync } from "fs";
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
function detectRegressions(current, previous) {
|
|
4
|
+
const prevKeys = new Set(previous.map((f) => `${f.ruleId}::${f.title}`));
|
|
5
|
+
const currKeys = new Set(current.map((f) => `${f.ruleId}::${f.title}`));
|
|
6
|
+
const newFindings = [];
|
|
7
|
+
for (const f of current) {
|
|
8
|
+
const key = `${f.ruleId}::${f.title}`;
|
|
9
|
+
if (!prevKeys.has(key)) {
|
|
10
|
+
newFindings.push({ ruleId: f.ruleId, title: f.title, severity: f.severity });
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
const resolved = [];
|
|
14
|
+
for (const f of previous) {
|
|
15
|
+
const key = `${f.ruleId}::${f.title}`;
|
|
16
|
+
if (!currKeys.has(key)) {
|
|
17
|
+
resolved.push({ ruleId: f.ruleId, title: f.title, severity: f.severity });
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
const persisting = current.length - newFindings.length;
|
|
21
|
+
return {
|
|
22
|
+
newFindings,
|
|
23
|
+
resolvedFindings: resolved,
|
|
24
|
+
persistingFindings: persisting,
|
|
25
|
+
regressionCount: newFindings.length,
|
|
26
|
+
improvementCount: resolved.length,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
export function runFindingRegressionDetect(argv) {
|
|
30
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
31
|
+
console.log(`Usage: judges finding-regression-detect [options]
|
|
32
|
+
|
|
33
|
+
Detect regressions by comparing current and previous verdicts.
|
|
34
|
+
|
|
35
|
+
Options:
|
|
36
|
+
--report <path> Path to current verdict JSON
|
|
37
|
+
--previous <path> Path to previous verdict JSON
|
|
38
|
+
--format <fmt> Output format: table (default) or json
|
|
39
|
+
-h, --help Show this help message`);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const formatIdx = argv.indexOf("--format");
|
|
43
|
+
const format = formatIdx !== -1 && argv[formatIdx + 1] ? argv[formatIdx + 1] : "table";
|
|
44
|
+
const reportIdx = argv.indexOf("--report");
|
|
45
|
+
const reportPath = reportIdx !== -1 && argv[reportIdx + 1]
|
|
46
|
+
? join(process.cwd(), argv[reportIdx + 1])
|
|
47
|
+
: join(process.cwd(), ".judges", "last-verdict.json");
|
|
48
|
+
const prevIdx = argv.indexOf("--previous");
|
|
49
|
+
const prevPath = prevIdx !== -1 && argv[prevIdx + 1]
|
|
50
|
+
? join(process.cwd(), argv[prevIdx + 1])
|
|
51
|
+
: join(process.cwd(), ".judges", "previous-verdict.json");
|
|
52
|
+
if (!existsSync(reportPath)) {
|
|
53
|
+
console.log(`No current report found at: ${reportPath}`);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
if (!existsSync(prevPath)) {
|
|
57
|
+
console.log(`No previous report found at: ${prevPath}`);
|
|
58
|
+
console.log("Cannot detect regressions without a comparison baseline.");
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
const current = JSON.parse(readFileSync(reportPath, "utf-8"));
|
|
62
|
+
const previous = JSON.parse(readFileSync(prevPath, "utf-8"));
|
|
63
|
+
const result = detectRegressions(current.findings ?? [], previous.findings ?? []);
|
|
64
|
+
if (format === "json") {
|
|
65
|
+
console.log(JSON.stringify(result, null, 2));
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
console.log("\n=== Regression Analysis ===\n");
|
|
69
|
+
console.log(`New findings (regressions): ${result.regressionCount}`);
|
|
70
|
+
console.log(`Resolved findings (improvements): ${result.improvementCount}`);
|
|
71
|
+
console.log(`Persisting findings: ${result.persistingFindings}\n`);
|
|
72
|
+
if (result.newFindings.length > 0) {
|
|
73
|
+
console.log("Regressions:");
|
|
74
|
+
for (const f of result.newFindings) {
|
|
75
|
+
console.log(` [${f.severity.toUpperCase()}] ${f.ruleId}: ${f.title}`);
|
|
76
|
+
}
|
|
77
|
+
console.log();
|
|
78
|
+
}
|
|
79
|
+
if (result.resolvedFindings.length > 0) {
|
|
80
|
+
console.log("Resolved:");
|
|
81
|
+
for (const f of result.resolvedFindings) {
|
|
82
|
+
console.log(` [${f.severity.toUpperCase()}] ${f.ruleId}: ${f.title}`);
|
|
83
|
+
}
|
|
84
|
+
console.log();
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=finding-regression-detect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"finding-regression-detect.js","sourceRoot":"","sources":["../../src/commands/finding-regression-detect.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"finding-reopen-detect.d.ts","sourceRoot":"","sources":["../../src/commands/finding-reopen-detect.ts"],"names":[],"mappings":"AAgDA,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAkE3D"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { readFileSync, existsSync, writeFileSync } from "fs";
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
function detectReopened(findings, suppressions) {
|
|
4
|
+
const suppressionMap = new Map();
|
|
5
|
+
for (const s of suppressions) {
|
|
6
|
+
suppressionMap.set(`${s.ruleId}::${s.title}`, s);
|
|
7
|
+
}
|
|
8
|
+
const reopened = [];
|
|
9
|
+
for (const f of findings) {
|
|
10
|
+
const key = `${f.ruleId}::${f.title}`;
|
|
11
|
+
const match = suppressionMap.get(key);
|
|
12
|
+
if (match) {
|
|
13
|
+
reopened.push({
|
|
14
|
+
ruleId: f.ruleId,
|
|
15
|
+
title: f.title,
|
|
16
|
+
severity: f.severity,
|
|
17
|
+
suppressedAt: match.suppressedAt,
|
|
18
|
+
recommendation: "Previously resolved — investigate regression",
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return reopened;
|
|
23
|
+
}
|
|
24
|
+
export function runFindingReopenDetect(argv) {
|
|
25
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
26
|
+
console.log(`Usage: judges finding-reopen-detect [options]
|
|
27
|
+
|
|
28
|
+
Detect findings that reappear after suppression.
|
|
29
|
+
|
|
30
|
+
Options:
|
|
31
|
+
--report <path> Path to verdict JSON file
|
|
32
|
+
--suppressions <path> Path to suppressions ledger JSON
|
|
33
|
+
--format <fmt> Output format: table (default) or json
|
|
34
|
+
-h, --help Show this help message`);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
const formatIdx = argv.indexOf("--format");
|
|
38
|
+
const format = formatIdx !== -1 && argv[formatIdx + 1] ? argv[formatIdx + 1] : "table";
|
|
39
|
+
const reportIdx = argv.indexOf("--report");
|
|
40
|
+
const reportPath = reportIdx !== -1 && argv[reportIdx + 1]
|
|
41
|
+
? join(process.cwd(), argv[reportIdx + 1])
|
|
42
|
+
: join(process.cwd(), ".judges", "last-verdict.json");
|
|
43
|
+
const suppIdx = argv.indexOf("--suppressions");
|
|
44
|
+
const suppPath = suppIdx !== -1 && argv[suppIdx + 1]
|
|
45
|
+
? join(process.cwd(), argv[suppIdx + 1])
|
|
46
|
+
: join(process.cwd(), ".judges", "suppressions.json");
|
|
47
|
+
if (!existsSync(reportPath)) {
|
|
48
|
+
console.log(`No report found at: ${reportPath}`);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
if (!existsSync(suppPath)) {
|
|
52
|
+
console.log("No suppressions ledger found. Creating template...");
|
|
53
|
+
writeFileSync(suppPath, JSON.stringify({ suppressions: [] }, null, 2), "utf-8");
|
|
54
|
+
console.log(`Created: ${suppPath}`);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const data = JSON.parse(readFileSync(reportPath, "utf-8"));
|
|
58
|
+
const findings = data.findings ?? [];
|
|
59
|
+
const suppData = JSON.parse(readFileSync(suppPath, "utf-8"));
|
|
60
|
+
const suppressions = suppData.suppressions ?? [];
|
|
61
|
+
const reopened = detectReopened(findings, suppressions);
|
|
62
|
+
if (format === "json") {
|
|
63
|
+
console.log(JSON.stringify(reopened, null, 2));
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (reopened.length === 0) {
|
|
67
|
+
console.log("\nNo reopened findings detected.");
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
console.log(`\n=== Reopened Findings (${reopened.length}) ===\n`);
|
|
71
|
+
for (const r of reopened) {
|
|
72
|
+
console.log(`[${r.severity.toUpperCase()}] ${r.ruleId}: ${r.title}`);
|
|
73
|
+
console.log(` Suppressed: ${r.suppressedAt}`);
|
|
74
|
+
console.log(` → ${r.recommendation}`);
|
|
75
|
+
console.log();
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=finding-reopen-detect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"finding-reopen-detect.js","sourceRoot":"","sources":["../../src/commands/finding-reopen-detect.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review-dependency-review.d.ts","sourceRoot":"","sources":["../../src/commands/review-dependency-review.ts"],"names":[],"mappings":"AAiFA,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CA2D9D"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { readFileSync, existsSync } from "fs";
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
const DEP_KEYWORDS = [
|
|
4
|
+
"dependency",
|
|
5
|
+
"dep",
|
|
6
|
+
"import",
|
|
7
|
+
"require",
|
|
8
|
+
"package",
|
|
9
|
+
"module",
|
|
10
|
+
"library",
|
|
11
|
+
"npm",
|
|
12
|
+
"version",
|
|
13
|
+
"outdated",
|
|
14
|
+
"vulnerable",
|
|
15
|
+
"supply-chain",
|
|
16
|
+
];
|
|
17
|
+
function isDependencyRelated(f) {
|
|
18
|
+
const lower = `${f.ruleId} ${f.title} ${f.description}`.toLowerCase();
|
|
19
|
+
return DEP_KEYWORDS.some((kw) => lower.includes(kw));
|
|
20
|
+
}
|
|
21
|
+
function categorizeDep(f) {
|
|
22
|
+
const lower = `${f.ruleId} ${f.title} ${f.description}`.toLowerCase();
|
|
23
|
+
if (lower.includes("vulnerable") || lower.includes("cve"))
|
|
24
|
+
return "vulnerability";
|
|
25
|
+
if (lower.includes("outdated") || lower.includes("version"))
|
|
26
|
+
return "outdated";
|
|
27
|
+
if (lower.includes("supply-chain") || lower.includes("integrity"))
|
|
28
|
+
return "supply-chain";
|
|
29
|
+
if (lower.includes("unused") || lower.includes("dead"))
|
|
30
|
+
return "unused";
|
|
31
|
+
return "general";
|
|
32
|
+
}
|
|
33
|
+
function analyzeDependencies(findings) {
|
|
34
|
+
const depFindings = findings.filter(isDependencyRelated);
|
|
35
|
+
const bySeverity = {};
|
|
36
|
+
const byCategory = {};
|
|
37
|
+
const risks = [];
|
|
38
|
+
for (const f of depFindings) {
|
|
39
|
+
bySeverity[f.severity] = (bySeverity[f.severity] ?? 0) + 1;
|
|
40
|
+
const cat = categorizeDep(f);
|
|
41
|
+
byCategory[cat] = (byCategory[cat] ?? 0) + 1;
|
|
42
|
+
risks.push({
|
|
43
|
+
ruleId: f.ruleId,
|
|
44
|
+
title: f.title,
|
|
45
|
+
severity: f.severity,
|
|
46
|
+
category: cat,
|
|
47
|
+
recommendation: f.recommendation,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
totalDependencyFindings: depFindings.length,
|
|
52
|
+
bySeverity,
|
|
53
|
+
byCategory,
|
|
54
|
+
risks,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
export function runReviewDependencyReview(argv) {
|
|
58
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
59
|
+
console.log(`Usage: judges review-dependency-review [options]
|
|
60
|
+
|
|
61
|
+
Review dependency-related findings and risks.
|
|
62
|
+
|
|
63
|
+
Options:
|
|
64
|
+
--report <path> Path to verdict JSON file
|
|
65
|
+
--format <fmt> Output format: table (default) or json
|
|
66
|
+
-h, --help Show this help message`);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
const formatIdx = argv.indexOf("--format");
|
|
70
|
+
const format = formatIdx !== -1 && argv[formatIdx + 1] ? argv[formatIdx + 1] : "table";
|
|
71
|
+
const reportIdx = argv.indexOf("--report");
|
|
72
|
+
const reportPath = reportIdx !== -1 && argv[reportIdx + 1]
|
|
73
|
+
? join(process.cwd(), argv[reportIdx + 1])
|
|
74
|
+
: join(process.cwd(), ".judges", "last-verdict.json");
|
|
75
|
+
if (!existsSync(reportPath)) {
|
|
76
|
+
console.log(`No report found at: ${reportPath}`);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
const data = JSON.parse(readFileSync(reportPath, "utf-8"));
|
|
80
|
+
const findings = data.findings ?? [];
|
|
81
|
+
const summary = analyzeDependencies(findings);
|
|
82
|
+
if (format === "json") {
|
|
83
|
+
console.log(JSON.stringify(summary, null, 2));
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
console.log("\n=== Dependency Review ===\n");
|
|
87
|
+
console.log(`Dependency findings: ${summary.totalDependencyFindings} of ${findings.length} total\n`);
|
|
88
|
+
if (summary.totalDependencyFindings === 0) {
|
|
89
|
+
console.log("No dependency-related findings detected.");
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
console.log("By severity:");
|
|
93
|
+
for (const [sev, count] of Object.entries(summary.bySeverity)) {
|
|
94
|
+
console.log(` ${sev}: ${count}`);
|
|
95
|
+
}
|
|
96
|
+
console.log("\nBy category:");
|
|
97
|
+
for (const [cat, count] of Object.entries(summary.byCategory)) {
|
|
98
|
+
console.log(` ${cat}: ${count}`);
|
|
99
|
+
}
|
|
100
|
+
console.log("\nRisks:");
|
|
101
|
+
for (const r of summary.risks) {
|
|
102
|
+
console.log(` [${r.severity.toUpperCase()}] ${r.ruleId}: ${r.title} (${r.category})`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=review-dependency-review.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review-dependency-review.js","sourceRoot":"","sources":["../../src/commands/review-dependency-review.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review-knowledge-capture.d.ts","sourceRoot":"","sources":["../../src/commands/review-knowledge-capture.ts"],"names":[],"mappings":"AAgEA,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAkE9D"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { readFileSync, existsSync, writeFileSync, mkdirSync } from "fs";
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
function extractPatterns(findings) {
|
|
4
|
+
const groups = new Map();
|
|
5
|
+
for (const f of findings) {
|
|
6
|
+
const key = f.ruleId;
|
|
7
|
+
const list = groups.get(key) ?? [];
|
|
8
|
+
list.push(f);
|
|
9
|
+
groups.set(key, list);
|
|
10
|
+
}
|
|
11
|
+
return groups;
|
|
12
|
+
}
|
|
13
|
+
function mergeKnowledge(existing, findings) {
|
|
14
|
+
const patterns = extractPatterns(findings);
|
|
15
|
+
const entryMap = new Map();
|
|
16
|
+
for (const e of existing.entries) {
|
|
17
|
+
entryMap.set(e.ruleId, e);
|
|
18
|
+
}
|
|
19
|
+
for (const [ruleId, group] of patterns) {
|
|
20
|
+
const existing_ = entryMap.get(ruleId);
|
|
21
|
+
if (existing_) {
|
|
22
|
+
existing_.occurrences += group.length;
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
const sample = group[0];
|
|
26
|
+
entryMap.set(ruleId, {
|
|
27
|
+
ruleId,
|
|
28
|
+
pattern: sample.title,
|
|
29
|
+
lesson: sample.recommendation,
|
|
30
|
+
severity: sample.severity,
|
|
31
|
+
capturedAt: new Date().toISOString().slice(0, 10),
|
|
32
|
+
occurrences: group.length,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
const entries = Array.from(entryMap.values());
|
|
37
|
+
entries.sort((a, b) => b.occurrences - a.occurrences);
|
|
38
|
+
return { entries };
|
|
39
|
+
}
|
|
40
|
+
export function runReviewKnowledgeCapture(argv) {
|
|
41
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
42
|
+
console.log(`Usage: judges review-knowledge-capture [options]
|
|
43
|
+
|
|
44
|
+
Capture recurring patterns and lessons from findings.
|
|
45
|
+
|
|
46
|
+
Options:
|
|
47
|
+
--report <path> Path to verdict JSON file
|
|
48
|
+
--kb <path> Path to knowledge base file
|
|
49
|
+
--format <fmt> Output format: table (default) or json
|
|
50
|
+
-h, --help Show this help message`);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
const formatIdx = argv.indexOf("--format");
|
|
54
|
+
const format = formatIdx !== -1 && argv[formatIdx + 1] ? argv[formatIdx + 1] : "table";
|
|
55
|
+
const reportIdx = argv.indexOf("--report");
|
|
56
|
+
const reportPath = reportIdx !== -1 && argv[reportIdx + 1]
|
|
57
|
+
? join(process.cwd(), argv[reportIdx + 1])
|
|
58
|
+
: join(process.cwd(), ".judges", "last-verdict.json");
|
|
59
|
+
const kbIdx = argv.indexOf("--kb");
|
|
60
|
+
const kbPath = kbIdx !== -1 && argv[kbIdx + 1]
|
|
61
|
+
? join(process.cwd(), argv[kbIdx + 1])
|
|
62
|
+
: join(process.cwd(), ".judges", "knowledge-base.json");
|
|
63
|
+
if (!existsSync(reportPath)) {
|
|
64
|
+
console.log(`No report found at: ${reportPath}`);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
const data = JSON.parse(readFileSync(reportPath, "utf-8"));
|
|
68
|
+
const findings = data.findings ?? [];
|
|
69
|
+
if (findings.length === 0) {
|
|
70
|
+
console.log("No findings to capture.");
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
let existing = { entries: [] };
|
|
74
|
+
if (existsSync(kbPath)) {
|
|
75
|
+
existing = JSON.parse(readFileSync(kbPath, "utf-8"));
|
|
76
|
+
}
|
|
77
|
+
const updated = mergeKnowledge(existing, findings);
|
|
78
|
+
const kbDir = join(kbPath, "..");
|
|
79
|
+
if (!existsSync(kbDir)) {
|
|
80
|
+
mkdirSync(kbDir, { recursive: true });
|
|
81
|
+
}
|
|
82
|
+
writeFileSync(kbPath, JSON.stringify(updated, null, 2), "utf-8");
|
|
83
|
+
if (format === "json") {
|
|
84
|
+
console.log(JSON.stringify(updated, null, 2));
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
console.log(`\n=== Knowledge Base (${updated.entries.length} patterns) ===\n`);
|
|
88
|
+
for (const e of updated.entries) {
|
|
89
|
+
console.log(`${e.ruleId} (${e.occurrences}x) — ${e.pattern}`);
|
|
90
|
+
console.log(` Lesson: ${e.lesson}`);
|
|
91
|
+
console.log();
|
|
92
|
+
}
|
|
93
|
+
console.log(`Saved to: ${kbPath}`);
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=review-knowledge-capture.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review-knowledge-capture.js","sourceRoot":"","sources":["../../src/commands/review-knowledge-capture.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review-merge-readiness.d.ts","sourceRoot":"","sources":["../../src/commands/review-merge-readiness.ts"],"names":[],"mappings":"AAsEA,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CA4D5D"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { readFileSync, existsSync } from "fs";
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
function evaluateReadiness(data, criteria) {
|
|
4
|
+
const checks = [];
|
|
5
|
+
if (criteria.requirePassVerdict) {
|
|
6
|
+
const passed = data.overallVerdict === "pass";
|
|
7
|
+
checks.push({
|
|
8
|
+
check: "Verdict is pass",
|
|
9
|
+
passed,
|
|
10
|
+
detail: `Verdict: ${data.overallVerdict}`,
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
const critOk = data.criticalCount <= criteria.maxCritical;
|
|
14
|
+
checks.push({
|
|
15
|
+
check: `Critical findings ≤ ${criteria.maxCritical}`,
|
|
16
|
+
passed: critOk,
|
|
17
|
+
detail: `Found: ${data.criticalCount}`,
|
|
18
|
+
});
|
|
19
|
+
const highOk = data.highCount <= criteria.maxHigh;
|
|
20
|
+
checks.push({
|
|
21
|
+
check: `High findings ≤ ${criteria.maxHigh}`,
|
|
22
|
+
passed: highOk,
|
|
23
|
+
detail: `Found: ${data.highCount}`,
|
|
24
|
+
});
|
|
25
|
+
const scoreOk = data.overallScore >= criteria.minScore;
|
|
26
|
+
checks.push({
|
|
27
|
+
check: `Score ≥ ${criteria.minScore}`,
|
|
28
|
+
passed: scoreOk,
|
|
29
|
+
detail: `Score: ${data.overallScore}`,
|
|
30
|
+
});
|
|
31
|
+
const ready = checks.every((c) => c.passed);
|
|
32
|
+
return {
|
|
33
|
+
ready,
|
|
34
|
+
verdict: data.overallVerdict,
|
|
35
|
+
score: data.overallScore,
|
|
36
|
+
criticalCount: data.criticalCount,
|
|
37
|
+
highCount: data.highCount,
|
|
38
|
+
checks,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
export function runReviewMergeReadiness(argv) {
|
|
42
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
43
|
+
console.log(`Usage: judges review-merge-readiness [options]
|
|
44
|
+
|
|
45
|
+
Evaluate merge readiness of a review.
|
|
46
|
+
|
|
47
|
+
Options:
|
|
48
|
+
--report <path> Path to verdict JSON file
|
|
49
|
+
--criteria <path> Path to merge criteria JSON
|
|
50
|
+
--format <fmt> Output format: table (default) or json
|
|
51
|
+
-h, --help Show this help message`);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
const formatIdx = argv.indexOf("--format");
|
|
55
|
+
const format = formatIdx !== -1 && argv[formatIdx + 1] ? argv[formatIdx + 1] : "table";
|
|
56
|
+
const reportIdx = argv.indexOf("--report");
|
|
57
|
+
const reportPath = reportIdx !== -1 && argv[reportIdx + 1]
|
|
58
|
+
? join(process.cwd(), argv[reportIdx + 1])
|
|
59
|
+
: join(process.cwd(), ".judges", "last-verdict.json");
|
|
60
|
+
const critIdx = argv.indexOf("--criteria");
|
|
61
|
+
const critPath = critIdx !== -1 && argv[critIdx + 1]
|
|
62
|
+
? join(process.cwd(), argv[critIdx + 1])
|
|
63
|
+
: join(process.cwd(), ".judges", "merge-criteria.json");
|
|
64
|
+
if (!existsSync(reportPath)) {
|
|
65
|
+
console.log(`No report found at: ${reportPath}`);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
const data = JSON.parse(readFileSync(reportPath, "utf-8"));
|
|
69
|
+
let criteria;
|
|
70
|
+
if (existsSync(critPath)) {
|
|
71
|
+
criteria = JSON.parse(readFileSync(critPath, "utf-8"));
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
criteria = { requirePassVerdict: true, maxCritical: 0, maxHigh: 2, minScore: 70 };
|
|
75
|
+
}
|
|
76
|
+
const result = evaluateReadiness(data, criteria);
|
|
77
|
+
if (format === "json") {
|
|
78
|
+
console.log(JSON.stringify(result, null, 2));
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
const status = result.ready ? "READY TO MERGE" : "NOT READY";
|
|
82
|
+
console.log(`\n=== Merge Readiness: ${status} ===\n`);
|
|
83
|
+
console.log(`Verdict: ${result.verdict} | Score: ${result.score}`);
|
|
84
|
+
console.log(`Critical: ${result.criticalCount} | High: ${result.highCount}\n`);
|
|
85
|
+
for (const c of result.checks) {
|
|
86
|
+
const icon = c.passed ? "PASS" : "FAIL";
|
|
87
|
+
console.log(` [${icon}] ${c.check} — ${c.detail}`);
|
|
88
|
+
}
|
|
89
|
+
console.log();
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=review-merge-readiness.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review-merge-readiness.js","sourceRoot":"","sources":["../../src/commands/review-merge-readiness.ts"],"names":[],"mappings":"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"}
|