@kevinrabun/judges 3.98.0 → 3.100.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.
Files changed (78) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/dist/cli.d.ts.map +1 -1
  3. package/dist/cli.js +126 -0
  4. package/dist/cli.js.map +1 -1
  5. package/dist/commands/finding-auto-suppress.d.ts +5 -0
  6. package/dist/commands/finding-auto-suppress.d.ts.map +1 -0
  7. package/dist/commands/finding-auto-suppress.js +127 -0
  8. package/dist/commands/finding-auto-suppress.js.map +1 -0
  9. package/dist/commands/finding-auto-triage.d.ts +5 -0
  10. package/dist/commands/finding-auto-triage.d.ts.map +1 -0
  11. package/dist/commands/finding-auto-triage.js +109 -0
  12. package/dist/commands/finding-auto-triage.js.map +1 -0
  13. package/dist/commands/finding-change-impact.d.ts +5 -0
  14. package/dist/commands/finding-change-impact.d.ts.map +1 -0
  15. package/dist/commands/finding-change-impact.js +108 -0
  16. package/dist/commands/finding-change-impact.js.map +1 -0
  17. package/dist/commands/finding-context-enrich.d.ts +5 -0
  18. package/dist/commands/finding-context-enrich.d.ts.map +1 -0
  19. package/dist/commands/finding-context-enrich.js +90 -0
  20. package/dist/commands/finding-context-enrich.js.map +1 -0
  21. package/dist/commands/finding-dismiss-workflow.d.ts +5 -0
  22. package/dist/commands/finding-dismiss-workflow.d.ts.map +1 -0
  23. package/dist/commands/finding-dismiss-workflow.js +120 -0
  24. package/dist/commands/finding-dismiss-workflow.js.map +1 -0
  25. package/dist/commands/finding-false-positive-learn.d.ts +5 -0
  26. package/dist/commands/finding-false-positive-learn.d.ts.map +1 -0
  27. package/dist/commands/finding-false-positive-learn.js +86 -0
  28. package/dist/commands/finding-false-positive-learn.js.map +1 -0
  29. package/dist/commands/finding-reachability-check.d.ts +5 -0
  30. package/dist/commands/finding-reachability-check.d.ts.map +1 -0
  31. package/dist/commands/finding-reachability-check.js +103 -0
  32. package/dist/commands/finding-reachability-check.js.map +1 -0
  33. package/dist/commands/review-audit-export.d.ts +5 -0
  34. package/dist/commands/review-audit-export.d.ts.map +1 -0
  35. package/dist/commands/review-audit-export.js +94 -0
  36. package/dist/commands/review-audit-export.js.map +1 -0
  37. package/dist/commands/review-data-retention.d.ts +5 -0
  38. package/dist/commands/review-data-retention.d.ts.map +1 -0
  39. package/dist/commands/review-data-retention.js +120 -0
  40. package/dist/commands/review-data-retention.js.map +1 -0
  41. package/dist/commands/review-deployment-gate.d.ts +5 -0
  42. package/dist/commands/review-deployment-gate.d.ts.map +1 -0
  43. package/dist/commands/review-deployment-gate.js +95 -0
  44. package/dist/commands/review-deployment-gate.js.map +1 -0
  45. package/dist/commands/review-environment-config.d.ts +5 -0
  46. package/dist/commands/review-environment-config.d.ts.map +1 -0
  47. package/dist/commands/review-environment-config.js +103 -0
  48. package/dist/commands/review-environment-config.js.map +1 -0
  49. package/dist/commands/review-multi-repo-sync.d.ts +5 -0
  50. package/dist/commands/review-multi-repo-sync.d.ts.map +1 -0
  51. package/dist/commands/review-multi-repo-sync.js +116 -0
  52. package/dist/commands/review-multi-repo-sync.js.map +1 -0
  53. package/dist/commands/review-permission-model.d.ts +5 -0
  54. package/dist/commands/review-permission-model.d.ts.map +1 -0
  55. package/dist/commands/review-permission-model.js +150 -0
  56. package/dist/commands/review-permission-model.js.map +1 -0
  57. package/dist/commands/review-pipeline-status.d.ts +5 -0
  58. package/dist/commands/review-pipeline-status.d.ts.map +1 -0
  59. package/dist/commands/review-pipeline-status.js +55 -0
  60. package/dist/commands/review-pipeline-status.js.map +1 -0
  61. package/dist/commands/review-repo-onboard.d.ts +5 -0
  62. package/dist/commands/review-repo-onboard.d.ts.map +1 -0
  63. package/dist/commands/review-repo-onboard.js +115 -0
  64. package/dist/commands/review-repo-onboard.js.map +1 -0
  65. package/dist/commands/review-review-comments.d.ts +5 -0
  66. package/dist/commands/review-review-comments.d.ts.map +1 -0
  67. package/dist/commands/review-review-comments.js +85 -0
  68. package/dist/commands/review-review-comments.js.map +1 -0
  69. package/dist/commands/review-session-replay.d.ts +5 -0
  70. package/dist/commands/review-session-replay.d.ts.map +1 -0
  71. package/dist/commands/review-session-replay.js +82 -0
  72. package/dist/commands/review-session-replay.js.map +1 -0
  73. package/dist/commands/review-stakeholder-report.d.ts +5 -0
  74. package/dist/commands/review-stakeholder-report.d.ts.map +1 -0
  75. package/dist/commands/review-stakeholder-report.js +76 -0
  76. package/dist/commands/review-stakeholder-report.js.map +1 -0
  77. package/package.json +1 -1
  78. package/server.json +2 -2
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Finding-auto-suppress — Automatically suppress findings matching criteria.
3
+ */
4
+ export declare function runFindingAutoSuppress(argv: string[]): void;
5
+ //# sourceMappingURL=finding-auto-suppress.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"finding-auto-suppress.d.ts","sourceRoot":"","sources":["../../src/commands/finding-auto-suppress.ts"],"names":[],"mappings":"AAAA;;GAEG;AAsBH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAqI3D"}
@@ -0,0 +1,127 @@
1
+ /**
2
+ * Finding-auto-suppress — Automatically suppress findings matching criteria.
3
+ */
4
+ import { readFileSync, writeFileSync, existsSync } from "fs";
5
+ // ─── CLI ────────────────────────────────────────────────────────────────────
6
+ export function runFindingAutoSuppress(argv) {
7
+ const storeIdx = argv.indexOf("--store");
8
+ const storePath = storeIdx >= 0 ? argv[storeIdx + 1] : ".judges-suppressions.json";
9
+ const formatIdx = argv.indexOf("--format");
10
+ const format = formatIdx >= 0 ? argv[formatIdx + 1] : "table";
11
+ if (argv.includes("--help") || argv.includes("-h")) {
12
+ console.log(`
13
+ judges finding-auto-suppress — Automatically suppress findings
14
+
15
+ Usage:
16
+ judges finding-auto-suppress [--store <path>]
17
+ [--add-rule <id> --field <f> --pattern <p> --reason <reason>]
18
+ [--remove-rule <id>] [--apply <report> --out <path>]
19
+ [--format table|json]
20
+
21
+ Options:
22
+ --store <path> Suppression store (default: .judges-suppressions.json)
23
+ --add-rule <id> Add suppression rule
24
+ --field <f> Match field: ruleId, severity, title
25
+ --pattern <p> Match pattern (substring)
26
+ --reason <reason> Suppression reason
27
+ --remove-rule <id> Remove rule by id
28
+ --apply <report> Apply suppressions to report, output filtered findings
29
+ --out <path> Write filtered report to file
30
+ --format <fmt> Output format: table (default), json
31
+ --help, -h Show this help
32
+ `);
33
+ return;
34
+ }
35
+ let store;
36
+ if (existsSync(storePath)) {
37
+ store = JSON.parse(readFileSync(storePath, "utf-8"));
38
+ }
39
+ else {
40
+ store = { rules: [], lastUpdated: new Date().toISOString().split("T")[0] };
41
+ }
42
+ // Add rule
43
+ const addIdx = argv.indexOf("--add-rule");
44
+ if (addIdx >= 0) {
45
+ const id = argv[addIdx + 1];
46
+ const fieldIdx = argv.indexOf("--field");
47
+ const patternIdx = argv.indexOf("--pattern");
48
+ const reasonIdx = argv.indexOf("--reason");
49
+ const rule = {
50
+ id,
51
+ field: (fieldIdx >= 0 ? argv[fieldIdx + 1] : "ruleId"),
52
+ pattern: patternIdx >= 0 ? argv[patternIdx + 1] : "",
53
+ reason: reasonIdx >= 0 ? argv[reasonIdx + 1] : "",
54
+ createdAt: new Date().toISOString().split("T")[0],
55
+ };
56
+ const existingIdx = store.rules.findIndex((r) => r.id === id);
57
+ if (existingIdx >= 0) {
58
+ store.rules[existingIdx] = rule;
59
+ }
60
+ else {
61
+ store.rules.push(rule);
62
+ }
63
+ store.lastUpdated = new Date().toISOString().split("T")[0];
64
+ writeFileSync(storePath, JSON.stringify(store, null, 2));
65
+ console.log(`Suppression rule "${id}" saved.`);
66
+ return;
67
+ }
68
+ // Remove rule
69
+ const removeIdx = argv.indexOf("--remove-rule");
70
+ if (removeIdx >= 0) {
71
+ const id = argv[removeIdx + 1];
72
+ store.rules = store.rules.filter((r) => r.id !== id);
73
+ store.lastUpdated = new Date().toISOString().split("T")[0];
74
+ writeFileSync(storePath, JSON.stringify(store, null, 2));
75
+ console.log(`Rule "${id}" removed.`);
76
+ return;
77
+ }
78
+ // Apply suppressions to report
79
+ const applyIdx = argv.indexOf("--apply");
80
+ if (applyIdx >= 0) {
81
+ const reportPath = argv[applyIdx + 1];
82
+ if (!existsSync(reportPath)) {
83
+ console.error(`Report not found: ${reportPath}`);
84
+ process.exitCode = 1;
85
+ return;
86
+ }
87
+ const report = JSON.parse(readFileSync(reportPath, "utf-8"));
88
+ const findings = report.findings ?? [];
89
+ let suppressed = 0;
90
+ const filtered = findings.filter((f) => {
91
+ for (const rule of store.rules) {
92
+ const fieldValue = String(f[rule.field] ?? "");
93
+ if (fieldValue.includes(rule.pattern)) {
94
+ suppressed++;
95
+ return false;
96
+ }
97
+ }
98
+ return true;
99
+ });
100
+ const outIdx = argv.indexOf("--out");
101
+ if (outIdx >= 0) {
102
+ const outPath = argv[outIdx + 1];
103
+ writeFileSync(outPath, JSON.stringify({ ...report, findings: filtered }, null, 2));
104
+ console.log(`Filtered report written to: ${outPath}`);
105
+ }
106
+ console.log(`Suppressed: ${suppressed} | Remaining: ${filtered.length} | Total: ${findings.length}`);
107
+ return;
108
+ }
109
+ // List rules
110
+ if (format === "json") {
111
+ console.log(JSON.stringify(store, null, 2));
112
+ return;
113
+ }
114
+ console.log(`\nSuppression Rules`);
115
+ console.log("═".repeat(65));
116
+ if (store.rules.length === 0) {
117
+ console.log(" No suppression rules. Use --add-rule to create one.");
118
+ }
119
+ else {
120
+ for (const r of store.rules) {
121
+ console.log(` ${r.id.padEnd(20)} ${r.field}:${r.pattern}`);
122
+ console.log(` Reason: ${r.reason} (${r.createdAt})`);
123
+ }
124
+ }
125
+ console.log("═".repeat(65));
126
+ }
127
+ //# sourceMappingURL=finding-auto-suppress.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"finding-auto-suppress.js","sourceRoot":"","sources":["../../src/commands/finding-auto-suppress.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAkB7D,+EAA+E;AAE/E,MAAM,UAAU,sBAAsB,CAAC,IAAc;IACnD,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACzC,MAAM,SAAS,GAAG,QAAQ,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,2BAA2B,CAAC;IACnF,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAC3C,MAAM,MAAM,GAAG,SAAS,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;IAE9D,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACnD,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;CAoBf,CAAC,CAAC;QACC,OAAO;IACT,CAAC;IAED,IAAI,KAAuB,CAAC;IAC5B,IAAI,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC1B,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAAqB,CAAC;IAC3E,CAAC;SAAM,CAAC;QACN,KAAK,GAAG,EAAE,KAAK,EAAE,EAAE,EAAE,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC7E,CAAC;IAED,WAAW;IACX,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IAC1C,IAAI,MAAM,IAAI,CAAC,EAAE,CAAC;QAChB,MAAM,EAAE,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAC5B,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QACzC,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;QAC7C,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QAE3C,MAAM,IAAI,GAAoB;YAC5B,EAAE;YACF,KAAK,EAAE,CAAC,QAAQ,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAA6B;YAClF,OAAO,EAAE,UAAU,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;YACpD,MAAM,EAAE,SAAS,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;YACjD,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;SAClD,CAAC;QAEF,MAAM,WAAW,GAAG,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QAC9D,IAAI,WAAW,IAAI,CAAC,EAAE,CAAC;YACrB,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,IAAI,CAAC;QAClC,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACzB,CAAC;QAED,KAAK,CAAC,WAAW,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAC3D,aAAa,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QACzD,OAAO,CAAC,GAAG,CAAC,qBAAqB,EAAE,UAAU,CAAC,CAAC;QAC/C,OAAO;IACT,CAAC;IAED,cAAc;IACd,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;IAChD,IAAI,SAAS,IAAI,CAAC,EAAE,CAAC;QACnB,MAAM,EAAE,GAAG,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC;QAC/B,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QACrD,KAAK,CAAC,WAAW,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAC3D,aAAa,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QACzD,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;QACrC,OAAO;IACT,CAAC;IAED,+BAA+B;IAC/B,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACzC,IAAI,QAAQ,IAAI,CAAC,EAAE,CAAC;QAClB,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC;QACtC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAC5B,OAAO,CAAC,KAAK,CAAC,qBAAqB,UAAU,EAAE,CAAC,CAAC;YACjD,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;YACrB,OAAO;QACT,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAA6B,CAAC;QACzF,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,IAAI,EAAE,CAAC;QACvC,IAAI,UAAU,GAAG,CAAC,CAAC;QAEnB,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE;YACrC,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;gBAC/B,MAAM,UAAU,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAsB,CAAC,IAAI,EAAE,CAAC,CAAC;gBAChE,IAAI,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;oBACtC,UAAU,EAAE,CAAC;oBACb,OAAO,KAAK,CAAC;gBACf,CAAC;YACH,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACrC,IAAI,MAAM,IAAI,CAAC,EAAE,CAAC;YAChB,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;YACjC,aAAa,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;YACnF,OAAO,CAAC,GAAG,CAAC,+BAA+B,OAAO,EAAE,CAAC,CAAC;QACxD,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,eAAe,UAAU,iBAAiB,QAAQ,CAAC,MAAM,aAAa,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;QACrG,OAAO;IACT,CAAC;IAED,aAAa;IACb,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;QACtB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAC5C,OAAO;IACT,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;IACnC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;IAE5B,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC7B,OAAO,CAAC,GAAG,CAAC,uDAAuD,CAAC,CAAC;IACvE,CAAC;SAAM,CAAC;QACN,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;YAC5B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;YAC5D,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC;QAC1D,CAAC;IACH,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;AAC9B,CAAC"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Finding-auto-triage — Automatically triage findings by severity, confidence, and context.
3
+ */
4
+ export declare function runFindingAutoTriage(argv: string[]): void;
5
+ //# sourceMappingURL=finding-auto-triage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"finding-auto-triage.d.ts","sourceRoot":"","sources":["../../src/commands/finding-auto-triage.ts"],"names":[],"mappings":"AAAA;;GAEG;AA+DH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CA6EzD"}
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Finding-auto-triage — Automatically triage findings by severity, confidence, and context.
3
+ */
4
+ import { readFileSync, writeFileSync, existsSync } from "fs";
5
+ // ─── Helpers ────────────────────────────────────────────────────────────────
6
+ function matchesRule(finding, rule) {
7
+ if (rule.field === "severity") {
8
+ if (rule.operator === "eq")
9
+ return finding.severity === rule.value;
10
+ }
11
+ if (rule.field === "ruleId") {
12
+ if (rule.operator === "eq")
13
+ return finding.ruleId === rule.value;
14
+ if (rule.operator === "contains")
15
+ return finding.ruleId.includes(String(rule.value));
16
+ }
17
+ if (rule.field === "confidence") {
18
+ const conf = finding.confidence ?? 0;
19
+ if (rule.operator === "gte")
20
+ return conf >= Number(rule.value);
21
+ if (rule.operator === "lte")
22
+ return conf <= Number(rule.value);
23
+ }
24
+ return false;
25
+ }
26
+ function triageFindings(findings, config) {
27
+ const sorted = [...config.rules].sort((a, b) => b.priority - a.priority);
28
+ return findings.map((f) => {
29
+ const matched = sorted.find((r) => matchesRule(f, r));
30
+ return {
31
+ ruleId: f.ruleId,
32
+ title: f.title,
33
+ severity: f.severity,
34
+ action: matched ? matched.action : config.defaultAction,
35
+ matchedRule: matched ? `${matched.field} ${matched.operator} ${matched.value}` : "default",
36
+ };
37
+ });
38
+ }
39
+ // ─── CLI ────────────────────────────────────────────────────────────────────
40
+ export function runFindingAutoTriage(argv) {
41
+ const configIdx = argv.indexOf("--config");
42
+ const configPath = configIdx >= 0 ? argv[configIdx + 1] : ".judges-triage.json";
43
+ const findingsIdx = argv.indexOf("--findings");
44
+ const findingsPath = findingsIdx >= 0 ? argv[findingsIdx + 1] : "";
45
+ const formatIdx = argv.indexOf("--format");
46
+ const format = formatIdx >= 0 ? argv[formatIdx + 1] : "table";
47
+ const initMode = argv.includes("--init");
48
+ if (argv.includes("--help") || argv.includes("-h")) {
49
+ console.log(`
50
+ judges finding-auto-triage — Automatically triage findings
51
+
52
+ Usage:
53
+ judges finding-auto-triage --findings <path> [--config <path>] [--format table|json]
54
+ judges finding-auto-triage --init [--config <path>]
55
+
56
+ Options:
57
+ --findings <path> Path to findings JSON file
58
+ --config <path> Triage rules config (default: .judges-triage.json)
59
+ --init Create default triage config
60
+ --format <fmt> Output format: table (default), json
61
+ --help, -h Show this help
62
+ `);
63
+ return;
64
+ }
65
+ if (initMode) {
66
+ const defaultConfig = {
67
+ rules: [
68
+ { field: "severity", operator: "eq", value: "critical", action: "accept", priority: 100 },
69
+ { field: "severity", operator: "eq", value: "high", action: "accept", priority: 90 },
70
+ { field: "confidence", operator: "lte", value: 0.3, action: "ignore", priority: 80 },
71
+ ],
72
+ defaultAction: "defer",
73
+ lastUpdated: new Date().toISOString(),
74
+ };
75
+ writeFileSync(configPath, JSON.stringify(defaultConfig, null, 2));
76
+ console.log(`Created default triage config: ${configPath}`);
77
+ return;
78
+ }
79
+ if (!findingsPath || !existsSync(findingsPath)) {
80
+ console.error("Provide --findings <path> to a valid findings JSON file.");
81
+ process.exitCode = 1;
82
+ return;
83
+ }
84
+ if (!existsSync(configPath)) {
85
+ console.error(`Triage config not found: ${configPath}. Run with --init to create one.`);
86
+ process.exitCode = 1;
87
+ return;
88
+ }
89
+ const findings = JSON.parse(readFileSync(findingsPath, "utf-8"));
90
+ const config = JSON.parse(readFileSync(configPath, "utf-8"));
91
+ const results = triageFindings(findings, config);
92
+ if (format === "json") {
93
+ console.log(JSON.stringify(results, null, 2));
94
+ return;
95
+ }
96
+ console.log(`\nAuto-Triage Results (${results.length} findings)`);
97
+ console.log("═".repeat(80));
98
+ console.log(` ${"Rule ID".padEnd(25)} ${"Severity".padEnd(12)} ${"Action".padEnd(10)} Matched Rule`);
99
+ console.log(" " + "─".repeat(75));
100
+ for (const r of results) {
101
+ console.log(` ${r.ruleId.padEnd(25)} ${r.severity.padEnd(12)} ${r.action.padEnd(10)} ${r.matchedRule}`);
102
+ }
103
+ const accepted = results.filter((r) => r.action === "accept").length;
104
+ const deferred = results.filter((r) => r.action === "defer").length;
105
+ const ignored = results.filter((r) => r.action === "ignore").length;
106
+ console.log(`\n Accept: ${accepted} | Defer: ${deferred} | Ignore: ${ignored}`);
107
+ console.log("═".repeat(80));
108
+ }
109
+ //# sourceMappingURL=finding-auto-triage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"finding-auto-triage.js","sourceRoot":"","sources":["../../src/commands/finding-auto-triage.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Finding-change-impact — Assess the impact of code changes on existing findings.
3
+ */
4
+ export declare function runFindingChangeImpact(argv: string[]): void;
5
+ //# sourceMappingURL=finding-change-impact.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"finding-change-impact.d.ts","sourceRoot":"","sources":["../../src/commands/finding-change-impact.ts"],"names":[],"mappings":"AAAA;;GAEG;AA4EH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CA4D3D"}
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Finding-change-impact — Assess the impact of code changes on existing findings.
3
+ */
4
+ import { readFileSync, existsSync } from "fs";
5
+ // ─── Helpers ────────────────────────────────────────────────────────────────
6
+ function assessImpact(findings, changes) {
7
+ const results = [];
8
+ const changedLineSets = new Map();
9
+ for (const ch of changes) {
10
+ const s = new Set([...ch.linesAdded, ...ch.linesRemoved]);
11
+ changedLineSets.set(ch.path, s);
12
+ }
13
+ for (const f of findings) {
14
+ const fLines = f.lineNumbers ?? [];
15
+ let bestImpact = "none";
16
+ const affected = [];
17
+ let matchedPath = "";
18
+ for (const ch of changes) {
19
+ const changedLines = changedLineSets.get(ch.path);
20
+ if (!changedLines)
21
+ continue;
22
+ const overlap = fLines.filter((ln) => changedLines.has(ln));
23
+ if (overlap.length > 0) {
24
+ bestImpact = "direct";
25
+ affected.push(...overlap);
26
+ matchedPath = ch.path;
27
+ }
28
+ else if (fLines.length > 0 && bestImpact === "none") {
29
+ const nearThreshold = 5;
30
+ const nearby = fLines.some((ln) => {
31
+ for (const cl of changedLines) {
32
+ if (Math.abs(ln - cl) <= nearThreshold)
33
+ return true;
34
+ }
35
+ return false;
36
+ });
37
+ if (nearby) {
38
+ bestImpact = "indirect";
39
+ matchedPath = ch.path;
40
+ }
41
+ }
42
+ }
43
+ results.push({
44
+ ruleId: f.ruleId,
45
+ title: f.title,
46
+ severity: f.severity,
47
+ impactLevel: bestImpact,
48
+ affectedLines: affected,
49
+ filePath: matchedPath,
50
+ });
51
+ }
52
+ return results;
53
+ }
54
+ // ─── CLI ────────────────────────────────────────────────────────────────────
55
+ export function runFindingChangeImpact(argv) {
56
+ const findingsIdx = argv.indexOf("--findings");
57
+ const findingsPath = findingsIdx >= 0 ? argv[findingsIdx + 1] : "";
58
+ const changesIdx = argv.indexOf("--changes");
59
+ const changesPath = changesIdx >= 0 ? argv[changesIdx + 1] : "";
60
+ const formatIdx = argv.indexOf("--format");
61
+ const format = formatIdx >= 0 ? argv[formatIdx + 1] : "table";
62
+ if (argv.includes("--help") || argv.includes("-h")) {
63
+ console.log(`
64
+ judges finding-change-impact — Assess impact of code changes on findings
65
+
66
+ Usage:
67
+ judges finding-change-impact --findings <path> --changes <path> [--format table|json]
68
+
69
+ Options:
70
+ --findings <path> Path to findings JSON file
71
+ --changes <path> Path to changes JSON file (array of {path, linesAdded, linesRemoved})
72
+ --format <fmt> Output format: table (default), json
73
+ --help, -h Show this help
74
+ `);
75
+ return;
76
+ }
77
+ if (!findingsPath || !existsSync(findingsPath)) {
78
+ console.error("Provide --findings <path> to a valid findings JSON file.");
79
+ process.exitCode = 1;
80
+ return;
81
+ }
82
+ if (!changesPath || !existsSync(changesPath)) {
83
+ console.error("Provide --changes <path> to a valid changes JSON file.");
84
+ process.exitCode = 1;
85
+ return;
86
+ }
87
+ const findings = JSON.parse(readFileSync(findingsPath, "utf-8"));
88
+ const changes = JSON.parse(readFileSync(changesPath, "utf-8"));
89
+ const results = assessImpact(findings, changes);
90
+ if (format === "json") {
91
+ console.log(JSON.stringify(results, null, 2));
92
+ return;
93
+ }
94
+ console.log(`\nChange Impact Analysis (${results.length} findings)`);
95
+ console.log("═".repeat(80));
96
+ console.log(` ${"Rule ID".padEnd(25)} ${"Severity".padEnd(12)} ${"Impact".padEnd(12)} Affected Lines`);
97
+ console.log(" " + "─".repeat(75));
98
+ for (const r of results) {
99
+ const lines = r.affectedLines.length > 0 ? r.affectedLines.join(", ") : "—";
100
+ console.log(` ${r.ruleId.padEnd(25)} ${r.severity.padEnd(12)} ${r.impactLevel.padEnd(12)} ${lines}`);
101
+ }
102
+ const direct = results.filter((r) => r.impactLevel === "direct").length;
103
+ const indirect = results.filter((r) => r.impactLevel === "indirect").length;
104
+ const none = results.filter((r) => r.impactLevel === "none").length;
105
+ console.log(`\n Direct: ${direct} | Indirect: ${indirect} | None: ${none}`);
106
+ console.log("═".repeat(80));
107
+ }
108
+ //# sourceMappingURL=finding-change-impact.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"finding-change-impact.js","sourceRoot":"","sources":["../../src/commands/finding-change-impact.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAoB9C,+EAA+E;AAE/E,SAAS,YAAY,CAAC,QAAmB,EAAE,OAAsB;IAC/D,MAAM,OAAO,GAAmB,EAAE,CAAC;IACnC,MAAM,eAAe,GAAG,IAAI,GAAG,EAAuB,CAAC;IACvD,KAAK,MAAM,EAAE,IAAI,OAAO,EAAE,CAAC;QACzB,MAAM,CAAC,GAAG,IAAI,GAAG,CAAS,CAAC,GAAG,EAAE,CAAC,UAAU,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC;QAClE,eAAe,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IAClC,CAAC;IAED,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,MAAM,MAAM,GAAG,CAAC,CAAC,WAAW,IAAI,EAAE,CAAC;QACnC,IAAI,UAAU,GAAmC,MAAM,CAAC;QACxD,MAAM,QAAQ,GAAa,EAAE,CAAC;QAC9B,IAAI,WAAW,GAAG,EAAE,CAAC;QAErB,KAAK,MAAM,EAAE,IAAI,OAAO,EAAE,CAAC;YACzB,MAAM,YAAY,GAAG,eAAe,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;YAClD,IAAI,CAAC,YAAY;gBAAE,SAAS;YAC5B,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;YAC5D,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACvB,UAAU,GAAG,QAAQ,CAAC;gBACtB,QAAQ,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC;gBAC1B,WAAW,GAAG,EAAE,CAAC,IAAI,CAAC;YACxB,CAAC;iBAAM,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,UAAU,KAAK,MAAM,EAAE,CAAC;gBACtD,MAAM,aAAa,GAAG,CAAC,CAAC;gBACxB,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE;oBAChC,KAAK,MAAM,EAAE,IAAI,YAAY,EAAE,CAAC;wBAC9B,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,CAAC,IAAI,aAAa;4BAAE,OAAO,IAAI,CAAC;oBACtD,CAAC;oBACD,OAAO,KAAK,CAAC;gBACf,CAAC,CAAC,CAAC;gBACH,IAAI,MAAM,EAAE,CAAC;oBACX,UAAU,GAAG,UAAU,CAAC;oBACxB,WAAW,GAAG,EAAE,CAAC,IAAI,CAAC;gBACxB,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,CAAC,IAAI,CAAC;YACX,MAAM,EAAE,CAAC,CAAC,MAAM;YAChB,KAAK,EAAE,CAAC,CAAC,KAAK;YACd,QAAQ,EAAE,CAAC,CAAC,QAAQ;YACpB,WAAW,EAAE,UAAU;YACvB,aAAa,EAAE,QAAQ;YACvB,QAAQ,EAAE,WAAW;SACtB,CAAC,CAAC;IACL,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,+EAA+E;AAE/E,MAAM,UAAU,sBAAsB,CAAC,IAAc;IACnD,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IAC/C,MAAM,YAAY,GAAG,WAAW,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACnE,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IAC7C,MAAM,WAAW,GAAG,UAAU,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAChE,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAC3C,MAAM,MAAM,GAAG,SAAS,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;IAE9D,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACnD,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;CAWf,CAAC,CAAC;QACC,OAAO;IACT,CAAC;IAED,IAAI,CAAC,YAAY,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QAC/C,OAAO,CAAC,KAAK,CAAC,0DAA0D,CAAC,CAAC;QAC1E,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACrB,OAAO;IACT,CAAC;IAED,IAAI,CAAC,WAAW,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAC7C,OAAO,CAAC,KAAK,CAAC,wDAAwD,CAAC,CAAC;QACxE,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACrB,OAAO;IACT,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAc,CAAC;IAC9E,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAkB,CAAC;IAChF,MAAM,OAAO,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAEhD,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;QACtB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAC9C,OAAO;IACT,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,6BAA6B,OAAO,CAAC,MAAM,YAAY,CAAC,CAAC;IACrE,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;IAC5B,OAAO,CAAC,GAAG,CAAC,KAAK,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,iBAAiB,CAAC,CAAC;IACxG,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;IAEnC,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACxB,MAAM,KAAK,GAAG,CAAC,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;QAC5E,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC;IACxG,CAAC;IAED,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,KAAK,QAAQ,CAAC,CAAC,MAAM,CAAC;IACxE,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,KAAK,UAAU,CAAC,CAAC,MAAM,CAAC;IAC5E,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,KAAK,MAAM,CAAC,CAAC,MAAM,CAAC;IACpE,OAAO,CAAC,GAAG,CAAC,eAAe,MAAM,gBAAgB,QAAQ,YAAY,IAAI,EAAE,CAAC,CAAC;IAC7E,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;AAC9B,CAAC"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Finding-context-enrich — Enrich findings with surrounding code context and metadata.
3
+ */
4
+ export declare function runFindingContextEnrich(argv: string[]): void;
5
+ //# sourceMappingURL=finding-context-enrich.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"finding-context-enrich.d.ts","sourceRoot":"","sources":["../../src/commands/finding-context-enrich.ts"],"names":[],"mappings":"AAAA;;GAEG;AA4CH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CA2E5D"}
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Finding-context-enrich — Enrich findings with surrounding code context and metadata.
3
+ */
4
+ import { readFileSync, existsSync } from "fs";
5
+ // ─── Helpers ────────────────────────────────────────────────────────────────
6
+ function extractContext(filePath, lineNumbers, contextSize) {
7
+ if (!existsSync(filePath)) {
8
+ return { snippet: [], start: 0, end: 0 };
9
+ }
10
+ const lines = readFileSync(filePath, "utf-8").split("\n");
11
+ if (lineNumbers.length === 0) {
12
+ return { snippet: [], start: 0, end: 0 };
13
+ }
14
+ const minLine = Math.max(0, Math.min(...lineNumbers) - 1 - contextSize);
15
+ const maxLine = Math.min(lines.length, Math.max(...lineNumbers) + contextSize);
16
+ return {
17
+ snippet: lines.slice(minLine, maxLine),
18
+ start: minLine + 1,
19
+ end: maxLine,
20
+ };
21
+ }
22
+ // ─── CLI ────────────────────────────────────────────────────────────────────
23
+ export function runFindingContextEnrich(argv) {
24
+ const findingsIdx = argv.indexOf("--findings");
25
+ const findingsPath = findingsIdx >= 0 ? argv[findingsIdx + 1] : "";
26
+ const fileIdx = argv.indexOf("--file");
27
+ const filePath = fileIdx >= 0 ? argv[fileIdx + 1] : "";
28
+ const contextIdx = argv.indexOf("--context");
29
+ const contextSize = contextIdx >= 0 ? parseInt(argv[contextIdx + 1], 10) : 3;
30
+ const formatIdx = argv.indexOf("--format");
31
+ const format = formatIdx >= 0 ? argv[formatIdx + 1] : "table";
32
+ if (argv.includes("--help") || argv.includes("-h")) {
33
+ console.log(`
34
+ judges finding-context-enrich — Enrich findings with code context
35
+
36
+ Usage:
37
+ judges finding-context-enrich --findings <path> --file <path> [--context <n>] [--format table|json]
38
+
39
+ Options:
40
+ --findings <path> Path to findings JSON file
41
+ --file <path> Source file to extract context from
42
+ --context <n> Lines of context around findings (default: 3)
43
+ --format <fmt> Output format: table (default), json
44
+ --help, -h Show this help
45
+ `);
46
+ return;
47
+ }
48
+ if (!findingsPath || !existsSync(findingsPath)) {
49
+ console.error("Provide --findings <path> to a valid findings JSON file.");
50
+ process.exitCode = 1;
51
+ return;
52
+ }
53
+ const findings = JSON.parse(readFileSync(findingsPath, "utf-8"));
54
+ const enriched = [];
55
+ for (const f of findings) {
56
+ const lineNumbers = f.lineNumbers ?? [];
57
+ const ctx = filePath ? extractContext(filePath, lineNumbers, contextSize) : { snippet: [], start: 0, end: 0 };
58
+ enriched.push({
59
+ ruleId: f.ruleId,
60
+ title: f.title,
61
+ severity: f.severity,
62
+ description: f.description,
63
+ recommendation: f.recommendation,
64
+ codeSnippet: ctx.snippet,
65
+ lineStart: ctx.start,
66
+ lineEnd: ctx.end,
67
+ contextLines: contextSize,
68
+ });
69
+ }
70
+ if (format === "json") {
71
+ console.log(JSON.stringify(enriched, null, 2));
72
+ return;
73
+ }
74
+ console.log(`\nEnriched Findings (${enriched.length})`);
75
+ console.log("═".repeat(80));
76
+ for (const e of enriched) {
77
+ console.log(`\n [${e.severity.toUpperCase()}] ${e.ruleId}: ${e.title}`);
78
+ console.log(` ${e.description}`);
79
+ console.log(` Recommendation: ${e.recommendation}`);
80
+ if (e.codeSnippet.length > 0) {
81
+ console.log(` Code (lines ${e.lineStart}–${e.lineEnd}):`);
82
+ for (let i = 0; i < e.codeSnippet.length; i++) {
83
+ console.log(` ${String(e.lineStart + i).padStart(4)} | ${e.codeSnippet[i]}`);
84
+ }
85
+ }
86
+ console.log(" " + "─".repeat(75));
87
+ }
88
+ console.log("═".repeat(80));
89
+ }
90
+ //# sourceMappingURL=finding-context-enrich.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"finding-context-enrich.js","sourceRoot":"","sources":["../../src/commands/finding-context-enrich.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAiB9C,+EAA+E;AAE/E,SAAS,cAAc,CACrB,QAAgB,EAChB,WAAqB,EACrB,WAAmB;IAEnB,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC1B,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC;IAC3C,CAAC;IACD,MAAM,KAAK,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC1D,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC7B,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC;IAC3C,CAAC;IACD,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,WAAW,CAAC,GAAG,CAAC,GAAG,WAAW,CAAC,CAAC;IACxE,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,WAAW,CAAC,GAAG,WAAW,CAAC,CAAC;IAC/E,OAAO;QACL,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC;QACtC,KAAK,EAAE,OAAO,GAAG,CAAC;QAClB,GAAG,EAAE,OAAO;KACb,CAAC;AACJ,CAAC;AAED,+EAA+E;AAE/E,MAAM,UAAU,uBAAuB,CAAC,IAAc;IACpD,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IAC/C,MAAM,YAAY,GAAG,WAAW,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACnE,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACvC,MAAM,QAAQ,GAAG,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACvD,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IAC7C,MAAM,WAAW,GAAG,UAAU,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7E,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAC3C,MAAM,MAAM,GAAG,SAAS,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;IAE9D,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACnD,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;CAYf,CAAC,CAAC;QACC,OAAO;IACT,CAAC;IAED,IAAI,CAAC,YAAY,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QAC/C,OAAO,CAAC,KAAK,CAAC,0DAA0D,CAAC,CAAC;QAC1E,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACrB,OAAO;IACT,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAc,CAAC;IAC9E,MAAM,QAAQ,GAAsB,EAAE,CAAC;IAEvC,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,MAAM,WAAW,GAAG,CAAC,CAAC,WAAW,IAAI,EAAE,CAAC;QACxC,MAAM,GAAG,GAAG,QAAQ,CAAC,CAAC,CAAC,cAAc,CAAC,QAAQ,EAAE,WAAW,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC;QAC9G,QAAQ,CAAC,IAAI,CAAC;YACZ,MAAM,EAAE,CAAC,CAAC,MAAM;YAChB,KAAK,EAAE,CAAC,CAAC,KAAK;YACd,QAAQ,EAAE,CAAC,CAAC,QAAQ;YACpB,WAAW,EAAE,CAAC,CAAC,WAAW;YAC1B,cAAc,EAAE,CAAC,CAAC,cAAc;YAChC,WAAW,EAAE,GAAG,CAAC,OAAO;YACxB,SAAS,EAAE,GAAG,CAAC,KAAK;YACpB,OAAO,EAAE,GAAG,CAAC,GAAG;YAChB,YAAY,EAAE,WAAW;SAC1B,CAAC,CAAC;IACL,CAAC;IAED,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;QACtB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAC/C,OAAO;IACT,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,wBAAwB,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC;IACxD,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;IAE5B,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;QACzE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;QAClC,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC,cAAc,EAAE,CAAC,CAAC;QAErD,IAAI,CAAC,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC7B,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC;YAC3D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC9C,OAAO,CAAC,GAAG,CAAC,OAAO,MAAM,CAAC,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YAClF,CAAC;QACH,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;IACrC,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;AAC9B,CAAC"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Finding-dismiss-workflow — Manage finding dismissal workflows.
3
+ */
4
+ export declare function runFindingDismissWorkflow(argv: string[]): void;
5
+ //# sourceMappingURL=finding-dismiss-workflow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"finding-dismiss-workflow.d.ts","sourceRoot":"","sources":["../../src/commands/finding-dismiss-workflow.ts"],"names":[],"mappings":"AAAA;;GAEG;AAsBH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CA8H9D"}
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Finding-dismiss-workflow — Manage finding dismissal workflows.
3
+ */
4
+ import { readFileSync, writeFileSync, existsSync } from "fs";
5
+ // ─── CLI ────────────────────────────────────────────────────────────────────
6
+ export function runFindingDismissWorkflow(argv) {
7
+ const storeIdx = argv.indexOf("--store");
8
+ const storePath = storeIdx >= 0 ? argv[storeIdx + 1] : ".judges-dismissals.json";
9
+ const formatIdx = argv.indexOf("--format");
10
+ const format = formatIdx >= 0 ? argv[formatIdx + 1] : "table";
11
+ if (argv.includes("--help") || argv.includes("-h")) {
12
+ console.log(`
13
+ judges finding-dismiss-workflow — Manage finding dismissals
14
+
15
+ Usage:
16
+ judges finding-dismiss-workflow [--store <path>]
17
+ [--dismiss <ruleId> --reason <r> --by <name> --note <text> --expires <date>]
18
+ [--revoke <ruleId>] [--audit] [--format table|json]
19
+
20
+ Options:
21
+ --store <path> Dismissal store (default: .judges-dismissals.json)
22
+ --dismiss <ruleId> Dismiss a finding
23
+ --reason <r> Reason: false-positive, accepted-risk, wont-fix, duplicate
24
+ --by <name> Who dismissed it
25
+ --note <text> Additional note
26
+ --expires <date> Expiry date (YYYY-MM-DD)
27
+ --revoke <ruleId> Revoke a dismissal
28
+ --audit Show audit log of all dismissals
29
+ --format <fmt> Output format: table (default), json
30
+ --help, -h Show this help
31
+ `);
32
+ return;
33
+ }
34
+ let store;
35
+ if (existsSync(storePath)) {
36
+ store = JSON.parse(readFileSync(storePath, "utf-8"));
37
+ }
38
+ else {
39
+ store = { dismissals: [], lastUpdated: new Date().toISOString().split("T")[0] };
40
+ }
41
+ // Dismiss
42
+ const dismissIdx = argv.indexOf("--dismiss");
43
+ if (dismissIdx >= 0) {
44
+ const ruleId = argv[dismissIdx + 1];
45
+ const reasonIdx = argv.indexOf("--reason");
46
+ const byIdx = argv.indexOf("--by");
47
+ const noteIdx = argv.indexOf("--note");
48
+ const expiresIdx = argv.indexOf("--expires");
49
+ const dismissal = {
50
+ ruleId,
51
+ reason: (reasonIdx >= 0 ? argv[reasonIdx + 1] : "accepted-risk"),
52
+ dismissedBy: byIdx >= 0 ? argv[byIdx + 1] : "unknown",
53
+ dismissedAt: new Date().toISOString().split("T")[0],
54
+ expiresAt: expiresIdx >= 0 ? argv[expiresIdx + 1] : "9999-12-31",
55
+ note: noteIdx >= 0 ? argv[noteIdx + 1] : "",
56
+ };
57
+ store.dismissals.push(dismissal);
58
+ store.lastUpdated = new Date().toISOString().split("T")[0];
59
+ writeFileSync(storePath, JSON.stringify(store, null, 2));
60
+ console.log(`Dismissed: ${ruleId} (${dismissal.reason})`);
61
+ return;
62
+ }
63
+ // Revoke
64
+ const revokeIdx = argv.indexOf("--revoke");
65
+ if (revokeIdx >= 0) {
66
+ const ruleId = argv[revokeIdx + 1];
67
+ const before = store.dismissals.length;
68
+ store.dismissals = store.dismissals.filter((d) => d.ruleId !== ruleId);
69
+ store.lastUpdated = new Date().toISOString().split("T")[0];
70
+ writeFileSync(storePath, JSON.stringify(store, null, 2));
71
+ console.log(`Revoked ${before - store.dismissals.length} dismissal(s) for: ${ruleId}`);
72
+ return;
73
+ }
74
+ // Audit log
75
+ if (argv.includes("--audit")) {
76
+ const today = new Date().toISOString().split("T")[0];
77
+ const active = store.dismissals.filter((d) => d.expiresAt >= today);
78
+ const expired = store.dismissals.filter((d) => d.expiresAt < today);
79
+ if (format === "json") {
80
+ console.log(JSON.stringify({ active, expired }, null, 2));
81
+ return;
82
+ }
83
+ console.log(`\nDismissal Audit`);
84
+ console.log("═".repeat(70));
85
+ if (active.length > 0) {
86
+ console.log(" Active:");
87
+ for (const d of active) {
88
+ console.log(` ${d.ruleId.padEnd(25)} [${d.reason}] by ${d.dismissedBy} (${d.dismissedAt})`);
89
+ if (d.note.length > 0)
90
+ console.log(` Note: ${d.note}`);
91
+ }
92
+ }
93
+ if (expired.length > 0) {
94
+ console.log(" Expired:");
95
+ for (const d of expired) {
96
+ console.log(` ${d.ruleId.padEnd(25)} [${d.reason}] expired ${d.expiresAt}`);
97
+ }
98
+ }
99
+ console.log(`\n Active: ${active.length} | Expired: ${expired.length}`);
100
+ console.log("═".repeat(70));
101
+ return;
102
+ }
103
+ // List
104
+ if (format === "json") {
105
+ console.log(JSON.stringify(store, null, 2));
106
+ return;
107
+ }
108
+ console.log(`\nDismissals`);
109
+ console.log("═".repeat(65));
110
+ if (store.dismissals.length === 0) {
111
+ console.log(" No dismissals. Use --dismiss <ruleId> to add one.");
112
+ }
113
+ else {
114
+ for (const d of store.dismissals) {
115
+ console.log(` ${d.ruleId.padEnd(25)} [${d.reason}] by ${d.dismissedBy}`);
116
+ }
117
+ }
118
+ console.log("═".repeat(65));
119
+ }
120
+ //# sourceMappingURL=finding-dismiss-workflow.js.map