karajan-code 4.70.3 → 5.0.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 (388) hide show
  1. package/README.md +2 -2
  2. package/package.json +6 -14
  3. package/packages/hu-board/package.json +1 -1
  4. package/packages/hu-board/public/app.js +4 -18
  5. package/packages/hu-board/public/index.html +5 -2
  6. package/packages/hu-board/public/styles.css +26 -0
  7. package/packages/hu-board/public/utils/api.js +0 -74
  8. package/packages/hu-board/public/utils/board-tour.js +62 -0
  9. package/packages/hu-board/public/utils/board-view.js +49 -144
  10. package/packages/hu-board/public/utils/command-launcher.js +8 -70
  11. package/packages/hu-board/public/utils/formatters.js +10 -0
  12. package/packages/hu-board/public/utils/governance-view.js +13 -1
  13. package/packages/hu-board/public/utils/hu-actions.js +17 -68
  14. package/packages/hu-board/public/utils/init-listeners.js +7 -8
  15. package/packages/hu-board/public/utils/log-panel.js +3 -16
  16. package/packages/hu-board/public/utils/maggle-mode.js +2 -12
  17. package/packages/hu-board/public/utils/modals.js +7 -0
  18. package/packages/hu-board/public/utils/project-picker-view.js +1 -1
  19. package/packages/hu-board/public/utils/server-push.js +3 -22
  20. package/packages/hu-board/public/utils/shared-board-notice.js +33 -0
  21. package/packages/hu-board/public/utils/story-detail-view.js +5 -19
  22. package/packages/hu-board/src/cleanup-zombies.js +0 -1
  23. package/packages/hu-board/src/command-runner.js +36 -25
  24. package/packages/hu-board/src/db-connection.js +282 -0
  25. package/packages/hu-board/src/db-paths.js +113 -0
  26. package/packages/hu-board/src/db-queries.js +188 -0
  27. package/packages/hu-board/src/db-tombstones.js +51 -0
  28. package/packages/hu-board/src/db.js +28 -619
  29. package/packages/hu-board/src/ephemeral-cleaner.js +2 -3
  30. package/packages/hu-board/src/hu-zombie-reaper.js +5 -1
  31. package/packages/hu-board/src/plan-mutations.js +3 -153
  32. package/packages/hu-board/src/plans-service.js +55 -0
  33. package/packages/hu-board/src/routes/api/commands.js +122 -0
  34. package/packages/hu-board/src/routes/api/plans.js +55 -0
  35. package/packages/hu-board/src/routes/api/projects.js +267 -0
  36. package/packages/hu-board/src/routes/api/prompts.js +135 -0
  37. package/packages/hu-board/src/routes/api/sessions.js +95 -0
  38. package/packages/hu-board/src/routes/api/stories.js +183 -0
  39. package/packages/hu-board/src/routes/api/system.js +241 -0
  40. package/packages/hu-board/src/routes/api/tombstones.js +38 -0
  41. package/packages/hu-board/src/routes/api.js +24 -1371
  42. package/packages/hu-board/src/routes/governance.js +23 -1
  43. package/packages/hu-board/src/routes/lanes.js +40 -0
  44. package/packages/hu-board/src/routes/rag.js +4 -3
  45. package/packages/hu-board/src/server.js +20 -34
  46. package/packages/hu-board/src/sync-files.js +318 -0
  47. package/packages/hu-board/src/sync-project.js +99 -0
  48. package/packages/hu-board/src/sync.js +22 -566
  49. package/packages/hu-board/src/zombie-reaper.js +1 -1
  50. package/scripts/dual-publish.mjs +19 -3
  51. package/scripts/postinstall.js +15 -2
  52. package/scripts/verify-pack-mcp.mjs +11 -7
  53. package/scripts/verify-pack.mjs +4 -4
  54. package/src/audit/audit-history.js +3 -2
  55. package/src/audit/dead-exports.js +68 -59
  56. package/src/audit/deterministic-summary.js +33 -13
  57. package/src/audit/npm-signatures.js +41 -0
  58. package/src/audit/sbom.js +35 -0
  59. package/src/checks/agent-token.js +112 -0
  60. package/src/checks/ai-surface.js +9 -7
  61. package/src/checks/config-files.js +8 -7
  62. package/src/checks/dir-setup.js +34 -1
  63. package/src/checks/native-build.js +21 -39
  64. package/src/checks/runner.js +128 -142
  65. package/src/cli/advanced-commands.js +6 -6
  66. package/src/cli/register-meta.js +42 -82
  67. package/src/cli/register-pipeline.js +8 -140
  68. package/src/cli/register-plan.js +9 -100
  69. package/src/cli/retired-commands.js +49 -0
  70. package/src/cli.js +18 -5
  71. package/src/commands/agent-run.js +40 -26
  72. package/src/commands/audit.js +127 -124
  73. package/src/commands/board.js +5 -9
  74. package/src/commands/check.js +29 -16
  75. package/src/commands/doctor.js +2 -0
  76. package/src/commands/env.js +176 -148
  77. package/src/commands/go.js +76 -55
  78. package/src/commands/harden.js +105 -86
  79. package/src/commands/hu-start.js +52 -0
  80. package/src/commands/hu.js +288 -221
  81. package/src/commands/identity.js +111 -78
  82. package/src/commands/init-atril.js +47 -0
  83. package/src/commands/init.js +11 -40
  84. package/src/commands/install-tools.js +70 -85
  85. package/src/commands/main-guard.js +78 -0
  86. package/src/commands/policy.js +226 -184
  87. package/src/commands/qmd.js +27 -21
  88. package/src/commands/rag.js +75 -48
  89. package/src/commands/review-gate.js +422 -339
  90. package/src/commands/start.js +4 -5
  91. package/src/commands/steward.js +96 -47
  92. package/src/commands/tournament.js +46 -37
  93. package/src/commands/worktree.js +94 -25
  94. package/src/config/loader.js +34 -17
  95. package/src/config/overrides.js +2 -1
  96. package/src/config/secrets.js +36 -0
  97. package/src/config.js +1 -0
  98. package/src/environment/adr.js +16 -2
  99. package/src/environment/board-access.js +11 -9
  100. package/src/git/karajan-label.js +20 -8
  101. package/src/guards/main-guard.js +54 -0
  102. package/src/harden/branch-protection.js +36 -3
  103. package/src/harden/hook-templates.js +16 -1
  104. package/src/harden/sentinel/posttooluse.mjs +18 -6
  105. package/src/harden/sentinel/pretooluse-sentinel.mjs +81 -35
  106. package/src/harden/sentinel/sentinel-lib.mjs +149 -23
  107. package/src/harden/sentinel/sentinel-shell.mjs +64 -0
  108. package/src/harden/sentinel/sessionstart.mjs +3 -2
  109. package/src/harden/sentinel/stop.mjs +5 -4
  110. package/src/harden/workflow-engine.js +12 -1
  111. package/src/harden/workflow-templates.js +1 -1
  112. package/src/hu/board-lookup.js +29 -0
  113. package/src/hu/gh-identity.js +23 -0
  114. package/src/hu/github-board.js +4 -2
  115. package/src/hu/lane-prune.js +15 -7
  116. package/src/hu/lane-setup.js +65 -0
  117. package/src/hu/lanes.js +66 -0
  118. package/src/hu/team-board-mirror.js +3 -2
  119. package/src/infrastructure/command-runner.js +1 -1
  120. package/src/infrastructure/file-system-service.js +1 -1
  121. package/src/mcp/handlers/direct-handlers.js +2 -292
  122. package/src/mcp/handlers/hu-handlers.js +44 -55
  123. package/src/mcp/handlers/management-handlers.js +2 -42
  124. package/src/mcp/server-handlers.js +16 -22
  125. package/src/mcp/tools.js +5 -200
  126. package/src/plan/lane-plans.js +54 -0
  127. package/src/plan/plan-store.js +7 -4
  128. package/src/policy/add.js +26 -12
  129. package/src/policy/adr-number-check.js +31 -0
  130. package/src/prompts/audit.js +299 -339
  131. package/src/prompts/card-context.js +10 -5
  132. package/src/prompts/reviewer.js +5 -2
  133. package/src/rag/auto-update.js +56 -43
  134. package/src/rag/bootstrap-index.js +28 -54
  135. package/src/rag/migrate.js +1 -1
  136. package/src/rag/onnx-fallback.js +2 -2
  137. package/src/rag/pid-lease.js +70 -0
  138. package/src/rag/project-store.js +2 -12
  139. package/src/review/card-first.js +57 -46
  140. package/src/review/dual-review.js +5 -4
  141. package/src/review/gate-gitignore.js +23 -4
  142. package/src/review/gate-hook.js +47 -0
  143. package/src/review/one-shot-review.js +51 -37
  144. package/src/review/publish-pr.js +18 -3
  145. package/src/review/repo-docs.js +73 -0
  146. package/src/review/repo-stack.js +59 -0
  147. package/src/review/reviewer-fallback.js +34 -3
  148. package/src/review/seal-commit.js +29 -0
  149. package/src/review/sonar-pregate.js +59 -44
  150. package/src/review/third-party-review.js +90 -16
  151. package/src/review/third-party-size.js +43 -0
  152. package/src/review/third-party-skills.js +54 -0
  153. package/src/review/verify-pr.js +2 -26
  154. package/src/roles/audit-role.js +106 -125
  155. package/src/skills/atril-skills.js +5 -4
  156. package/src/sonar/scanner.js +116 -101
  157. package/src/steward/invariants.js +5 -4
  158. package/src/steward/phantom-sweep.js +66 -0
  159. package/src/tournament/judge.js +60 -53
  160. package/src/utils/agent-home.js +33 -0
  161. package/src/utils/gh-account.js +37 -0
  162. package/src/utils/git.js +0 -13
  163. package/src/utils/home-migration.js +7 -1
  164. package/src/utils/main-checkout.js +53 -0
  165. package/src/utils/qmd-collection.js +3 -1
  166. package/src/utils/welcome.js +3 -3
  167. package/templates/{skills → atril/commands}/kj-architect.md +5 -0
  168. package/templates/{skills → atril/commands}/kj-audit.md +5 -0
  169. package/templates/{skills → atril/commands}/kj-board.md +5 -0
  170. package/templates/{skills → atril/commands}/kj-code.md +5 -0
  171. package/templates/{skills → atril/commands}/kj-csv-transform.md +5 -0
  172. package/templates/{skills → atril/commands}/kj-data-report.md +5 -0
  173. package/templates/{skills → atril/commands}/kj-discover.md +5 -0
  174. package/templates/{skills → atril/commands}/kj-rag-query.md +5 -0
  175. package/templates/{skills → atril/commands}/kj-review.md +5 -0
  176. package/templates/{skills → atril/commands}/kj-security.md +5 -0
  177. package/templates/{skills → atril/commands}/kj-sonar.md +5 -0
  178. package/templates/{skills → atril/commands}/kj-sql-analysis.md +5 -0
  179. package/templates/{skills → atril/commands}/kj-test.md +5 -0
  180. package/packages/hu-board/public/utils/run-launcher.js +0 -169
  181. package/packages/hu-board/src/run-tracker.js +0 -121
  182. package/src/activity-log.js +0 -59
  183. package/src/agents/host-agent.js +0 -38
  184. package/src/agents/model-registry.js +0 -142
  185. package/src/audit/plan-adherence.js +0 -224
  186. package/src/autonomy/arbiter-role.js +0 -71
  187. package/src/autonomy/arbiter.js +0 -22
  188. package/src/autonomy/decider.js +0 -18
  189. package/src/autonomy/decision-resolver.js +0 -58
  190. package/src/autonomy/outcome-report.js +0 -55
  191. package/src/autonomy/stage-ask.js +0 -30
  192. package/src/brain/decision-tracker.js +0 -125
  193. package/src/brain/decisor.js +0 -243
  194. package/src/brain/solomon-consult.js +0 -171
  195. package/src/brain/standby-scheduler.js +0 -8
  196. package/src/budget/comparison.js +0 -96
  197. package/src/canvas/parse-md.js +0 -238
  198. package/src/canvas/schema.js +0 -101
  199. package/src/canvas/to-flat.js +0 -85
  200. package/src/canvas/validate.js +0 -163
  201. package/src/ci/dispatch.js +0 -99
  202. package/src/ci/index.js +0 -3
  203. package/src/ci/pr-diff.js +0 -26
  204. package/src/cli/register-standby.js +0 -26
  205. package/src/commands/architect.js +0 -111
  206. package/src/commands/autorun.js +0 -49
  207. package/src/commands/researcher.js +0 -54
  208. package/src/commands/resume.js +0 -72
  209. package/src/commands/review.js +0 -89
  210. package/src/commands/run.js +0 -185
  211. package/src/commands/standby.js +0 -117
  212. package/src/commands/status.js +0 -36
  213. package/src/commands/triage.js +0 -78
  214. package/src/commands/undo.js +0 -62
  215. package/src/domains/domain-loader.js +0 -245
  216. package/src/domains/domain-registry.js +0 -140
  217. package/src/domains/domain-synthesizer.js +0 -129
  218. package/src/git/automation.js +0 -433
  219. package/src/git/coder-commit-guard.js +0 -40
  220. package/src/git/hu-automation.js +0 -243
  221. package/src/git/hu-snapshot.js +0 -10
  222. package/src/git/symlink-targets.js +0 -57
  223. package/src/golden/asserter.js +0 -92
  224. package/src/golden/loader.js +0 -52
  225. package/src/golden/runner.js +0 -92
  226. package/src/golden/schema.js +0 -41
  227. package/src/guards/duplicate-members.js +0 -86
  228. package/src/guards/intent-guard.js +0 -161
  229. package/src/guards/perf-guard.js +0 -126
  230. package/src/guards/policy-guard.js +0 -90
  231. package/src/guards/policy-resolver.js +0 -85
  232. package/src/guards/secret-redactor.js +0 -71
  233. package/src/hu/acceptance-runner.js +0 -138
  234. package/src/hu/lazy-planner.js +0 -109
  235. package/src/hu/parallel-executor.js +0 -94
  236. package/src/hu/routing-metrics.js +0 -17
  237. package/src/hu/split-validator.js +0 -143
  238. package/src/hu/splitting-detector.js +0 -158
  239. package/src/hu/splitting-generator.js +0 -175
  240. package/src/hu/store.js +0 -394
  241. package/src/infrastructure/mocks.js +0 -182
  242. package/src/mcp/handlers/run-handler.js +0 -318
  243. package/src/mcp/sovereignty-guard.js +0 -113
  244. package/src/mcp/tool-arg-normalizers.js +0 -16
  245. package/src/mutate/reviewer-signal.js +0 -76
  246. package/src/orchestrator/agent-fallback.js +0 -81
  247. package/src/orchestrator/brain-coordinator.js +0 -186
  248. package/src/orchestrator/ci-integration.js +0 -139
  249. package/src/orchestrator/config-init.js +0 -426
  250. package/src/orchestrator/direct-actions.js +0 -217
  251. package/src/orchestrator/drivers/error-recovery.js +0 -287
  252. package/src/orchestrator/drivers/init-context.js +0 -238
  253. package/src/orchestrator/drivers/iteration-loop.js +0 -382
  254. package/src/orchestrator/drivers/iteration-phases/coder-and-refactorer.js +0 -69
  255. package/src/orchestrator/drivers/iteration-phases/guards.js +0 -91
  256. package/src/orchestrator/drivers/iteration-phases/handle-approved.js +0 -29
  257. package/src/orchestrator/drivers/iteration-phases/quality-gates.js +0 -125
  258. package/src/orchestrator/drivers/iteration-phases/reviewer-gate.js +0 -62
  259. package/src/orchestrator/drivers/post-loop.js +0 -404
  260. package/src/orchestrator/drivers/pre-loop-phases/auto-hu-batch.js +0 -137
  261. package/src/orchestrator/drivers/pre-loop-phases/config-deprecations.js +0 -47
  262. package/src/orchestrator/drivers/pre-loop-phases/ensure-addyosmani-skills.js +0 -84
  263. package/src/orchestrator/drivers/pre-loop-phases/inject-loaded-plan.js +0 -393
  264. package/src/orchestrator/drivers/pre-loop.js +0 -524
  265. package/src/orchestrator/drivers/run-hu-batch.js +0 -468
  266. package/src/orchestrator/feedback-enrichment.js +0 -140
  267. package/src/orchestrator/feedback-queue.js +0 -151
  268. package/src/orchestrator/flow-control.js +0 -170
  269. package/src/orchestrator/flow-runner.js +0 -365
  270. package/src/orchestrator/fs-leak-detector.js +0 -228
  271. package/src/orchestrator/hu-scheduler.js +0 -114
  272. package/src/orchestrator/hu-sub-pipeline.js +0 -642
  273. package/src/orchestrator/iteration-gate.js +0 -73
  274. package/src/orchestrator/iteration-stages.js +0 -9
  275. package/src/orchestrator/parallel-limiter.js +0 -74
  276. package/src/orchestrator/pipeline-context.js +0 -72
  277. package/src/orchestrator/post-loop-stages.js +0 -468
  278. package/src/orchestrator/pre-loop-stages.js +0 -11
  279. package/src/orchestrator/preflight-checks.js +0 -487
  280. package/src/orchestrator/repair/repair-detector.js +0 -117
  281. package/src/orchestrator/repair/repair-runner.js +0 -142
  282. package/src/orchestrator/reviewer-fallback.js +0 -45
  283. package/src/orchestrator/role-output-compressor.js +0 -189
  284. package/src/orchestrator/session-journal.js +0 -308
  285. package/src/orchestrator/solomon-escalation.js +0 -331
  286. package/src/orchestrator/solomon-rules.js +0 -212
  287. package/src/orchestrator/stages/acceptance-coverage-stage.js +0 -47
  288. package/src/orchestrator/stages/architect-stage.js +0 -172
  289. package/src/orchestrator/stages/coder-stage.js +0 -506
  290. package/src/orchestrator/stages/domain-curator-stage.js +0 -82
  291. package/src/orchestrator/stages/format-stage.js +0 -61
  292. package/src/orchestrator/stages/hu-reviewer-phases/detect-and-apply-splits.js +0 -127
  293. package/src/orchestrator/stages/hu-reviewer-stage.js +0 -419
  294. package/src/orchestrator/stages/perf-stage.js +0 -140
  295. package/src/orchestrator/stages/planner-stage.js +0 -85
  296. package/src/orchestrator/stages/rag-context-stage.js +0 -80
  297. package/src/orchestrator/stages/rag-preload-decisor.js +0 -58
  298. package/src/orchestrator/stages/research-stage.js +0 -69
  299. package/src/orchestrator/stages/reviewer-stage.js +0 -431
  300. package/src/orchestrator/stages/sonar-stage.js +0 -439
  301. package/src/orchestrator/stages/stage-classes.js +0 -84
  302. package/src/orchestrator/stages/stage-executor.js +0 -155
  303. package/src/orchestrator/stages/suite-green-stage.js +0 -62
  304. package/src/orchestrator/stages/tdd-discipline-stage.js +0 -56
  305. package/src/orchestrator/stages/tool-judge-stage.js +0 -53
  306. package/src/orchestrator/stages/triage-stage.js +0 -172
  307. package/src/orchestrator/standby.js +0 -71
  308. package/src/orchestrator/verification-gate.js +0 -183
  309. package/src/orchestrator.js +0 -22
  310. package/src/plan/adr-generator.js +0 -170
  311. package/src/plan/adr-loader.js +0 -60
  312. package/src/plan/plan-executor.js +0 -100
  313. package/src/plan/plan-validation.js +0 -4
  314. package/src/prompts/acceptance-coverage.js +0 -32
  315. package/src/prompts/arbiter.js +0 -38
  316. package/src/prompts/architect.js +0 -103
  317. package/src/prompts/hu-reviewer.js +0 -244
  318. package/src/prompts/tool-correctness-judge.js +0 -31
  319. package/src/prompts/triage.js +0 -57
  320. package/src/rag/embedder.js +0 -2
  321. package/src/rag/embedders/_cloud-base.js +0 -2
  322. package/src/rag/embedders/cohere.js +0 -2
  323. package/src/rag/embedders/mistral.js +0 -2
  324. package/src/rag/embedders/onnx.js +0 -2
  325. package/src/rag/embedders/openai.js +0 -2
  326. package/src/rag/embedders/voyage.js +0 -2
  327. package/src/rag/rerank.js +0 -4
  328. package/src/rag/where-parser.js +0 -4
  329. package/src/repeat-detector.js +0 -88
  330. package/src/review/diff-generator.js +0 -112
  331. package/src/review/git-stash-helper.js +0 -104
  332. package/src/review/schema.js +0 -31
  333. package/src/review/scope-filter.js +0 -152
  334. package/src/review/snapshot-diff.js +0 -122
  335. package/src/review/tdd-discipline.js +0 -90
  336. package/src/review/tdd-policy.js +0 -69
  337. package/src/roles/acceptance-coverage-role.js +0 -78
  338. package/src/roles/architect-role.js +0 -77
  339. package/src/roles/coder-role.js +0 -113
  340. package/src/roles/commiter-role.js +0 -113
  341. package/src/roles/domain-curator-role.js +0 -134
  342. package/src/roles/hu-reviewer-role.js +0 -64
  343. package/src/roles/impeccable-role.js +0 -85
  344. package/src/roles/index.js +0 -18
  345. package/src/roles/karajan-brain-role.js +0 -134
  346. package/src/roles/perf-role.js +0 -122
  347. package/src/roles/planner-role.js +0 -151
  348. package/src/roles/refactorer-role.js +0 -30
  349. package/src/roles/repairer-role.js +0 -181
  350. package/src/roles/researcher-role.js +0 -70
  351. package/src/roles/reviewer-role.js +0 -115
  352. package/src/roles/security-role.js +0 -73
  353. package/src/roles/solomon-role.js +0 -271
  354. package/src/roles/sonar-role.js +0 -72
  355. package/src/roles/tester-role.js +0 -235
  356. package/src/roles/tool-correctness-judge-role.js +0 -78
  357. package/src/roles/triage-role.js +0 -99
  358. package/src/session/journal/decisions-writer.js +0 -200
  359. package/src/session/journal/iteration-logger.js +0 -194
  360. package/src/session/journal/summary-writer.js +0 -320
  361. package/src/session/journal/tree-writer.js +0 -164
  362. package/src/session/journal/write-all.js +0 -89
  363. package/src/session-cleanup.js +0 -116
  364. package/src/skills/semantic-detector.js +0 -167
  365. package/src/skills/skill-detector.js +0 -385
  366. package/src/sonar/cloud-scanner.js +0 -78
  367. package/src/tracker-bootstrap.js +0 -44
  368. package/src/types/index.js +0 -38
  369. package/src/types/policy.js +0 -43
  370. package/src/types/solomon.js +0 -87
  371. package/src/utils/async-lock.js +0 -31
  372. package/src/utils/budget.js +0 -229
  373. package/src/utils/cwd-confirm.js +0 -39
  374. package/src/utils/display/event-handlers.js +0 -403
  375. package/src/utils/display/formatters.js +0 -132
  376. package/src/utils/display/header.js +0 -47
  377. package/src/utils/display/session-summary.js +0 -118
  378. package/src/utils/display/solomon.js +0 -42
  379. package/src/utils/pricing.js +0 -29
  380. package/src/utils/quota-simulator.js +0 -56
  381. package/src/utils/role-assigner.js +0 -137
  382. package/src/utils/rtk-wrapper.js +0 -87
  383. package/src/utils/run-registry.js +0 -9
  384. package/src/utils/status-dashboard.js +0 -254
  385. package/src/utils/tool-call-extractor.js +0 -56
  386. package/src/webperf/devtools-detect.js +0 -112
  387. package/src/webperf/webperf-role-integration.js +0 -66
  388. package/templates/skills/kj-run.md +0 -73
@@ -1,431 +0,0 @@
1
- /**
2
- * Reviewer stage logic + fetchReviewDiff.
3
- * Extracted from iteration-stages.js for maintainability.
4
- */
5
-
6
- import { addCheckpoint, markSessionStatus, saveSession } from "../../session/store.js";
7
- import { setReviewerFeedback, setDeferredIssues } from "../../session/mutators.js";
8
- import { generateDiff } from "../../review/diff-generator.js";
9
- import { redactSecrets } from "../../guards/secret-redactor.js";
10
- import { validateReviewResult } from "../../review/schema.js";
11
- import { filterReviewScope } from "../../review/scope-filter.js";
12
- import { emitProgress, makeEvent, emitAgentOutput } from "../../utils/events.js";
13
- import { runReviewerWithFallback } from "../reviewer-fallback.js";
14
- import { invokeSolomon } from "../solomon-escalation.js";
15
- import { detectRateLimit } from "../../utils/rate-limit-detector.js";
16
- import { createStallDetector } from "../../utils/stall-detector.js";
17
- import { applyQuotaSimulation } from "../../utils/quota-simulator.js";
18
- import { correctionNote } from "../../review/correction-rounds.js";
19
-
20
- function categorizeIssues(issues) {
21
- const categories = { security: 0, correctness: 0, tests: 0, style: 0, other: 0 };
22
- const securityKw = /inject(?:ion)?|xss|csrf|secret.?leak|credential.?expos|auth(?:entication|orization).?(?:bypass|fail|miss|broken|weak)|vulnerab|exploit|httponly|token.?expos/i;
23
- const styleKw = /naming|name|rename|style|format|indent|spacing|convention|cosmetic|readability|comment|jsdoc|whitespace/i;
24
- const testKw = /test|coverage|assert|spec|mock/i;
25
-
26
- for (const issue of issues || []) {
27
- const desc = issue.description || "";
28
- const sev = (issue.severity || "").toLowerCase();
29
- if (sev === "critical" || securityKw.test(desc)) categories.security++;
30
- else if (testKw.test(desc)) categories.tests++;
31
- else if (sev === "low" || sev === "minor" || styleKw.test(desc)) categories.style++;
32
- else categories.correctness++;
33
- }
34
- return categories;
35
- }
36
-
37
- // KJC-TSK-1017: the rejections before an approval are review corrections.
38
- export function approvedMessage(session) {
39
- const rejections = (session.checkpoints || []).filter((cp) => cp.stage === "reviewer" && cp.approved === false).length;
40
- return ["Review approved", correctionNote(rejections)].filter(Boolean).join(" — ");
41
- }
42
-
43
- function buildReviewHistory(session) {
44
- return (session.checkpoints || [])
45
- .filter(cp => cp.stage === "reviewer")
46
- .map(cp => ({ iteration: cp.iteration, note: cp.note || "" }));
47
- }
48
-
49
- async function handleReviewerStalledSolomon({ review, repeatCounts, repeatState, config, logger, emitter, eventBase, session, iteration, task, askQuestion, budgetSummary, repeatDetector, brainCtx }) {
50
- // DETERMINISTIC GUARD: security issues NEVER go to Solomon — always return to coder
51
- const categories = categorizeIssues(review.blocking_issues);
52
- if (categories.security > 0) {
53
- logger.info(`Reviewer found ${categories.security} security issue(s) — returning to coder (Solomon bypassed)`);
54
- emitProgress(emitter, makeEvent("reviewer:security-block", { ...eventBase, stage: "reviewer" }, {
55
- message: `${categories.security} security issue(s) detected — must be fixed before approval`,
56
- detail: { securityCount: categories.security, blockingIssues: review.blocking_issues }
57
- }));
58
- return { review, solomonApproved: false };
59
- }
60
-
61
- // Brain: when enabled, ALL paths go through Brain, not Solomon
62
- if (brainCtx?.enabled) {
63
- const logPrefix = repeatState.stalled
64
- ? `Reviewer stalled (${repeatCounts.reviewer} repeats)`
65
- : `Reviewer rejected (first rejection)`;
66
- logger.info(`Brain: ${logPrefix} — Brain will handle (Solomon bypassed)`);
67
- emitProgress(emitter, makeEvent("brain:escalate", { ...eventBase, stage: "reviewer" }, {
68
- message: `${logPrefix} — Brain handling`,
69
- detail: { repeats: repeatCounts.reviewer || 1, reason: repeatState.reason || "first_rejection" }
70
- }));
71
- // Push reviewer feedback into Brain queue
72
- const { processRoleOutput } = await import("../brain-coordinator.js");
73
- processRoleOutput(brainCtx, { roleName: "reviewer", output: review, iteration });
74
- return { review, solomonApproved: false };
75
- }
76
-
77
- const logPrefix = repeatState.stalled
78
- ? `Reviewer stalled (${repeatCounts.reviewer} repeats)`
79
- : `Reviewer rejected (first rejection)`;
80
- logger.warn(`${logPrefix}. Invoking Solomon mediation.`);
81
- emitProgress(
82
- emitter,
83
- makeEvent("solomon:escalate", { ...eventBase, stage: "reviewer" }, {
84
- message: `${logPrefix} — Solomon mediating`,
85
- detail: { repeats: repeatCounts.reviewer || 1, reason: repeatState.reason || "first_rejection" }
86
- })
87
- );
88
-
89
- const solomonResult = await invokeSolomon({
90
- config, logger, emitter, eventBase, stage: "reviewer", askQuestion, session, iteration,
91
- conflict: {
92
- stage: "reviewer",
93
- task,
94
- iterationCount: repeatCounts.reviewer || 1,
95
- maxIterations: config.session?.fail_fast_repeats ?? 2,
96
- isFirstRejection: !repeatState.stalled,
97
- isRepeat: repeatState.stalled,
98
- stalledReason: repeatState.reason || "first_rejection",
99
- blockingIssues: review.blocking_issues,
100
- issueCategories: categorizeIssues(review.blocking_issues),
101
- history: [
102
- ...buildReviewHistory(session),
103
- { agent: "reviewer", feedback: review.blocking_issues.map(x => x.description).join("; ") }
104
- ]
105
- }
106
- });
107
-
108
- if (solomonResult.action === "approve") {
109
- logger.info("Solomon overrode reviewer — approving code");
110
- emitProgress(emitter, makeEvent("solomon:override", { ...eventBase, stage: "solomon" }, {
111
- message: "Solomon overrode reviewer rejection — code approved",
112
- detail: { ruling: solomonResult.ruling?.result?.ruling }
113
- }));
114
- return { review: { ...review, approved: true, solomon_override: true }, solomonApproved: true };
115
- }
116
- if (solomonResult.action === "pause") {
117
- await markSessionStatus(session, "stalled");
118
- return { review, stalled: true, stalledResult: { paused: true, sessionId: session.id, question: solomonResult.question, context: "reviewer_stalled" } };
119
- }
120
- if (solomonResult.action === "continue") {
121
- repeatDetector.reviewer = { lastHash: null, repeatCount: 0 };
122
- if (solomonResult.humanGuidance) {
123
- setReviewerFeedback(session, `Solomon/user guidance: ${solomonResult.humanGuidance}`);
124
- await saveSession(session);
125
- }
126
- return { review };
127
- }
128
- if (solomonResult.action === "subtask") {
129
- return { review, stalled: true, stalledResult: { paused: true, sessionId: session.id, subtask: solomonResult.subtask, context: "reviewer_subtask" } };
130
- }
131
-
132
- // Fallback
133
- const message = `Manual intervention required: reviewer issues repeated ${repeatCounts.reviewer || 1} times.`;
134
- await markSessionStatus(session, "stalled");
135
- emitProgress(
136
- emitter,
137
- makeEvent("session:end", { ...eventBase, stage: "reviewer" }, {
138
- status: "stalled",
139
- message,
140
- detail: { reason: repeatState.reason, repeats: repeatCounts.reviewer, budget: budgetSummary() }
141
- })
142
- );
143
- return { review, stalled: true, stalledResult: { approved: false, sessionId: session.id, reason: "stalled" } };
144
- }
145
-
146
- async function handleReviewerRejection({ review, repeatDetector, config, logger, emitter, eventBase, session, iteration, task, askQuestion, budgetSummary, brainCtx }) {
147
- repeatDetector.addIteration([], review.blocking_issues);
148
- const repeatState = repeatDetector.isStalled();
149
-
150
- const solomonEnabled = Boolean(config.pipeline?.solomon?.enabled);
151
-
152
- // Brain: if enabled and bypass_solomon_on_correctness, push issues to queue and skip Solomon
153
- // for non-style rejections. Solomon is still consulted on genuine dilemmas (style-only, deadlock).
154
- if (brainCtx?.enabled && config.brain?.bypass_solomon_on_correctness !== false) {
155
- const cats = categorizeIssues(review.blocking_issues);
156
- const nonStyleIssues = cats.security + cats.correctness + cats.tests;
157
- // Only bypass if there ARE non-style issues (correctness, tests, security, or "other" is correctness)
158
- // If it's style-only, let Solomon evaluate whether to override
159
- if (nonStyleIssues > 0 || cats.other > 0) {
160
- const { processRoleOutput } = await import("../brain-coordinator.js");
161
- processRoleOutput(brainCtx, { roleName: "reviewer", output: review, iteration });
162
- logger.info(`Brain: reviewer rejected with ${nonStyleIssues} non-style issue(s) — bypassing Solomon, returning to coder`);
163
- emitProgress(emitter, makeEvent("brain:bypass-solomon", { ...eventBase, stage: "reviewer" }, {
164
- message: `Brain: ${nonStyleIssues} non-style issue(s) — sending to coder without Solomon`,
165
- detail: { categories: cats, queueSize: brainCtx.feedbackQueue.entries.length }
166
- }));
167
- // Persist flat feedback for compat with non-Brain flow
168
- setReviewerFeedback(session, review.blocking_issues
169
- .map((x, idx) => `R-${idx + 1} [${x.severity || "medium"}]: ${x.description}`)
170
- .join("\n"));
171
- await saveSession(session);
172
- return null; // null = continue to next iteration (coder fixes)
173
- }
174
- logger.info("Brain: reviewer rejected with style-only issues — consulting Solomon for dilemma");
175
- }
176
-
177
- // When Solomon is disabled, only act on stalls (legacy behavior)
178
- if (!solomonEnabled) {
179
- if (!repeatState.stalled) return null;
180
- const repeatCounts = repeatDetector.getRepeatCounts();
181
- return handleReviewerStalledSolomon({
182
- review, repeatCounts, repeatState, config, logger, emitter,
183
- eventBase, session, iteration, task, askQuestion,
184
- budgetSummary, repeatDetector, brainCtx
185
- });
186
- }
187
-
188
- // Solomon evaluates EVERY rejection
189
- const repeatCounts = repeatDetector.getRepeatCounts();
190
- const evaluateEventName = brainCtx?.enabled ? "brain:evaluate" : "solomon:evaluate";
191
- logger.info(`Reviewer rejected — ${brainCtx?.enabled ? "Brain" : "Solomon"} evaluating ${review.blocking_issues.length} blocking issue(s)`);
192
- emitProgress(emitter, makeEvent(evaluateEventName, { ...eventBase, stage: brainCtx?.enabled ? "brain" : "solomon" }, {
193
- message: `${brainCtx?.enabled ? "Brain" : "Solomon"} evaluating reviewer rejection`,
194
- detail: { blockingCount: review.blocking_issues.length, isRepeat: repeatState.stalled }
195
- }));
196
-
197
- return handleReviewerStalledSolomon({
198
- review, repeatCounts, repeatState, config, logger, emitter,
199
- eventBase, session, iteration, task, askQuestion,
200
- budgetSummary, repeatDetector, brainCtx
201
- });
202
- }
203
-
204
- export async function fetchReviewDiff(session, logger, projectDir = null) {
205
- let diff;
206
- if (session.ci_pr_number) {
207
- const { getPrDiff } = await import("../../ci/pr-diff.js");
208
- diff = await getPrDiff(session.ci_pr_number);
209
- logger.info(`Reviewer reading PR diff #${session.ci_pr_number}`);
210
- } else {
211
- diff = await generateDiff({ baseRef: session.session_start_sha, stageNewFiles: true, projectDir });
212
- }
213
- // Inbound boundary: mask hardcoded secrets before the diff reaches the
214
- // (possibly cloud) reviewer model. Runs BEFORE the injection guard below so
215
- // that guard still sees the real prompt-injection phrasing (KJC-TSK-0583).
216
- return redactSecrets(diff);
217
- }
218
-
219
- export async function runReviewerStage({ reviewerRole, config, logger, emitter, eventBase, session, trackBudget, iteration, reviewRules, task, repeatDetector, budgetSummary, askQuestion, brainCtx }) {
220
- logger.setContext({ iteration, stage: "reviewer" });
221
- emitProgress(
222
- emitter,
223
- makeEvent("reviewer:start", { ...eventBase, stage: "reviewer" }, {
224
- message: `Reviewer (${reviewerRole.provider}) running`,
225
- detail: { reviewer: reviewerRole.provider, provider: reviewerRole.provider, executorType: "agent" }
226
- })
227
- );
228
-
229
- let diff;
230
- try {
231
- diff = await fetchReviewDiff(session, logger, config?.projectDir || null);
232
- } catch (err) {
233
- logger.warn(`Review diff generation failed: ${err.message}`);
234
- return { approved: false, blocking_issues: [{ description: `Diff generation failed: ${err.message}` }], non_blocking_suggestions: [], summary: `Reviewer failed: cannot generate diff — ${err.message}`, confidence: 0 };
235
- }
236
-
237
- // Injection guard: scan diff before sending to AI reviewer
238
- const { scanDiff } = await import("../../utils/injection-guard.js");
239
- const guardResult = scanDiff(diff);
240
- if (!guardResult.clean) {
241
- logger.warn(`Injection guard: ${guardResult.summary}`);
242
- emitProgress(emitter, makeEvent("guard:injection", { ...eventBase, stage: "reviewer" }, {
243
- message: `Injection guard blocked review: ${guardResult.summary}`,
244
- detail: { findings: guardResult.findings, summary: guardResult.summary }
245
- }));
246
- return {
247
- approved: false,
248
- blocking_issues: guardResult.findings.map((f) => ({
249
- id: `INJECTION_${f.type.toUpperCase()}`,
250
- severity: "critical",
251
- description: `Potential prompt injection (${f.type}): ${f.snippet}`,
252
- line: f.line,
253
- })),
254
- non_blocking_suggestions: [],
255
- summary: `Review blocked by injection guard: ${guardResult.summary}`,
256
- confidence: 1,
257
- };
258
- }
259
-
260
- const reviewerOnOutput = (payload) => emitAgentOutput(emitter, eventBase, "reviewer", reviewerRole.provider, payload);
261
- const reviewerStall = createStallDetector({
262
- onOutput: reviewerOnOutput, emitter, eventBase, stage: "reviewer", provider: reviewerRole.provider
263
- });
264
- const reviewerStart = Date.now();
265
- let reviewerExec;
266
- try {
267
- reviewerExec = await runReviewerWithFallback({
268
- reviewerName: reviewerRole.provider,
269
- config,
270
- logger,
271
- emitter,
272
- reviewInput: { task, diff, reviewRules, onOutput: reviewerStall.onOutput },
273
- session,
274
- iteration,
275
- onAttemptResult: ({ reviewer, result }) => {
276
- trackBudget({ role: "reviewer", provider: reviewer, model: reviewerRole.model, result, duration_ms: Date.now() - reviewerStart });
277
- }
278
- });
279
- } catch (err) {
280
- logger.warn(`Reviewer threw: ${err.message}`);
281
- reviewerExec = { execResult: { ok: false, error: err.message }, attempts: [{ reviewer: reviewerRole.provider, result: { ok: false, error: err.message } }] };
282
- } finally {
283
- reviewerStall.stop();
284
- }
285
-
286
- if (applyQuotaSimulation(reviewerExec.execResult, { iteration, agent: reviewerRole.provider })) {
287
- // Reviewer wraps the agent call: detectRateLimit reads `lastAttempt.result.error`,
288
- // so propagate the synthetic line into the most recent attempt too.
289
- const last = reviewerExec.attempts?.at(-1);
290
- if (last) {
291
- if (!last.result || typeof last.result !== "object") last.result = {};
292
- last.result.error = reviewerExec.execResult.result.error;
293
- }
294
- }
295
-
296
- if (!reviewerExec.execResult?.ok) {
297
- const lastAttempt = reviewerExec.attempts.at(-1);
298
- const details =
299
- lastAttempt?.result?.error ||
300
- lastAttempt?.execResult?.summary ||
301
- `reviewer=${lastAttempt?.reviewer || "unknown"}`;
302
-
303
- const rateLimitCheck = detectRateLimit({
304
- stderr: lastAttempt?.result?.error || "",
305
- stdout: lastAttempt?.result?.output || ""
306
- });
307
-
308
- if (rateLimitCheck.isRateLimit) {
309
- // Enter standby instead of pausing
310
- return {
311
- action: "standby",
312
- standbyInfo: {
313
- agent: reviewerRole.provider,
314
- cooldownMs: rateLimitCheck.cooldownMs || (rateLimitCheck.isProviderOutage ? 30000 : null),
315
- cooldownUntil: rateLimitCheck.cooldownUntil,
316
- message: rateLimitCheck.message,
317
- isProviderOutage: rateLimitCheck.isProviderOutage || false
318
- }
319
- };
320
- }
321
-
322
- await markSessionStatus(session, "failed");
323
- emitProgress(
324
- emitter,
325
- makeEvent("reviewer:end", { ...eventBase, stage: "reviewer" }, {
326
- status: "fail",
327
- message: `Reviewer failed: ${details}`,
328
- detail: { provider: reviewerRole.provider, executorType: "agent" }
329
- })
330
- );
331
- throw new Error(`Reviewer failed: ${details}`);
332
- }
333
-
334
- const reviewResult = reviewerExec.execResult.result;
335
- let review;
336
- try {
337
- review = validateReviewResult({
338
- approved: reviewResult.approved,
339
- blocking_issues: reviewResult.blocking_issues || [],
340
- non_blocking_suggestions: reviewResult.non_blocking_suggestions || [],
341
- summary: reviewResult.raw_summary || "",
342
- confidence: reviewResult.confidence ?? 0
343
- });
344
- } catch (error_) {
345
- // KJC-BUG-0284 (#1982): a verdict kj cannot read is the reviewer's failure,
346
- // never a PARSE_ERROR defect handed to the coder (it sent one run in circles).
347
- const details = `the verdict could not be read: ${error_.message}`;
348
- logger.warn(`Reviewer output validation failed: ${error_.message}`);
349
- await markSessionStatus(session, "failed");
350
- emitProgress(
351
- emitter,
352
- makeEvent("reviewer:end", { ...eventBase, stage: "reviewer" }, {
353
- status: "fail",
354
- message: `Reviewer failed: ${details}`,
355
- detail: { provider: reviewerRole.provider, executorType: "agent" }
356
- })
357
- );
358
- throw new Error(`Reviewer failed: ${details}`, { cause: error_ });
359
- }
360
- // --- Scope filter: auto-defer out-of-scope blocking issues ---
361
- const { review: filteredReview, demoted, deferred, allDemoted } = filterReviewScope(review, diff);
362
- review = filteredReview;
363
-
364
- if (demoted.length > 0) {
365
- logger.info(`Scope filter: deferred ${demoted.length} out-of-scope issue(s)${allDemoted ? " — auto-approved" : ""}`);
366
-
367
- // Accumulate deferred issues in session for tracking
368
- if (!session.deferred_issues) setDeferredIssues(session, []);
369
- session.deferred_issues.push(...deferred);
370
- await saveSession(session);
371
-
372
- emitProgress(
373
- emitter,
374
- makeEvent("reviewer:scope_filter", { ...eventBase, stage: "reviewer" }, {
375
- message: `Scope filter deferred ${demoted.length} out-of-scope issue(s)`,
376
- detail: {
377
- demotedCount: demoted.length,
378
- autoApproved: allDemoted,
379
- totalDeferred: session.deferred_issues.length,
380
- deferred: deferred.map(d => ({ file: d.file, id: d.id, description: d.description }))
381
- }
382
- })
383
- );
384
- await addCheckpoint(session, {
385
- stage: "reviewer-scope-filter",
386
- iteration,
387
- demoted_count: demoted.length,
388
- auto_approved: allDemoted,
389
- total_deferred: session.deferred_issues.length
390
- });
391
- }
392
-
393
- // Feedback signature for stale detection: concatenated issue descriptions
394
- const feedbackSignature = review.blocking_issues
395
- .map(x => (x.description || "").slice(0, 120))
396
- .join("|") || "approved";
397
-
398
- await addCheckpoint(session, {
399
- stage: "reviewer",
400
- iteration,
401
- approved: review.approved,
402
- blocking_issues: review.blocking_issues.length,
403
- provider: reviewerRole.provider,
404
- model: reviewerRole.model || null,
405
- note: feedbackSignature
406
- });
407
-
408
- emitProgress(
409
- emitter,
410
- makeEvent("reviewer:end", { ...eventBase, stage: "reviewer" }, {
411
- status: review.approved ? "ok" : "fail",
412
- message: review.approved ? approvedMessage(session) : `Review rejected (${review.blocking_issues.length} blocking)`,
413
- detail: {
414
- approved: review.approved,
415
- blockingCount: review.blocking_issues.length,
416
- issues: review.blocking_issues.map(
417
- (x) => `${x.id || "ISSUE"}: ${x.description || "Missing description"}`
418
- ),
419
- provider: reviewerRole.provider,
420
- executorType: "agent"
421
- }
422
- })
423
- );
424
-
425
- if (!review.approved) {
426
- const rejectionResult = await handleReviewerRejection({ review, repeatDetector, config, logger, emitter, eventBase, session, iteration, task, askQuestion, budgetSummary, brainCtx });
427
- if (rejectionResult) return rejectionResult;
428
- }
429
-
430
- return { review };
431
- }