@kevinrabun/judges 3.38.0 → 3.41.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 (379) hide show
  1. package/CHANGELOG.md +68 -0
  2. package/README.md +5 -4
  3. package/dist/api.d.ts +5 -2
  4. package/dist/api.d.ts.map +1 -1
  5. package/dist/api.js +5 -1
  6. package/dist/api.js.map +1 -1
  7. package/dist/ast/structural-parser.js +3 -3
  8. package/dist/ast/structural-parser.js.map +1 -1
  9. package/dist/calibration.d.ts +35 -0
  10. package/dist/calibration.d.ts.map +1 -1
  11. package/dist/calibration.js +52 -0
  12. package/dist/calibration.js.map +1 -1
  13. package/dist/cli.d.ts.map +1 -1
  14. package/dist/cli.js +370 -16
  15. package/dist/cli.js.map +1 -1
  16. package/dist/commands/auto-calibrate.d.ts +15 -0
  17. package/dist/commands/auto-calibrate.d.ts.map +1 -0
  18. package/dist/commands/auto-calibrate.js +107 -0
  19. package/dist/commands/auto-calibrate.js.map +1 -0
  20. package/dist/commands/benchmark-languages.js +4 -4
  21. package/dist/commands/benchmark.d.ts +2 -1
  22. package/dist/commands/benchmark.d.ts.map +1 -1
  23. package/dist/commands/benchmark.js +67 -2
  24. package/dist/commands/benchmark.js.map +1 -1
  25. package/dist/commands/calibration-dashboard.d.ts.map +1 -1
  26. package/dist/commands/calibration-dashboard.js +198 -0
  27. package/dist/commands/calibration-dashboard.js.map +1 -1
  28. package/dist/commands/calibration-share.d.ts +31 -0
  29. package/dist/commands/calibration-share.d.ts.map +1 -0
  30. package/dist/commands/calibration-share.js +183 -0
  31. package/dist/commands/calibration-share.js.map +1 -0
  32. package/dist/commands/compliance-report.d.ts +35 -0
  33. package/dist/commands/compliance-report.d.ts.map +1 -0
  34. package/dist/commands/compliance-report.js +162 -0
  35. package/dist/commands/compliance-report.js.map +1 -0
  36. package/dist/commands/config-migrate.d.ts +44 -0
  37. package/dist/commands/config-migrate.d.ts.map +1 -0
  38. package/dist/commands/config-migrate.js +241 -0
  39. package/dist/commands/config-migrate.js.map +1 -0
  40. package/dist/commands/dedup-report.d.ts +13 -0
  41. package/dist/commands/dedup-report.d.ts.map +1 -0
  42. package/dist/commands/dedup-report.js +138 -0
  43. package/dist/commands/dedup-report.js.map +1 -0
  44. package/dist/commands/dep-audit.d.ts +53 -0
  45. package/dist/commands/dep-audit.d.ts.map +1 -0
  46. package/dist/commands/dep-audit.js +278 -0
  47. package/dist/commands/dep-audit.js.map +1 -0
  48. package/dist/commands/deprecated.d.ts +48 -0
  49. package/dist/commands/deprecated.d.ts.map +1 -0
  50. package/dist/commands/deprecated.js +202 -0
  51. package/dist/commands/deprecated.js.map +1 -0
  52. package/dist/commands/diff.d.ts.map +1 -1
  53. package/dist/commands/diff.js +8 -3
  54. package/dist/commands/diff.js.map +1 -1
  55. package/dist/commands/feedback-rules.d.ts +29 -0
  56. package/dist/commands/feedback-rules.d.ts.map +1 -0
  57. package/dist/commands/feedback-rules.js +174 -0
  58. package/dist/commands/feedback-rules.js.map +1 -0
  59. package/dist/commands/feedback.d.ts +12 -0
  60. package/dist/commands/feedback.d.ts.map +1 -1
  61. package/dist/commands/feedback.js +16 -0
  62. package/dist/commands/feedback.js.map +1 -1
  63. package/dist/commands/fix-pr.d.ts +23 -0
  64. package/dist/commands/fix-pr.d.ts.map +1 -0
  65. package/dist/commands/fix-pr.js +323 -0
  66. package/dist/commands/fix-pr.js.map +1 -0
  67. package/dist/commands/fix.d.ts.map +1 -1
  68. package/dist/commands/fix.js +33 -1
  69. package/dist/commands/fix.js.map +1 -1
  70. package/dist/commands/governance.d.ts +32 -0
  71. package/dist/commands/governance.d.ts.map +1 -0
  72. package/dist/commands/governance.js +203 -0
  73. package/dist/commands/governance.js.map +1 -0
  74. package/dist/commands/help.d.ts +8 -0
  75. package/dist/commands/help.d.ts.map +1 -0
  76. package/dist/commands/help.js +303 -0
  77. package/dist/commands/help.js.map +1 -0
  78. package/dist/commands/hook.d.ts.map +1 -1
  79. package/dist/commands/hook.js +17 -20
  80. package/dist/commands/hook.js.map +1 -1
  81. package/dist/commands/interactive-fix.d.ts +23 -0
  82. package/dist/commands/interactive-fix.d.ts.map +1 -0
  83. package/dist/commands/interactive-fix.js +140 -0
  84. package/dist/commands/interactive-fix.js.map +1 -0
  85. package/dist/commands/llm-benchmark.d.ts +119 -0
  86. package/dist/commands/llm-benchmark.d.ts.map +1 -0
  87. package/dist/commands/llm-benchmark.js +396 -0
  88. package/dist/commands/llm-benchmark.js.map +1 -0
  89. package/dist/commands/metrics-dashboard.d.ts +22 -0
  90. package/dist/commands/metrics-dashboard.d.ts.map +1 -0
  91. package/dist/commands/metrics-dashboard.js +335 -0
  92. package/dist/commands/metrics-dashboard.js.map +1 -0
  93. package/dist/commands/metrics.d.ts +58 -0
  94. package/dist/commands/metrics.d.ts.map +1 -0
  95. package/dist/commands/metrics.js +242 -0
  96. package/dist/commands/metrics.js.map +1 -0
  97. package/dist/commands/monorepo.d.ts +38 -0
  98. package/dist/commands/monorepo.d.ts.map +1 -0
  99. package/dist/commands/monorepo.js +233 -0
  100. package/dist/commands/monorepo.js.map +1 -0
  101. package/dist/commands/notify.d.ts +79 -0
  102. package/dist/commands/notify.d.ts.map +1 -0
  103. package/dist/commands/notify.js +325 -0
  104. package/dist/commands/notify.js.map +1 -0
  105. package/dist/commands/onboard.d.ts +13 -0
  106. package/dist/commands/onboard.d.ts.map +1 -0
  107. package/dist/commands/onboard.js +179 -0
  108. package/dist/commands/onboard.js.map +1 -0
  109. package/dist/commands/org-metrics.d.ts +24 -0
  110. package/dist/commands/org-metrics.d.ts.map +1 -0
  111. package/dist/commands/org-metrics.js +238 -0
  112. package/dist/commands/org-metrics.js.map +1 -0
  113. package/dist/commands/override.d.ts +62 -0
  114. package/dist/commands/override.d.ts.map +1 -0
  115. package/dist/commands/override.js +264 -0
  116. package/dist/commands/override.js.map +1 -0
  117. package/dist/commands/parity.d.ts +31 -0
  118. package/dist/commands/parity.d.ts.map +1 -0
  119. package/dist/commands/parity.js +213 -0
  120. package/dist/commands/parity.js.map +1 -0
  121. package/dist/commands/plugin-search.d.ts +40 -0
  122. package/dist/commands/plugin-search.d.ts.map +1 -0
  123. package/dist/commands/plugin-search.js +328 -0
  124. package/dist/commands/plugin-search.js.map +1 -0
  125. package/dist/commands/plugins.d.ts +13 -0
  126. package/dist/commands/plugins.d.ts.map +1 -0
  127. package/dist/commands/plugins.js +105 -0
  128. package/dist/commands/plugins.js.map +1 -0
  129. package/dist/commands/quality-gate.d.ts +70 -0
  130. package/dist/commands/quality-gate.d.ts.map +1 -0
  131. package/dist/commands/quality-gate.js +264 -0
  132. package/dist/commands/quality-gate.js.map +1 -0
  133. package/dist/commands/review.js +1 -1
  134. package/dist/commands/review.js.map +1 -1
  135. package/dist/commands/snapshot.d.ts +27 -0
  136. package/dist/commands/snapshot.d.ts.map +1 -1
  137. package/dist/commands/snapshot.js +99 -0
  138. package/dist/commands/snapshot.js.map +1 -1
  139. package/dist/commands/trace.d.ts +65 -0
  140. package/dist/commands/trace.d.ts.map +1 -0
  141. package/dist/commands/trace.js +246 -0
  142. package/dist/commands/trace.js.map +1 -0
  143. package/dist/commands/trust-ramp.d.ts +30 -0
  144. package/dist/commands/trust-ramp.d.ts.map +1 -0
  145. package/dist/commands/trust-ramp.js +190 -0
  146. package/dist/commands/trust-ramp.js.map +1 -0
  147. package/dist/config.d.ts +5 -0
  148. package/dist/config.d.ts.map +1 -1
  149. package/dist/config.js +65 -0
  150. package/dist/config.js.map +1 -1
  151. package/dist/data-adapter.d.ts +124 -0
  152. package/dist/data-adapter.d.ts.map +1 -0
  153. package/dist/data-adapter.js +213 -0
  154. package/dist/data-adapter.js.map +1 -0
  155. package/dist/evaluators/accessibility.js +1 -1
  156. package/dist/evaluators/accessibility.js.map +1 -1
  157. package/dist/evaluators/ai-code-safety.d.ts.map +1 -1
  158. package/dist/evaluators/ai-code-safety.js +1 -4
  159. package/dist/evaluators/ai-code-safety.js.map +1 -1
  160. package/dist/evaluators/cost-effectiveness.js +1 -1
  161. package/dist/evaluators/cost-effectiveness.js.map +1 -1
  162. package/dist/evaluators/false-positive-review.js +4 -4
  163. package/dist/evaluators/false-positive-review.js.map +1 -1
  164. package/dist/evaluators/framework-rules.d.ts +59 -0
  165. package/dist/evaluators/framework-rules.d.ts.map +1 -0
  166. package/dist/evaluators/framework-rules.js +292 -0
  167. package/dist/evaluators/framework-rules.js.map +1 -0
  168. package/dist/evaluators/iac-security.js +1 -1
  169. package/dist/evaluators/iac-security.js.map +1 -1
  170. package/dist/evaluators/index.d.ts.map +1 -1
  171. package/dist/evaluators/index.js +59 -10
  172. package/dist/evaluators/index.js.map +1 -1
  173. package/dist/evaluators/intent-alignment.d.ts +4 -0
  174. package/dist/evaluators/intent-alignment.d.ts.map +1 -1
  175. package/dist/evaluators/intent-alignment.js +163 -0
  176. package/dist/evaluators/intent-alignment.js.map +1 -1
  177. package/dist/evaluators/logic-review.js +1 -1
  178. package/dist/evaluators/logic-review.js.map +1 -1
  179. package/dist/evaluators/maintainability.js +1 -1
  180. package/dist/evaluators/maintainability.js.map +1 -1
  181. package/dist/evaluators/over-engineering.js +3 -3
  182. package/dist/evaluators/over-engineering.js.map +1 -1
  183. package/dist/evaluators/project.d.ts +12 -0
  184. package/dist/evaluators/project.d.ts.map +1 -1
  185. package/dist/evaluators/project.js +86 -0
  186. package/dist/evaluators/project.js.map +1 -1
  187. package/dist/evaluators/security.js +2 -2
  188. package/dist/evaluators/security.js.map +1 -1
  189. package/dist/evaluators/ux.js +1 -1
  190. package/dist/evaluators/ux.js.map +1 -1
  191. package/dist/finding-lifecycle.d.ts +9 -0
  192. package/dist/finding-lifecycle.d.ts.map +1 -1
  193. package/dist/finding-lifecycle.js +15 -0
  194. package/dist/finding-lifecycle.js.map +1 -1
  195. package/dist/fix-history.d.ts +9 -0
  196. package/dist/fix-history.d.ts.map +1 -1
  197. package/dist/fix-history.js +15 -0
  198. package/dist/fix-history.js.map +1 -1
  199. package/dist/formatters/sarif.d.ts +3 -0
  200. package/dist/formatters/sarif.d.ts.map +1 -1
  201. package/dist/formatters/sarif.js +36 -12
  202. package/dist/formatters/sarif.js.map +1 -1
  203. package/dist/github-app.d.ts +16 -1
  204. package/dist/github-app.d.ts.map +1 -1
  205. package/dist/github-app.js +85 -2
  206. package/dist/github-app.js.map +1 -1
  207. package/dist/index.js +5 -0
  208. package/dist/index.js.map +1 -1
  209. package/dist/judge-registry.d.ts +157 -0
  210. package/dist/judge-registry.d.ts.map +1 -0
  211. package/dist/judge-registry.js +273 -0
  212. package/dist/judge-registry.js.map +1 -0
  213. package/dist/judges/accessibility.d.ts.map +1 -1
  214. package/dist/judges/accessibility.js +4 -0
  215. package/dist/judges/accessibility.js.map +1 -1
  216. package/dist/judges/agent-instructions.d.ts.map +1 -1
  217. package/dist/judges/agent-instructions.js +4 -0
  218. package/dist/judges/agent-instructions.js.map +1 -1
  219. package/dist/judges/ai-code-safety.d.ts.map +1 -1
  220. package/dist/judges/ai-code-safety.js +4 -0
  221. package/dist/judges/ai-code-safety.js.map +1 -1
  222. package/dist/judges/api-contract.d.ts.map +1 -1
  223. package/dist/judges/api-contract.js +4 -0
  224. package/dist/judges/api-contract.js.map +1 -1
  225. package/dist/judges/api-design.d.ts.map +1 -1
  226. package/dist/judges/api-design.js +4 -0
  227. package/dist/judges/api-design.js.map +1 -1
  228. package/dist/judges/authentication.d.ts.map +1 -1
  229. package/dist/judges/authentication.js +4 -0
  230. package/dist/judges/authentication.js.map +1 -1
  231. package/dist/judges/backwards-compatibility.d.ts.map +1 -1
  232. package/dist/judges/backwards-compatibility.js +4 -0
  233. package/dist/judges/backwards-compatibility.js.map +1 -1
  234. package/dist/judges/caching.d.ts.map +1 -1
  235. package/dist/judges/caching.js +4 -0
  236. package/dist/judges/caching.js.map +1 -1
  237. package/dist/judges/ci-cd.d.ts.map +1 -1
  238. package/dist/judges/ci-cd.js +4 -0
  239. package/dist/judges/ci-cd.js.map +1 -1
  240. package/dist/judges/cloud-readiness.d.ts.map +1 -1
  241. package/dist/judges/cloud-readiness.js +4 -0
  242. package/dist/judges/cloud-readiness.js.map +1 -1
  243. package/dist/judges/code-structure.d.ts.map +1 -1
  244. package/dist/judges/code-structure.js +4 -0
  245. package/dist/judges/code-structure.js.map +1 -1
  246. package/dist/judges/compliance.d.ts.map +1 -1
  247. package/dist/judges/compliance.js +4 -0
  248. package/dist/judges/compliance.js.map +1 -1
  249. package/dist/judges/concurrency.d.ts.map +1 -1
  250. package/dist/judges/concurrency.js +4 -0
  251. package/dist/judges/concurrency.js.map +1 -1
  252. package/dist/judges/configuration-management.d.ts.map +1 -1
  253. package/dist/judges/configuration-management.js +4 -0
  254. package/dist/judges/configuration-management.js.map +1 -1
  255. package/dist/judges/cost-effectiveness.d.ts.map +1 -1
  256. package/dist/judges/cost-effectiveness.js +4 -0
  257. package/dist/judges/cost-effectiveness.js.map +1 -1
  258. package/dist/judges/cybersecurity.d.ts.map +1 -1
  259. package/dist/judges/cybersecurity.js +4 -0
  260. package/dist/judges/cybersecurity.js.map +1 -1
  261. package/dist/judges/data-security.d.ts.map +1 -1
  262. package/dist/judges/data-security.js +4 -0
  263. package/dist/judges/data-security.js.map +1 -1
  264. package/dist/judges/data-sovereignty.d.ts.map +1 -1
  265. package/dist/judges/data-sovereignty.js +4 -0
  266. package/dist/judges/data-sovereignty.js.map +1 -1
  267. package/dist/judges/database.d.ts.map +1 -1
  268. package/dist/judges/database.js +4 -0
  269. package/dist/judges/database.js.map +1 -1
  270. package/dist/judges/dependency-health.d.ts.map +1 -1
  271. package/dist/judges/dependency-health.js +4 -0
  272. package/dist/judges/dependency-health.js.map +1 -1
  273. package/dist/judges/documentation.d.ts.map +1 -1
  274. package/dist/judges/documentation.js +4 -0
  275. package/dist/judges/documentation.js.map +1 -1
  276. package/dist/judges/error-handling.d.ts.map +1 -1
  277. package/dist/judges/error-handling.js +4 -0
  278. package/dist/judges/error-handling.js.map +1 -1
  279. package/dist/judges/ethics-bias.d.ts.map +1 -1
  280. package/dist/judges/ethics-bias.js +4 -0
  281. package/dist/judges/ethics-bias.js.map +1 -1
  282. package/dist/judges/false-positive-review.d.ts.map +1 -1
  283. package/dist/judges/false-positive-review.js +2 -0
  284. package/dist/judges/false-positive-review.js.map +1 -1
  285. package/dist/judges/framework-safety.d.ts.map +1 -1
  286. package/dist/judges/framework-safety.js +4 -0
  287. package/dist/judges/framework-safety.js.map +1 -1
  288. package/dist/judges/hallucination-detection.d.ts.map +1 -1
  289. package/dist/judges/hallucination-detection.js +4 -0
  290. package/dist/judges/hallucination-detection.js.map +1 -1
  291. package/dist/judges/iac-security.d.ts.map +1 -1
  292. package/dist/judges/iac-security.js +4 -0
  293. package/dist/judges/iac-security.js.map +1 -1
  294. package/dist/judges/index.d.ts +59 -0
  295. package/dist/judges/index.d.ts.map +1 -1
  296. package/dist/judges/index.js +65 -189
  297. package/dist/judges/index.js.map +1 -1
  298. package/dist/judges/intent-alignment.d.ts.map +1 -1
  299. package/dist/judges/intent-alignment.js +4 -0
  300. package/dist/judges/intent-alignment.js.map +1 -1
  301. package/dist/judges/internationalization.d.ts.map +1 -1
  302. package/dist/judges/internationalization.js +4 -0
  303. package/dist/judges/internationalization.js.map +1 -1
  304. package/dist/judges/logging-privacy.d.ts.map +1 -1
  305. package/dist/judges/logging-privacy.js +4 -0
  306. package/dist/judges/logging-privacy.js.map +1 -1
  307. package/dist/judges/logic-review.d.ts.map +1 -1
  308. package/dist/judges/logic-review.js +4 -0
  309. package/dist/judges/logic-review.js.map +1 -1
  310. package/dist/judges/maintainability.d.ts.map +1 -1
  311. package/dist/judges/maintainability.js +4 -0
  312. package/dist/judges/maintainability.js.map +1 -1
  313. package/dist/judges/model-fingerprint.d.ts.map +1 -1
  314. package/dist/judges/model-fingerprint.js +4 -0
  315. package/dist/judges/model-fingerprint.js.map +1 -1
  316. package/dist/judges/multi-turn-coherence.d.ts.map +1 -1
  317. package/dist/judges/multi-turn-coherence.js +4 -0
  318. package/dist/judges/multi-turn-coherence.js.map +1 -1
  319. package/dist/judges/observability.d.ts.map +1 -1
  320. package/dist/judges/observability.js +4 -0
  321. package/dist/judges/observability.js.map +1 -1
  322. package/dist/judges/over-engineering.d.ts.map +1 -1
  323. package/dist/judges/over-engineering.js +4 -0
  324. package/dist/judges/over-engineering.js.map +1 -1
  325. package/dist/judges/performance.d.ts.map +1 -1
  326. package/dist/judges/performance.js +4 -0
  327. package/dist/judges/performance.js.map +1 -1
  328. package/dist/judges/portability.d.ts.map +1 -1
  329. package/dist/judges/portability.js +4 -0
  330. package/dist/judges/portability.js.map +1 -1
  331. package/dist/judges/rate-limiting.d.ts.map +1 -1
  332. package/dist/judges/rate-limiting.js +4 -0
  333. package/dist/judges/rate-limiting.js.map +1 -1
  334. package/dist/judges/reliability.d.ts.map +1 -1
  335. package/dist/judges/reliability.js +4 -0
  336. package/dist/judges/reliability.js.map +1 -1
  337. package/dist/judges/scalability.d.ts.map +1 -1
  338. package/dist/judges/scalability.js +4 -0
  339. package/dist/judges/scalability.js.map +1 -1
  340. package/dist/judges/security.d.ts.map +1 -1
  341. package/dist/judges/security.js +4 -0
  342. package/dist/judges/security.js.map +1 -1
  343. package/dist/judges/software-practices.d.ts.map +1 -1
  344. package/dist/judges/software-practices.js +4 -0
  345. package/dist/judges/software-practices.js.map +1 -1
  346. package/dist/judges/testing.d.ts.map +1 -1
  347. package/dist/judges/testing.js +4 -0
  348. package/dist/judges/testing.js.map +1 -1
  349. package/dist/judges/ux.d.ts.map +1 -1
  350. package/dist/judges/ux.js +4 -0
  351. package/dist/judges/ux.js.map +1 -1
  352. package/dist/parallel.d.ts +53 -0
  353. package/dist/parallel.d.ts.map +1 -0
  354. package/dist/parallel.js +170 -0
  355. package/dist/parallel.js.map +1 -0
  356. package/dist/plugins.d.ts +8 -51
  357. package/dist/plugins.d.ts.map +1 -1
  358. package/dist/plugins.js +16 -125
  359. package/dist/plugins.js.map +1 -1
  360. package/dist/security-ids.d.ts +24 -0
  361. package/dist/security-ids.d.ts.map +1 -0
  362. package/dist/security-ids.js +240 -0
  363. package/dist/security-ids.js.map +1 -0
  364. package/dist/tools/prompts.d.ts +4 -0
  365. package/dist/tools/prompts.d.ts.map +1 -1
  366. package/dist/tools/prompts.js +6 -4
  367. package/dist/tools/prompts.js.map +1 -1
  368. package/dist/tools/register-scaffold.d.ts +3 -0
  369. package/dist/tools/register-scaffold.d.ts.map +1 -0
  370. package/dist/tools/register-scaffold.js +399 -0
  371. package/dist/tools/register-scaffold.js.map +1 -0
  372. package/dist/tools/register.d.ts +1 -1
  373. package/dist/tools/register.d.ts.map +1 -1
  374. package/dist/tools/register.js +3 -1
  375. package/dist/tools/register.js.map +1 -1
  376. package/dist/types.d.ts +75 -0
  377. package/dist/types.d.ts.map +1 -1
  378. package/package.json +3 -2
  379. package/server.json +2 -2
package/dist/cli.js CHANGED
@@ -42,6 +42,8 @@ import { generateGitLabCi, generateAzurePipelines, generateBitbucketPipelines }
42
42
  import { getPreset, listPresets, composePresets } from "./presets.js";
43
43
  import { parseConfig } from "./config.js";
44
44
  import { applyPatches } from "./commands/fix.js";
45
+ import { DiskCache } from "./disk-cache.js";
46
+ import { contentHash } from "./cache.js";
45
47
  import { runFeedback } from "./commands/feedback.js";
46
48
  import { runBenchmark } from "./commands/benchmark.js";
47
49
  import { runRule } from "./commands/rule.js";
@@ -50,6 +52,8 @@ import { runConfig } from "./commands/config-share.js";
50
52
  import { runDoctor } from "./commands/doctor.js";
51
53
  import { runTriage } from "./commands/triage.js";
52
54
  import { formatComparisonReport, formatFullComparisonMatrix, TOOL_PROFILES } from "./comparison.js";
55
+ import { runOverride, loadOverrideStore, applyOverrides } from "./commands/override.js";
56
+ import { runNotify } from "./commands/notify.js";
53
57
  // ─── Language Detection from Extension ──────────────────────────────────────
54
58
  const EXT_TO_LANG = {
55
59
  ".ts": "typescript",
@@ -117,8 +121,12 @@ function parseCliArgs(argv) {
117
121
  include: [],
118
122
  maxFiles: undefined,
119
123
  changedOnly: false,
124
+ stagedOnly: false,
120
125
  explain: false,
121
126
  sample: false,
127
+ trace: false,
128
+ incremental: false,
129
+ noCache: false,
122
130
  };
123
131
  // First non-flag arg is the command
124
132
  let i = 2; // skip node + script
@@ -185,6 +193,9 @@ function parseCliArgs(argv) {
185
193
  case "--changed-only":
186
194
  args.changedOnly = true;
187
195
  break;
196
+ case "--staged-only":
197
+ args.stagedOnly = true;
198
+ break;
188
199
  case "--explain":
189
200
  args.explain = true;
190
201
  break;
@@ -202,6 +213,15 @@ function parseCliArgs(argv) {
202
213
  case "--sample":
203
214
  args.sample = true;
204
215
  break;
216
+ case "--trace":
217
+ args.trace = true;
218
+ break;
219
+ case "--incremental":
220
+ args.incremental = true;
221
+ break;
222
+ case "--no-cache":
223
+ args.noCache = true;
224
+ break;
205
225
  default:
206
226
  // If it looks like a file path (not a flag), treat as --file
207
227
  if (!arg.startsWith("-") && !args.file) {
@@ -223,6 +243,7 @@ USAGE:
223
243
  judges init Interactive project setup wizard
224
244
  judges fix <file> [--apply] Preview / apply auto-fixes
225
245
  --rule <id> --severity <level> --lines <start>-<end>
246
+ judges fix-pr <path> Create a PR with auto-fix patches (like Dependabot)
226
247
  judges watch <path> Watch files and re-evaluate on save
227
248
  judges lsp Start LSP server for editor integration
228
249
  judges trend [file] Show findings trend from snapshots
@@ -244,6 +265,14 @@ USAGE:
244
265
  judges compare Compare judges vs other tools
245
266
  judges review Post inline review comments on a GitHub PR
246
267
  judges app serve Start GitHub App webhook server (zero-config PR reviews)
268
+ judges notify Send results to Slack, Teams, or webhook endpoints
269
+ judges quality-gate Evaluate composite quality gate policies
270
+ judges auto-calibrate Auto-tune thresholds from feedback history
271
+ judges dep-audit Correlate dependency vulnerabilities with code findings
272
+ judges monorepo Discover and evaluate monorepo packages
273
+ judges config-migrate Migrate .judgesrc to current schema
274
+ judges deprecated List deprecated rules with migration guidance
275
+ judges dedup-report Cross-run finding deduplication report
247
276
  judges tune Analyze project and suggest optimal config
248
277
  judges list List all available judges
249
278
  judges version Show version information
@@ -273,6 +302,7 @@ EVAL OPTIONS:
273
302
  --fix Auto-fix findings after evaluation (applies patches in-place)
274
303
  --changed-only Only evaluate files changed since last commit (uses git diff)
275
304
  --explain Enrich findings with OWASP/CWE learning context
305
+ --trace Show detailed decision trace for every finding
276
306
  --help, -h Show this help
277
307
 
278
308
  FIX OPTIONS:
@@ -526,6 +556,23 @@ function getGitChangedFiles(cwd) {
526
556
  return [];
527
557
  }
528
558
  }
559
+ function getStagedFiles(cwd) {
560
+ try {
561
+ const resolvedCwd = resolve(cwd);
562
+ const output = execSync("git diff --cached --name-only --diff-filter=ACM", {
563
+ cwd: resolvedCwd,
564
+ encoding: "utf-8",
565
+ stdio: ["pipe", "pipe", "pipe"],
566
+ }).trim();
567
+ return output
568
+ .split("\n")
569
+ .filter(Boolean)
570
+ .map((f) => resolve(resolvedCwd, f));
571
+ }
572
+ catch {
573
+ return [];
574
+ }
575
+ }
529
576
  // ─── Format Output ──────────────────────────────────────────────────────────
530
577
  function formatTribunalOutput(verdict, format, filePath) {
531
578
  switch (format) {
@@ -613,10 +660,33 @@ function formatTextOutput(verdict) {
613
660
  lines.push(" " + "─".repeat(60));
614
661
  for (const f of critical.slice(0, 20)) {
615
662
  const fixTag = f.patch ? " 🔧" : "";
616
- lines.push(` [${f.severity.toUpperCase().padEnd(8)}] ${f.ruleId}: ${f.title}${fixTag}`);
663
+ const confTag = f.confidence !== undefined ? ` (${Math.round(f.confidence * 100)}% confidence)` : "";
664
+ lines.push(` [${f.severity.toUpperCase().padEnd(8)}] ${f.ruleId}: ${f.title}${fixTag}${confTag}`);
617
665
  if (f.lineNumbers && f.lineNumbers.length > 0) {
618
666
  lines.push(` Line ${f.lineNumbers[0]}: ${f.description.slice(0, 100)}`);
619
667
  }
668
+ if (f.provenance) {
669
+ lines.push(` Evidence: ${f.provenance}`);
670
+ }
671
+ if (f.evidenceBasis) {
672
+ lines.push(` Basis: ${f.evidenceBasis}`);
673
+ }
674
+ if (f.evidenceChain && f.evidenceChain.steps.length > 0) {
675
+ lines.push(` Impact: ${f.evidenceChain.impactStatement}`);
676
+ for (const step of f.evidenceChain.steps.slice(0, 3)) {
677
+ const loc = step.line ? ` (L${step.line})` : "";
678
+ lines.push(` → [${step.source}]${loc} ${step.observation}`);
679
+ }
680
+ }
681
+ if (f.cweIds && f.cweIds.length > 0) {
682
+ lines.push(` CWE: ${f.cweIds.join(", ")}`);
683
+ }
684
+ if (f.owaspLlmTop10) {
685
+ lines.push(` OWASP LLM: ${f.owaspLlmTop10}`);
686
+ }
687
+ if (f.learnMoreUrl) {
688
+ lines.push(` 📖 Learn more: ${f.learnMoreUrl}`);
689
+ }
620
690
  }
621
691
  if (critical.length > 20) {
622
692
  lines.push(` ... and ${critical.length - 20} more critical/high findings`);
@@ -650,13 +720,23 @@ function formatSingleJudgeTextOutput(evaluation) {
650
720
  lines.push(` Findings : ${evaluation.findings.length}`);
651
721
  lines.push("");
652
722
  for (const f of evaluation.findings) {
653
- lines.push(` [${f.severity.toUpperCase().padEnd(8)}] ${f.ruleId}: ${f.title}`);
723
+ const confTag = f.confidence !== undefined ? ` (${Math.round(f.confidence * 100)}%)` : "";
724
+ lines.push(` [${f.severity.toUpperCase().padEnd(8)}] ${f.ruleId}: ${f.title}${confTag}`);
654
725
  if (f.lineNumbers && f.lineNumbers.length > 0) {
655
726
  lines.push(` Line ${f.lineNumbers[0]}: ${f.description.slice(0, 120)}`);
656
727
  }
728
+ if (f.provenance) {
729
+ lines.push(` Evidence: ${f.provenance}`);
730
+ }
731
+ if (f.evidenceChain && f.evidenceChain.steps.length > 0) {
732
+ lines.push(` Impact: ${f.evidenceChain.impactStatement}`);
733
+ }
657
734
  if (f.suggestedFix) {
658
735
  lines.push(` Fix: ${f.suggestedFix.slice(0, 120)}`);
659
736
  }
737
+ if (f.learnMoreUrl) {
738
+ lines.push(` 📖 ${f.learnMoreUrl}`);
739
+ }
660
740
  }
661
741
  lines.push("");
662
742
  return lines.join("\n");
@@ -720,6 +800,12 @@ export async function runCli(argv) {
720
800
  runFix(argv);
721
801
  return; // runFix calls process.exit internally
722
802
  }
803
+ // ─── Fix-PR Command ──────────────────────────────────────────────────
804
+ if (args.command === "fix-pr") {
805
+ const { runFixPr } = await import("./commands/fix-pr.js");
806
+ await runFixPr(argv);
807
+ return;
808
+ }
723
809
  // ─── Watch Command ────────────────────────────────────────────────────
724
810
  if (args.command === "watch") {
725
811
  const { runWatch } = await import("./commands/watch.js");
@@ -782,11 +868,66 @@ export async function runCli(argv) {
782
868
  runFeedback(argv);
783
869
  return;
784
870
  }
871
+ // ─── Override Command ─────────────────────────────────────────────────
872
+ if (args.command === "override") {
873
+ runOverride(argv);
874
+ return;
875
+ }
876
+ // ─── Feedback-Rules Command ───────────────────────────────────────────
877
+ if (args.command === "feedback-rules") {
878
+ const { runFeedbackRules } = await import("./commands/feedback-rules.js");
879
+ runFeedbackRules(argv);
880
+ return;
881
+ }
882
+ // ─── Governance Command ───────────────────────────────────────────────
883
+ if (args.command === "governance") {
884
+ const { runGovernance } = await import("./commands/governance.js");
885
+ runGovernance(argv);
886
+ return;
887
+ }
888
+ // ─── Parity Command ──────────────────────────────────────────────────
889
+ if (args.command === "parity") {
890
+ const { runParity } = await import("./commands/parity.js");
891
+ runParity(argv);
892
+ return;
893
+ }
894
+ // ─── Compliance-Report Command ────────────────────────────────────────
895
+ if (args.command === "compliance-report") {
896
+ const { buildComplianceReport, formatComplianceReportText } = await import("./commands/compliance-report.js");
897
+ const target = args.file || ".";
898
+ const code = args.file ? (await import("fs")).readFileSync(args.file, "utf-8") : "";
899
+ let findings = [];
900
+ if (code) {
901
+ const lang = detectLanguage(args.file) || "typescript";
902
+ const result = evaluateWithTribunal(code, lang);
903
+ findings = result.findings;
904
+ }
905
+ const framework = argv.find((a, i) => argv[i - 1] === "--framework") || undefined;
906
+ const report = buildComplianceReport(target, findings, framework);
907
+ if (argv.includes("--json")) {
908
+ console.log(JSON.stringify(report, null, 2));
909
+ }
910
+ else {
911
+ console.log(formatComplianceReportText(report));
912
+ }
913
+ return;
914
+ }
785
915
  // ─── Triage Command ───────────────────────────────────────────────────
786
916
  if (args.command === "triage") {
787
917
  runTriage(argv);
788
918
  return;
789
919
  }
920
+ // ─── Quality-Gate Command ─────────────────────────────────────────────
921
+ if (args.command === "quality-gate") {
922
+ const { runQualityGate } = await import("./commands/quality-gate.js");
923
+ runQualityGate(argv);
924
+ return;
925
+ }
926
+ // ─── Notify Command ─────────────────────────────────────────────────
927
+ if (args.command === "notify") {
928
+ await runNotify(argv);
929
+ return;
930
+ }
790
931
  // ─── Benchmark Command ────────────────────────────────────────────────
791
932
  if (args.command === "benchmark") {
792
933
  runBenchmark(argv);
@@ -819,6 +960,42 @@ export async function runCli(argv) {
819
960
  runAppCommand(argv.slice(3));
820
961
  return;
821
962
  }
963
+ // ─── Auto-Calibrate Command ────────────────────────────────────────
964
+ if (args.command === "auto-calibrate") {
965
+ const { runAutoCalibrate } = await import("./commands/auto-calibrate.js");
966
+ runAutoCalibrate(argv);
967
+ return;
968
+ }
969
+ // ─── Dep-Audit Command ─────────────────────────────────────────────
970
+ if (args.command === "dep-audit") {
971
+ const { runDepAuditCommand } = await import("./commands/dep-audit.js");
972
+ runDepAuditCommand(argv);
973
+ return;
974
+ }
975
+ // ─── Monorepo Command ─────────────────────────────────────────────
976
+ if (args.command === "monorepo") {
977
+ const { runMonorepoCommand } = await import("./commands/monorepo.js");
978
+ runMonorepoCommand(argv);
979
+ return;
980
+ }
981
+ // ─── Config-Migrate Command ───────────────────────────────────────
982
+ if (args.command === "config-migrate") {
983
+ const { runConfigMigrate } = await import("./commands/config-migrate.js");
984
+ runConfigMigrate(argv);
985
+ return;
986
+ }
987
+ // ─── Deprecated Rules Command ─────────────────────────────────────
988
+ if (args.command === "deprecated") {
989
+ const { runDeprecatedCommand } = await import("./commands/deprecated.js");
990
+ runDeprecatedCommand(argv);
991
+ return;
992
+ }
993
+ // ─── Dedup Report Command ─────────────────────────────────────────
994
+ if (args.command === "dedup-report") {
995
+ const { runDedupReport } = await import("./commands/dedup-report.js");
996
+ runDedupReport(argv);
997
+ return;
998
+ }
822
999
  // ─── Tune Command ─────────────────────────────────────────────────
823
1000
  if (args.command === "tune") {
824
1001
  const { runTune } = await import("./commands/tune.js");
@@ -837,6 +1014,12 @@ export async function runCli(argv) {
837
1014
  await runCommunityPatterns(argv);
838
1015
  process.exit(0);
839
1016
  }
1017
+ // ─── Calibration Share Command ───────────────────────────────────────
1018
+ if (args.command === "calibration-share") {
1019
+ const { runCalibrationShare } = await import("./commands/calibration-share.js");
1020
+ runCalibrationShare(argv);
1021
+ process.exit(0);
1022
+ }
840
1023
  // ─── Compare Command ─────────────────────────────────────────────────
841
1024
  if (args.command === "compare") {
842
1025
  const toolName = argv[3];
@@ -856,9 +1039,11 @@ export async function runCli(argv) {
856
1039
  }
857
1040
  // ─── Trend Command ───────────────────────────────────────────────────
858
1041
  if (args.command === "trend") {
859
- const { loadSnapshotStore, computeTrend, formatTrendReport, formatTrendReportHtml } = await import("./commands/snapshot.js");
860
- const snapshotFile = argv.find((a, i) => i >= 3 && !a.startsWith("-")) || ".judges-snapshots.json";
1042
+ const { loadSnapshotStore, computeTrend, formatTrendReport, formatTrendReportHtml, detectRegressions, formatRegressionAlerts, } = await import("./commands/snapshot.js");
1043
+ const snapshotFile = argv.find((a, i) => i >= 3 && !a.startsWith("-") && !["html", "json", "text"].includes(a)) ||
1044
+ ".judges-snapshots.json";
861
1045
  const formatArg = argv.includes("--format") ? argv[argv.indexOf("--format") + 1] : "text";
1046
+ const outputArg = argv.includes("--output") ? argv[argv.indexOf("--output") + 1] : undefined;
862
1047
  const store = loadSnapshotStore(snapshotFile);
863
1048
  if (store.snapshots.length === 0) {
864
1049
  console.log("No snapshot data found. Run evaluations with --snapshot to collect trend data.");
@@ -866,14 +1051,30 @@ export async function runCli(argv) {
866
1051
  }
867
1052
  else {
868
1053
  const report = computeTrend(store);
1054
+ let output;
869
1055
  if (formatArg === "html") {
870
- console.log(formatTrendReportHtml(report));
1056
+ output = formatTrendReportHtml(report);
871
1057
  }
872
1058
  else if (formatArg === "json") {
873
- console.log(JSON.stringify(report, null, 2));
1059
+ output = JSON.stringify(report, null, 2);
1060
+ }
1061
+ else {
1062
+ output = formatTrendReport(report);
1063
+ }
1064
+ if (outputArg) {
1065
+ writeFileSync(outputArg, output, "utf-8");
1066
+ console.log(` ✅ Trend report written to ${outputArg}`);
874
1067
  }
875
1068
  else {
876
- console.log(formatTrendReport(report));
1069
+ console.log(output);
1070
+ }
1071
+ // Regression alerts
1072
+ const regressions = detectRegressions(store);
1073
+ if (regressions.length > 0) {
1074
+ console.log(formatRegressionAlerts(regressions));
1075
+ if (args.failOnFindings && regressions.some((r) => r.severity === "error")) {
1076
+ process.exit(1);
1077
+ }
877
1078
  }
878
1079
  }
879
1080
  process.exit(0);
@@ -884,6 +1085,54 @@ export async function runCli(argv) {
884
1085
  runScaffoldPlugin(argv);
885
1086
  process.exit(0);
886
1087
  }
1088
+ // ─── Plugin Search Command ───────────────────────────────────────────
1089
+ if (args.command === "plugin") {
1090
+ const { runPluginSearch } = await import("./commands/plugin-search.js");
1091
+ runPluginSearch(argv);
1092
+ process.exit(0);
1093
+ }
1094
+ // ─── Trust Ramp Command ──────────────────────────────────────────────
1095
+ if (args.command === "trust-ramp") {
1096
+ const { runTrustRamp } = await import("./commands/trust-ramp.js");
1097
+ runTrustRamp(argv);
1098
+ process.exit(0);
1099
+ }
1100
+ // ─── Metrics Command ────────────────────────────────────────────────
1101
+ if (args.command === "metrics") {
1102
+ const { runMetrics } = await import("./commands/metrics.js");
1103
+ runMetrics(argv);
1104
+ process.exit(0);
1105
+ }
1106
+ // ─── Metrics Dashboard Command ────────────────────────────────────────
1107
+ if (args.command === "metrics-dashboard") {
1108
+ const { runMetricsDashboard } = await import("./commands/metrics-dashboard.js");
1109
+ runMetricsDashboard(argv);
1110
+ process.exit(0);
1111
+ }
1112
+ // ─── Help Command ────────────────────────────────────────────────────
1113
+ if (args.command === "help") {
1114
+ const { runHelp } = await import("./commands/help.js");
1115
+ runHelp(argv);
1116
+ process.exit(0);
1117
+ }
1118
+ // ─── Onboard Command ─────────────────────────────────────────────────
1119
+ if (args.command === "onboard") {
1120
+ const { runOnboard } = await import("./commands/onboard.js");
1121
+ await runOnboard(argv);
1122
+ process.exit(0);
1123
+ }
1124
+ // ─── Org Metrics Command ──────────────────────────────────────────────
1125
+ if (args.command === "org-metrics") {
1126
+ const { runOrgMetrics } = await import("./commands/org-metrics.js");
1127
+ runOrgMetrics(argv);
1128
+ process.exit(0);
1129
+ }
1130
+ // ─── Plugins Command ──────────────────────────────────────────────────
1131
+ if (args.command === "plugins") {
1132
+ const { runPlugins } = await import("./commands/plugins.js");
1133
+ runPlugins(argv);
1134
+ process.exit(0);
1135
+ }
887
1136
  // ─── List Command ────────────────────────────────────────────────────
888
1137
  if (args.command === "list") {
889
1138
  listJudges();
@@ -920,6 +1169,12 @@ export async function runCli(argv) {
920
1169
  const changedSet = new Set(changedFiles.map((f) => resolve(f)));
921
1170
  files = files.filter((f) => changedSet.has(resolve(f)));
922
1171
  }
1172
+ // ── --staged-only: scope to git-staged files ──
1173
+ if (args.stagedOnly) {
1174
+ const stagedFiles = getStagedFiles(target);
1175
+ const stagedSet = new Set(stagedFiles.map((f) => resolve(f)));
1176
+ files = files.filter((f) => stagedSet.has(resolve(f)));
1177
+ }
923
1178
  if (files.length === 0) {
924
1179
  console.error(`No supported source files found in: ${target}${args.changedOnly ? " (changed-only)" : ""}`);
925
1180
  process.exit(1);
@@ -933,6 +1188,9 @@ export async function runCli(argv) {
933
1188
  let failCount = 0;
934
1189
  let totalFixed = 0;
935
1190
  let totalFixable = 0;
1191
+ let cacheHits = 0;
1192
+ // Incremental evaluation: use disk cache to skip unchanged files
1193
+ const diskCache = args.noCache ? undefined : new DiskCache();
936
1194
  for (let idx = 0; idx < files.length; idx++) {
937
1195
  const filePath = files[idx];
938
1196
  const relPath = relative(resolve("."), filePath);
@@ -941,7 +1199,21 @@ export async function runCli(argv) {
941
1199
  }
942
1200
  const fileCode = readFileSync(filePath, "utf-8");
943
1201
  const fileLang = args.language || detectLanguage(filePath) || "typescript";
944
- const verdict = evaluateWithTribunal(fileCode, fileLang, undefined, evalOptions);
1202
+ // Check disk cache for incremental mode (always when cache available)
1203
+ const hash = contentHash(fileCode, fileLang);
1204
+ let verdict;
1205
+ if (diskCache) {
1206
+ verdict = diskCache.get(hash);
1207
+ }
1208
+ if (verdict) {
1209
+ cacheHits++;
1210
+ }
1211
+ else {
1212
+ verdict = evaluateWithTribunal(fileCode, fileLang, undefined, evalOptions);
1213
+ if (diskCache) {
1214
+ diskCache.set(hash, verdict, relPath);
1215
+ }
1216
+ }
945
1217
  // Apply baseline suppression
946
1218
  if (loadedBaseline) {
947
1219
  for (const evaluation of verdict.evaluations) {
@@ -949,6 +1221,18 @@ export async function runCli(argv) {
949
1221
  }
950
1222
  verdict.findings = verdict.findings.filter((f) => !isBaselined(f, loadedBaseline, fileCode, relPath));
951
1223
  }
1224
+ // Apply override suppressions for multi-file mode
1225
+ {
1226
+ const overrideStore = loadOverrideStore();
1227
+ if (overrideStore.overrides.length > 0) {
1228
+ for (const evaluation of verdict.evaluations) {
1229
+ const result = applyOverrides(evaluation.findings, overrideStore, relPath);
1230
+ evaluation.findings = result.active;
1231
+ }
1232
+ const topResult = applyOverrides(verdict.findings, overrideStore, relPath);
1233
+ verdict.findings = topResult.active;
1234
+ }
1235
+ }
952
1236
  const fileFindings = verdict.evaluations.reduce((s, e) => s + e.findings.length, 0);
953
1237
  const fileFixable = verdict.evaluations.reduce((s, e) => s + e.findings.filter((f) => f.patch).length, 0);
954
1238
  totalFindings += fileFindings;
@@ -996,6 +1280,9 @@ export async function runCli(argv) {
996
1280
  if (args.fix && totalFixed > 0) {
997
1281
  console.log(` Fixed : ${totalFixed} patch(es) applied`);
998
1282
  }
1283
+ if (cacheHits > 0) {
1284
+ console.log(` Cached : ${cacheHits} file(s) unchanged (skipped re-evaluation)`);
1285
+ }
999
1286
  console.log(` Time : ${elapsed}ms`);
1000
1287
  console.log("");
1001
1288
  if (args.failOnFindings && failCount > 0)
@@ -1069,6 +1356,27 @@ export async function runCli(argv) {
1069
1356
  if (args.verbose) {
1070
1357
  console.log(` ⏱ Evaluated in ${elapsed}ms`);
1071
1358
  }
1359
+ // Trace output — show pipeline decision trace
1360
+ if (args.trace) {
1361
+ const { buildEvaluationTrace, formatTraceText } = await import("./commands/trace.js");
1362
+ const wrappedForTrace = {
1363
+ overallVerdict: evaluation.verdict,
1364
+ overallScore: evaluation.score,
1365
+ summary: evaluation.summary,
1366
+ evaluations: [evaluation],
1367
+ findings: evaluation.findings,
1368
+ criticalCount: evaluation.findings.filter((f) => f.severity === "critical").length,
1369
+ highCount: evaluation.findings.filter((f) => f.severity === "high").length,
1370
+ timestamp: new Date().toISOString(),
1371
+ };
1372
+ const trace = buildEvaluationTrace(wrappedForTrace, resolvedPath || args.file, language);
1373
+ if (args.format === "json") {
1374
+ console.log(JSON.stringify(trace, null, 2));
1375
+ }
1376
+ else {
1377
+ console.log(formatTraceText(trace));
1378
+ }
1379
+ }
1072
1380
  // Exit code — fail-on-findings or min-score
1073
1381
  if (args.failOnFindings && evaluation.verdict === "fail")
1074
1382
  process.exit(1);
@@ -1117,6 +1425,22 @@ export async function runCli(argv) {
1117
1425
  }
1118
1426
  verdict.findings = filterBySeverity(verdict.findings, evalConfig.minSeverity);
1119
1427
  }
1428
+ // Apply override suppressions
1429
+ {
1430
+ const overrideStore = loadOverrideStore();
1431
+ if (overrideStore.overrides.length > 0) {
1432
+ const fileSrc = resolvedPath || args.file;
1433
+ for (const evaluation of verdict.evaluations) {
1434
+ const result = applyOverrides(evaluation.findings, overrideStore, fileSrc);
1435
+ evaluation.findings = result.active;
1436
+ }
1437
+ const topResult = applyOverrides(verdict.findings, overrideStore, fileSrc);
1438
+ verdict.findings = topResult.active;
1439
+ if (topResult.overridden.length > 0 && !args.quiet) {
1440
+ console.log(` ℹ️ ${topResult.overridden.length} finding(s) suppressed by overrides`);
1441
+ }
1442
+ }
1443
+ }
1120
1444
  // Enrich with learning context when --explain is set
1121
1445
  if (args.explain) {
1122
1446
  for (const evaluation of verdict.evaluations) {
@@ -1149,6 +1473,17 @@ export async function runCli(argv) {
1149
1473
  console.log(` ⏱ Evaluated in ${elapsed}ms`);
1150
1474
  console.log(` 📊 ${verdict.evaluations.length} judges, ${verdict.findings.length} total findings`);
1151
1475
  }
1476
+ // Trace output — show pipeline decision trace
1477
+ if (args.trace) {
1478
+ const { buildEvaluationTrace, formatTraceText } = await import("./commands/trace.js");
1479
+ const trace = buildEvaluationTrace(verdict, resolvedPath || args.file, language);
1480
+ if (args.format === "json") {
1481
+ console.log(JSON.stringify(trace, null, 2));
1482
+ }
1483
+ else {
1484
+ console.log(formatTraceText(trace));
1485
+ }
1486
+ }
1152
1487
  // Exit code — fail-on-findings or min-score
1153
1488
  if (args.failOnFindings && verdict.overallVerdict === "fail")
1154
1489
  process.exit(1);
@@ -1380,18 +1715,37 @@ function enrichWithExplanations(findings) {
1380
1715
  return findings.map((f) => {
1381
1716
  const prefix = f.ruleId.replace(/-\d+$/, "");
1382
1717
  const ctx = RULE_PREFIX_CONTEXT[prefix];
1383
- if (!ctx)
1384
- return f;
1385
1718
  const parts = [f.description];
1386
- if (ctx.owasp)
1387
- parts.push(`\n📚 OWASP: ${ctx.owasp}`);
1388
- if (ctx.cwe)
1389
- parts.push(`CWE: ${ctx.cwe}`);
1390
- parts.push(`💡 ${ctx.learn}`);
1719
+ // Layer 2: evidence-based explanation
1720
+ if (f.confidence !== undefined) {
1721
+ parts.push(`\n🎯 Confidence: ${Math.round(f.confidence * 100)}%`);
1722
+ }
1723
+ if (f.provenance) {
1724
+ parts.push(`🔍 Detection: ${f.provenance}`);
1725
+ }
1726
+ if (f.evidenceBasis) {
1727
+ parts.push(`📊 Evidence: ${f.evidenceBasis}`);
1728
+ }
1729
+ if (f.evidenceChain && f.evidenceChain.steps.length > 0) {
1730
+ parts.push(`\n⚡ Why this matters: ${f.evidenceChain.impactStatement}`);
1731
+ parts.push(" Evidence chain:");
1732
+ for (const step of f.evidenceChain.steps.slice(0, 5)) {
1733
+ const loc = step.line ? ` (L${step.line})` : "";
1734
+ parts.push(` → [${step.source}]${loc} ${step.observation}`);
1735
+ }
1736
+ }
1737
+ // Layer 1: OWASP/CWE reference context
1738
+ if (ctx) {
1739
+ if (ctx.owasp)
1740
+ parts.push(`\n📚 OWASP: ${ctx.owasp}`);
1741
+ if (ctx.cwe)
1742
+ parts.push(`CWE: ${ctx.cwe}`);
1743
+ parts.push(`💡 ${ctx.learn}`);
1744
+ }
1391
1745
  return {
1392
1746
  ...f,
1393
1747
  description: parts.join(" "),
1394
- reference: f.reference || [ctx.owasp, ctx.cwe].filter(Boolean).join(" / ") || f.reference,
1748
+ reference: f.reference || (ctx ? [ctx.owasp, ctx.cwe].filter(Boolean).join(" / ") : undefined) || f.reference,
1395
1749
  };
1396
1750
  });
1397
1751
  }