karajan-code 4.70.4 → 5.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (390) 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/dir-setup.js +34 -1
  61. package/src/checks/native-build.js +21 -39
  62. package/src/checks/runner.js +128 -142
  63. package/src/cli/advanced-commands.js +6 -6
  64. package/src/cli/register-meta.js +42 -82
  65. package/src/cli/register-pipeline.js +8 -143
  66. package/src/cli/register-plan.js +9 -100
  67. package/src/cli/register-roles-skills.js +1 -1
  68. package/src/cli/retired-commands.js +49 -0
  69. package/src/cli.js +18 -5
  70. package/src/commands/agent-run.js +40 -26
  71. package/src/commands/audit.js +127 -124
  72. package/src/commands/board.js +5 -9
  73. package/src/commands/check.js +29 -16
  74. package/src/commands/doctor.js +2 -0
  75. package/src/commands/env.js +176 -150
  76. package/src/commands/go.js +71 -53
  77. package/src/commands/harden.js +90 -81
  78. package/src/commands/hu-start.js +52 -0
  79. package/src/commands/hu.js +288 -221
  80. package/src/commands/identity.js +111 -78
  81. package/src/commands/init-atril.js +47 -0
  82. package/src/commands/init.js +11 -40
  83. package/src/commands/install-tools.js +70 -85
  84. package/src/commands/main-guard.js +78 -0
  85. package/src/commands/policy.js +226 -184
  86. package/src/commands/qmd.js +27 -21
  87. package/src/commands/rag.js +121 -55
  88. package/src/commands/review-gate.js +421 -341
  89. package/src/commands/skills.js +4 -1
  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 +107 -26
  94. package/src/config/defaults.js +1 -0
  95. package/src/config/loader.js +34 -17
  96. package/src/config/role-resolver.js +1 -0
  97. package/src/config/schema.js +1 -0
  98. package/src/config/secrets.js +36 -0
  99. package/src/config.js +1 -0
  100. package/src/environment/adr.js +16 -2
  101. package/src/git/karajan-label.js +20 -8
  102. package/src/guards/main-guard.js +54 -0
  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 +64 -36
  106. package/src/harden/sentinel/sentinel-lib.mjs +129 -26
  107. package/src/harden/sentinel/sentinel-shell.mjs +5 -16
  108. package/src/harden/sentinel/sessionstart.mjs +3 -2
  109. package/src/harden/sentinel/stop.mjs +5 -4
  110. package/src/harden/workflow-templates.js +1 -1
  111. package/src/hu/board-lookup.js +29 -0
  112. package/src/hu/gh-identity.js +23 -0
  113. package/src/hu/github-board.js +4 -2
  114. package/src/hu/lane-prune.js +83 -13
  115. package/src/hu/lane-setup.js +65 -0
  116. package/src/hu/lanes.js +66 -0
  117. package/src/hu/team-board-mirror.js +3 -2
  118. package/src/infrastructure/command-runner.js +1 -1
  119. package/src/infrastructure/file-system-service.js +1 -1
  120. package/src/mcp/handlers/direct-handlers.js +2 -292
  121. package/src/mcp/handlers/hu-handlers.js +1 -35
  122. package/src/mcp/handlers/management-handlers.js +2 -42
  123. package/src/mcp/handlers/rag-handler.js +9 -1
  124. package/src/mcp/server-handlers.js +16 -22
  125. package/src/mcp/tools.js +1 -196
  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 +71 -44
  134. package/src/rag/bootstrap-index.js +46 -54
  135. package/src/rag/indexer.js +9 -4
  136. package/src/rag/migrate.js +1 -1
  137. package/src/rag/onnx-fallback.js +2 -2
  138. package/src/rag/pid-lease.js +181 -0
  139. package/src/rag/project-store.js +2 -12
  140. package/src/review/card-first.js +57 -46
  141. package/src/review/gate-gitignore.js +23 -4
  142. package/src/review/gate-hook.js +12 -4
  143. package/src/review/one-shot-review.js +45 -35
  144. package/src/review/publish-pr.js +14 -2
  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 +19 -4
  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 +1 -24
  154. package/src/roles/audit-role.js +106 -125
  155. package/src/skills/atril-cli.js +19 -1
  156. package/src/skills/atril-skills.js +5 -4
  157. package/src/skills/skills-search.js +72 -0
  158. package/src/skills/translate.js +62 -0
  159. package/src/sonar/scanner.js +116 -101
  160. package/src/steward/invariants.js +5 -4
  161. package/src/steward/phantom-sweep.js +66 -0
  162. package/src/tournament/judge.js +60 -53
  163. package/src/utils/gh-account.js +37 -0
  164. package/src/utils/git.js +0 -13
  165. package/src/utils/home-migration.js +7 -1
  166. package/src/utils/main-checkout.js +53 -0
  167. package/src/utils/qmd-collection.js +3 -1
  168. package/src/utils/welcome.js +3 -3
  169. package/templates/{skills → atril/commands}/kj-architect.md +5 -0
  170. package/templates/{skills → atril/commands}/kj-audit.md +5 -0
  171. package/templates/{skills → atril/commands}/kj-board.md +5 -0
  172. package/templates/{skills → atril/commands}/kj-code.md +5 -0
  173. package/templates/{skills → atril/commands}/kj-csv-transform.md +5 -0
  174. package/templates/{skills → atril/commands}/kj-data-report.md +5 -0
  175. package/templates/{skills → atril/commands}/kj-discover.md +5 -0
  176. package/templates/{skills → atril/commands}/kj-rag-query.md +5 -0
  177. package/templates/{skills → atril/commands}/kj-review.md +5 -0
  178. package/templates/{skills → atril/commands}/kj-security.md +5 -0
  179. package/templates/{skills → atril/commands}/kj-sonar.md +5 -0
  180. package/templates/{skills → atril/commands}/kj-sql-analysis.md +5 -0
  181. package/templates/{skills → atril/commands}/kj-test.md +5 -0
  182. package/packages/hu-board/public/utils/run-launcher.js +0 -169
  183. package/packages/hu-board/src/run-tracker.js +0 -121
  184. package/src/activity-log.js +0 -59
  185. package/src/agents/host-agent.js +0 -38
  186. package/src/agents/model-registry.js +0 -142
  187. package/src/audit/plan-adherence.js +0 -224
  188. package/src/autonomy/arbiter-role.js +0 -71
  189. package/src/autonomy/arbiter.js +0 -22
  190. package/src/autonomy/decider.js +0 -18
  191. package/src/autonomy/decision-resolver.js +0 -58
  192. package/src/autonomy/outcome-report.js +0 -55
  193. package/src/autonomy/stage-ask.js +0 -30
  194. package/src/brain/decision-tracker.js +0 -125
  195. package/src/brain/decisor.js +0 -243
  196. package/src/brain/solomon-consult.js +0 -171
  197. package/src/brain/standby-scheduler.js +0 -8
  198. package/src/budget/comparison.js +0 -96
  199. package/src/canvas/parse-md.js +0 -238
  200. package/src/canvas/schema.js +0 -101
  201. package/src/canvas/to-flat.js +0 -85
  202. package/src/canvas/validate.js +0 -163
  203. package/src/ci/dispatch.js +0 -99
  204. package/src/ci/index.js +0 -3
  205. package/src/ci/pr-diff.js +0 -26
  206. package/src/cli/register-standby.js +0 -26
  207. package/src/commands/architect.js +0 -111
  208. package/src/commands/autorun.js +0 -49
  209. package/src/commands/researcher.js +0 -54
  210. package/src/commands/resume.js +0 -72
  211. package/src/commands/review.js +0 -89
  212. package/src/commands/run.js +0 -185
  213. package/src/commands/standby.js +0 -117
  214. package/src/commands/status.js +0 -36
  215. package/src/commands/triage.js +0 -78
  216. package/src/commands/undo.js +0 -62
  217. package/src/domains/domain-loader.js +0 -245
  218. package/src/domains/domain-registry.js +0 -140
  219. package/src/domains/domain-synthesizer.js +0 -129
  220. package/src/git/automation.js +0 -433
  221. package/src/git/coder-commit-guard.js +0 -40
  222. package/src/git/hu-automation.js +0 -243
  223. package/src/git/hu-snapshot.js +0 -10
  224. package/src/git/symlink-targets.js +0 -57
  225. package/src/golden/asserter.js +0 -92
  226. package/src/golden/loader.js +0 -52
  227. package/src/golden/runner.js +0 -92
  228. package/src/golden/schema.js +0 -41
  229. package/src/guards/duplicate-members.js +0 -86
  230. package/src/guards/intent-guard.js +0 -161
  231. package/src/guards/perf-guard.js +0 -126
  232. package/src/guards/policy-guard.js +0 -90
  233. package/src/guards/policy-resolver.js +0 -85
  234. package/src/guards/secret-redactor.js +0 -71
  235. package/src/hu/acceptance-runner.js +0 -138
  236. package/src/hu/lazy-planner.js +0 -109
  237. package/src/hu/parallel-executor.js +0 -94
  238. package/src/hu/routing-metrics.js +0 -17
  239. package/src/hu/split-validator.js +0 -143
  240. package/src/hu/splitting-detector.js +0 -158
  241. package/src/hu/splitting-generator.js +0 -175
  242. package/src/hu/store.js +0 -394
  243. package/src/infrastructure/mocks.js +0 -182
  244. package/src/mcp/handlers/run-handler.js +0 -318
  245. package/src/mcp/sovereignty-guard.js +0 -113
  246. package/src/mcp/tool-arg-normalizers.js +0 -16
  247. package/src/mutate/reviewer-signal.js +0 -76
  248. package/src/orchestrator/agent-fallback.js +0 -81
  249. package/src/orchestrator/brain-coordinator.js +0 -186
  250. package/src/orchestrator/ci-integration.js +0 -139
  251. package/src/orchestrator/config-init.js +0 -426
  252. package/src/orchestrator/direct-actions.js +0 -217
  253. package/src/orchestrator/drivers/error-recovery.js +0 -287
  254. package/src/orchestrator/drivers/init-context.js +0 -238
  255. package/src/orchestrator/drivers/iteration-loop.js +0 -382
  256. package/src/orchestrator/drivers/iteration-phases/coder-and-refactorer.js +0 -69
  257. package/src/orchestrator/drivers/iteration-phases/guards.js +0 -91
  258. package/src/orchestrator/drivers/iteration-phases/handle-approved.js +0 -29
  259. package/src/orchestrator/drivers/iteration-phases/quality-gates.js +0 -125
  260. package/src/orchestrator/drivers/iteration-phases/reviewer-gate.js +0 -62
  261. package/src/orchestrator/drivers/post-loop.js +0 -404
  262. package/src/orchestrator/drivers/pre-loop-phases/auto-hu-batch.js +0 -137
  263. package/src/orchestrator/drivers/pre-loop-phases/config-deprecations.js +0 -47
  264. package/src/orchestrator/drivers/pre-loop-phases/ensure-addyosmani-skills.js +0 -84
  265. package/src/orchestrator/drivers/pre-loop-phases/inject-loaded-plan.js +0 -393
  266. package/src/orchestrator/drivers/pre-loop.js +0 -524
  267. package/src/orchestrator/drivers/run-hu-batch.js +0 -468
  268. package/src/orchestrator/feedback-enrichment.js +0 -140
  269. package/src/orchestrator/feedback-queue.js +0 -151
  270. package/src/orchestrator/flow-control.js +0 -170
  271. package/src/orchestrator/flow-runner.js +0 -365
  272. package/src/orchestrator/fs-leak-detector.js +0 -228
  273. package/src/orchestrator/hu-scheduler.js +0 -114
  274. package/src/orchestrator/hu-sub-pipeline.js +0 -642
  275. package/src/orchestrator/iteration-gate.js +0 -73
  276. package/src/orchestrator/iteration-stages.js +0 -9
  277. package/src/orchestrator/parallel-limiter.js +0 -74
  278. package/src/orchestrator/pipeline-context.js +0 -72
  279. package/src/orchestrator/post-loop-stages.js +0 -468
  280. package/src/orchestrator/pre-loop-stages.js +0 -11
  281. package/src/orchestrator/preflight-checks.js +0 -487
  282. package/src/orchestrator/repair/repair-detector.js +0 -117
  283. package/src/orchestrator/repair/repair-runner.js +0 -142
  284. package/src/orchestrator/reviewer-fallback.js +0 -45
  285. package/src/orchestrator/role-output-compressor.js +0 -189
  286. package/src/orchestrator/session-journal.js +0 -308
  287. package/src/orchestrator/solomon-escalation.js +0 -331
  288. package/src/orchestrator/solomon-rules.js +0 -212
  289. package/src/orchestrator/stages/acceptance-coverage-stage.js +0 -47
  290. package/src/orchestrator/stages/architect-stage.js +0 -172
  291. package/src/orchestrator/stages/coder-stage.js +0 -506
  292. package/src/orchestrator/stages/domain-curator-stage.js +0 -82
  293. package/src/orchestrator/stages/format-stage.js +0 -61
  294. package/src/orchestrator/stages/hu-reviewer-phases/detect-and-apply-splits.js +0 -127
  295. package/src/orchestrator/stages/hu-reviewer-stage.js +0 -419
  296. package/src/orchestrator/stages/perf-stage.js +0 -140
  297. package/src/orchestrator/stages/planner-stage.js +0 -85
  298. package/src/orchestrator/stages/rag-context-stage.js +0 -80
  299. package/src/orchestrator/stages/rag-preload-decisor.js +0 -58
  300. package/src/orchestrator/stages/research-stage.js +0 -69
  301. package/src/orchestrator/stages/reviewer-stage.js +0 -431
  302. package/src/orchestrator/stages/sonar-stage.js +0 -439
  303. package/src/orchestrator/stages/stage-classes.js +0 -84
  304. package/src/orchestrator/stages/stage-executor.js +0 -155
  305. package/src/orchestrator/stages/suite-green-stage.js +0 -62
  306. package/src/orchestrator/stages/tdd-discipline-stage.js +0 -56
  307. package/src/orchestrator/stages/tool-judge-stage.js +0 -53
  308. package/src/orchestrator/stages/triage-stage.js +0 -172
  309. package/src/orchestrator/standby.js +0 -71
  310. package/src/orchestrator/verification-gate.js +0 -183
  311. package/src/orchestrator.js +0 -22
  312. package/src/plan/adr-generator.js +0 -170
  313. package/src/plan/adr-loader.js +0 -60
  314. package/src/plan/plan-executor.js +0 -100
  315. package/src/plan/plan-validation.js +0 -4
  316. package/src/prompts/acceptance-coverage.js +0 -32
  317. package/src/prompts/arbiter.js +0 -38
  318. package/src/prompts/architect.js +0 -103
  319. package/src/prompts/hu-reviewer.js +0 -244
  320. package/src/prompts/tool-correctness-judge.js +0 -31
  321. package/src/prompts/triage.js +0 -57
  322. package/src/rag/embedder.js +0 -2
  323. package/src/rag/embedders/_cloud-base.js +0 -2
  324. package/src/rag/embedders/cohere.js +0 -2
  325. package/src/rag/embedders/mistral.js +0 -2
  326. package/src/rag/embedders/onnx.js +0 -2
  327. package/src/rag/embedders/openai.js +0 -2
  328. package/src/rag/embedders/voyage.js +0 -2
  329. package/src/rag/rerank.js +0 -4
  330. package/src/rag/where-parser.js +0 -4
  331. package/src/repeat-detector.js +0 -88
  332. package/src/review/diff-generator.js +0 -112
  333. package/src/review/git-stash-helper.js +0 -104
  334. package/src/review/schema.js +0 -31
  335. package/src/review/scope-filter.js +0 -152
  336. package/src/review/snapshot-diff.js +0 -122
  337. package/src/review/tdd-discipline.js +0 -90
  338. package/src/review/tdd-policy.js +0 -69
  339. package/src/roles/acceptance-coverage-role.js +0 -78
  340. package/src/roles/architect-role.js +0 -77
  341. package/src/roles/coder-role.js +0 -113
  342. package/src/roles/commiter-role.js +0 -113
  343. package/src/roles/domain-curator-role.js +0 -134
  344. package/src/roles/hu-reviewer-role.js +0 -64
  345. package/src/roles/impeccable-role.js +0 -85
  346. package/src/roles/index.js +0 -18
  347. package/src/roles/karajan-brain-role.js +0 -134
  348. package/src/roles/perf-role.js +0 -122
  349. package/src/roles/planner-role.js +0 -151
  350. package/src/roles/refactorer-role.js +0 -30
  351. package/src/roles/repairer-role.js +0 -181
  352. package/src/roles/researcher-role.js +0 -70
  353. package/src/roles/reviewer-role.js +0 -115
  354. package/src/roles/security-role.js +0 -73
  355. package/src/roles/solomon-role.js +0 -271
  356. package/src/roles/sonar-role.js +0 -72
  357. package/src/roles/tester-role.js +0 -235
  358. package/src/roles/tool-correctness-judge-role.js +0 -78
  359. package/src/roles/triage-role.js +0 -99
  360. package/src/session/journal/decisions-writer.js +0 -200
  361. package/src/session/journal/iteration-logger.js +0 -194
  362. package/src/session/journal/summary-writer.js +0 -320
  363. package/src/session/journal/tree-writer.js +0 -164
  364. package/src/session/journal/write-all.js +0 -89
  365. package/src/session-cleanup.js +0 -116
  366. package/src/skills/semantic-detector.js +0 -167
  367. package/src/skills/skill-detector.js +0 -385
  368. package/src/sonar/cloud-scanner.js +0 -78
  369. package/src/tracker-bootstrap.js +0 -44
  370. package/src/types/index.js +0 -38
  371. package/src/types/policy.js +0 -43
  372. package/src/types/solomon.js +0 -87
  373. package/src/utils/async-lock.js +0 -31
  374. package/src/utils/budget.js +0 -229
  375. package/src/utils/cwd-confirm.js +0 -39
  376. package/src/utils/display/event-handlers.js +0 -403
  377. package/src/utils/display/formatters.js +0 -132
  378. package/src/utils/display/header.js +0 -47
  379. package/src/utils/display/session-summary.js +0 -118
  380. package/src/utils/display/solomon.js +0 -42
  381. package/src/utils/pricing.js +0 -29
  382. package/src/utils/quota-simulator.js +0 -56
  383. package/src/utils/role-assigner.js +0 -137
  384. package/src/utils/rtk-wrapper.js +0 -87
  385. package/src/utils/run-registry.js +0 -9
  386. package/src/utils/status-dashboard.js +0 -254
  387. package/src/utils/tool-call-extractor.js +0 -56
  388. package/src/webperf/devtools-detect.js +0 -112
  389. package/src/webperf/webperf-role-integration.js +0 -66
  390. 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
- }