@karajan-family/code 4.70.4 → 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 (380) 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/retired-commands.js +49 -0
  68. package/src/cli.js +18 -5
  69. package/src/commands/agent-run.js +40 -26
  70. package/src/commands/audit.js +127 -124
  71. package/src/commands/board.js +5 -9
  72. package/src/commands/check.js +29 -16
  73. package/src/commands/doctor.js +2 -0
  74. package/src/commands/env.js +176 -150
  75. package/src/commands/go.js +71 -53
  76. package/src/commands/harden.js +90 -81
  77. package/src/commands/hu-start.js +52 -0
  78. package/src/commands/hu.js +288 -221
  79. package/src/commands/identity.js +111 -78
  80. package/src/commands/init-atril.js +47 -0
  81. package/src/commands/init.js +11 -40
  82. package/src/commands/install-tools.js +70 -85
  83. package/src/commands/main-guard.js +78 -0
  84. package/src/commands/policy.js +226 -184
  85. package/src/commands/qmd.js +27 -21
  86. package/src/commands/rag.js +75 -48
  87. package/src/commands/review-gate.js +421 -341
  88. package/src/commands/start.js +4 -5
  89. package/src/commands/steward.js +96 -47
  90. package/src/commands/tournament.js +46 -37
  91. package/src/commands/worktree.js +94 -25
  92. package/src/config/loader.js +34 -17
  93. package/src/config/secrets.js +36 -0
  94. package/src/config.js +1 -0
  95. package/src/environment/adr.js +16 -2
  96. package/src/git/karajan-label.js +20 -8
  97. package/src/guards/main-guard.js +54 -0
  98. package/src/harden/hook-templates.js +16 -1
  99. package/src/harden/sentinel/posttooluse.mjs +18 -6
  100. package/src/harden/sentinel/pretooluse-sentinel.mjs +64 -36
  101. package/src/harden/sentinel/sentinel-lib.mjs +129 -26
  102. package/src/harden/sentinel/sentinel-shell.mjs +5 -16
  103. package/src/harden/sentinel/sessionstart.mjs +3 -2
  104. package/src/harden/sentinel/stop.mjs +5 -4
  105. package/src/harden/workflow-templates.js +1 -1
  106. package/src/hu/board-lookup.js +29 -0
  107. package/src/hu/gh-identity.js +23 -0
  108. package/src/hu/github-board.js +4 -2
  109. package/src/hu/lane-prune.js +15 -7
  110. package/src/hu/lane-setup.js +65 -0
  111. package/src/hu/lanes.js +66 -0
  112. package/src/hu/team-board-mirror.js +3 -2
  113. package/src/infrastructure/command-runner.js +1 -1
  114. package/src/infrastructure/file-system-service.js +1 -1
  115. package/src/mcp/handlers/direct-handlers.js +2 -292
  116. package/src/mcp/handlers/hu-handlers.js +1 -35
  117. package/src/mcp/handlers/management-handlers.js +2 -42
  118. package/src/mcp/server-handlers.js +16 -22
  119. package/src/mcp/tools.js +1 -196
  120. package/src/plan/lane-plans.js +54 -0
  121. package/src/plan/plan-store.js +7 -4
  122. package/src/policy/add.js +26 -12
  123. package/src/policy/adr-number-check.js +31 -0
  124. package/src/prompts/audit.js +299 -339
  125. package/src/prompts/card-context.js +10 -5
  126. package/src/prompts/reviewer.js +5 -2
  127. package/src/rag/auto-update.js +56 -43
  128. package/src/rag/bootstrap-index.js +28 -54
  129. package/src/rag/migrate.js +1 -1
  130. package/src/rag/onnx-fallback.js +2 -2
  131. package/src/rag/pid-lease.js +70 -0
  132. package/src/rag/project-store.js +2 -12
  133. package/src/review/card-first.js +57 -46
  134. package/src/review/gate-gitignore.js +23 -4
  135. package/src/review/gate-hook.js +12 -4
  136. package/src/review/one-shot-review.js +45 -35
  137. package/src/review/publish-pr.js +14 -2
  138. package/src/review/repo-docs.js +73 -0
  139. package/src/review/repo-stack.js +59 -0
  140. package/src/review/reviewer-fallback.js +19 -4
  141. package/src/review/seal-commit.js +29 -0
  142. package/src/review/sonar-pregate.js +59 -44
  143. package/src/review/third-party-review.js +90 -16
  144. package/src/review/third-party-size.js +43 -0
  145. package/src/review/third-party-skills.js +54 -0
  146. package/src/review/verify-pr.js +1 -24
  147. package/src/roles/audit-role.js +106 -125
  148. package/src/skills/atril-skills.js +5 -4
  149. package/src/sonar/scanner.js +116 -101
  150. package/src/steward/invariants.js +5 -4
  151. package/src/steward/phantom-sweep.js +66 -0
  152. package/src/tournament/judge.js +60 -53
  153. package/src/utils/gh-account.js +37 -0
  154. package/src/utils/git.js +0 -13
  155. package/src/utils/home-migration.js +7 -1
  156. package/src/utils/main-checkout.js +53 -0
  157. package/src/utils/qmd-collection.js +3 -1
  158. package/src/utils/welcome.js +3 -3
  159. package/templates/{skills → atril/commands}/kj-architect.md +5 -0
  160. package/templates/{skills → atril/commands}/kj-audit.md +5 -0
  161. package/templates/{skills → atril/commands}/kj-board.md +5 -0
  162. package/templates/{skills → atril/commands}/kj-code.md +5 -0
  163. package/templates/{skills → atril/commands}/kj-csv-transform.md +5 -0
  164. package/templates/{skills → atril/commands}/kj-data-report.md +5 -0
  165. package/templates/{skills → atril/commands}/kj-discover.md +5 -0
  166. package/templates/{skills → atril/commands}/kj-rag-query.md +5 -0
  167. package/templates/{skills → atril/commands}/kj-review.md +5 -0
  168. package/templates/{skills → atril/commands}/kj-security.md +5 -0
  169. package/templates/{skills → atril/commands}/kj-sonar.md +5 -0
  170. package/templates/{skills → atril/commands}/kj-sql-analysis.md +5 -0
  171. package/templates/{skills → atril/commands}/kj-test.md +5 -0
  172. package/packages/hu-board/public/utils/run-launcher.js +0 -169
  173. package/packages/hu-board/src/run-tracker.js +0 -121
  174. package/src/activity-log.js +0 -59
  175. package/src/agents/host-agent.js +0 -38
  176. package/src/agents/model-registry.js +0 -142
  177. package/src/audit/plan-adherence.js +0 -224
  178. package/src/autonomy/arbiter-role.js +0 -71
  179. package/src/autonomy/arbiter.js +0 -22
  180. package/src/autonomy/decider.js +0 -18
  181. package/src/autonomy/decision-resolver.js +0 -58
  182. package/src/autonomy/outcome-report.js +0 -55
  183. package/src/autonomy/stage-ask.js +0 -30
  184. package/src/brain/decision-tracker.js +0 -125
  185. package/src/brain/decisor.js +0 -243
  186. package/src/brain/solomon-consult.js +0 -171
  187. package/src/brain/standby-scheduler.js +0 -8
  188. package/src/budget/comparison.js +0 -96
  189. package/src/canvas/parse-md.js +0 -238
  190. package/src/canvas/schema.js +0 -101
  191. package/src/canvas/to-flat.js +0 -85
  192. package/src/canvas/validate.js +0 -163
  193. package/src/ci/dispatch.js +0 -99
  194. package/src/ci/index.js +0 -3
  195. package/src/ci/pr-diff.js +0 -26
  196. package/src/cli/register-standby.js +0 -26
  197. package/src/commands/architect.js +0 -111
  198. package/src/commands/autorun.js +0 -49
  199. package/src/commands/researcher.js +0 -54
  200. package/src/commands/resume.js +0 -72
  201. package/src/commands/review.js +0 -89
  202. package/src/commands/run.js +0 -185
  203. package/src/commands/standby.js +0 -117
  204. package/src/commands/status.js +0 -36
  205. package/src/commands/triage.js +0 -78
  206. package/src/commands/undo.js +0 -62
  207. package/src/domains/domain-loader.js +0 -245
  208. package/src/domains/domain-registry.js +0 -140
  209. package/src/domains/domain-synthesizer.js +0 -129
  210. package/src/git/automation.js +0 -433
  211. package/src/git/coder-commit-guard.js +0 -40
  212. package/src/git/hu-automation.js +0 -243
  213. package/src/git/hu-snapshot.js +0 -10
  214. package/src/git/symlink-targets.js +0 -57
  215. package/src/golden/asserter.js +0 -92
  216. package/src/golden/loader.js +0 -52
  217. package/src/golden/runner.js +0 -92
  218. package/src/golden/schema.js +0 -41
  219. package/src/guards/duplicate-members.js +0 -86
  220. package/src/guards/intent-guard.js +0 -161
  221. package/src/guards/perf-guard.js +0 -126
  222. package/src/guards/policy-guard.js +0 -90
  223. package/src/guards/policy-resolver.js +0 -85
  224. package/src/guards/secret-redactor.js +0 -71
  225. package/src/hu/acceptance-runner.js +0 -138
  226. package/src/hu/lazy-planner.js +0 -109
  227. package/src/hu/parallel-executor.js +0 -94
  228. package/src/hu/routing-metrics.js +0 -17
  229. package/src/hu/split-validator.js +0 -143
  230. package/src/hu/splitting-detector.js +0 -158
  231. package/src/hu/splitting-generator.js +0 -175
  232. package/src/hu/store.js +0 -394
  233. package/src/infrastructure/mocks.js +0 -182
  234. package/src/mcp/handlers/run-handler.js +0 -318
  235. package/src/mcp/sovereignty-guard.js +0 -113
  236. package/src/mcp/tool-arg-normalizers.js +0 -16
  237. package/src/mutate/reviewer-signal.js +0 -76
  238. package/src/orchestrator/agent-fallback.js +0 -81
  239. package/src/orchestrator/brain-coordinator.js +0 -186
  240. package/src/orchestrator/ci-integration.js +0 -139
  241. package/src/orchestrator/config-init.js +0 -426
  242. package/src/orchestrator/direct-actions.js +0 -217
  243. package/src/orchestrator/drivers/error-recovery.js +0 -287
  244. package/src/orchestrator/drivers/init-context.js +0 -238
  245. package/src/orchestrator/drivers/iteration-loop.js +0 -382
  246. package/src/orchestrator/drivers/iteration-phases/coder-and-refactorer.js +0 -69
  247. package/src/orchestrator/drivers/iteration-phases/guards.js +0 -91
  248. package/src/orchestrator/drivers/iteration-phases/handle-approved.js +0 -29
  249. package/src/orchestrator/drivers/iteration-phases/quality-gates.js +0 -125
  250. package/src/orchestrator/drivers/iteration-phases/reviewer-gate.js +0 -62
  251. package/src/orchestrator/drivers/post-loop.js +0 -404
  252. package/src/orchestrator/drivers/pre-loop-phases/auto-hu-batch.js +0 -137
  253. package/src/orchestrator/drivers/pre-loop-phases/config-deprecations.js +0 -47
  254. package/src/orchestrator/drivers/pre-loop-phases/ensure-addyosmani-skills.js +0 -84
  255. package/src/orchestrator/drivers/pre-loop-phases/inject-loaded-plan.js +0 -393
  256. package/src/orchestrator/drivers/pre-loop.js +0 -524
  257. package/src/orchestrator/drivers/run-hu-batch.js +0 -468
  258. package/src/orchestrator/feedback-enrichment.js +0 -140
  259. package/src/orchestrator/feedback-queue.js +0 -151
  260. package/src/orchestrator/flow-control.js +0 -170
  261. package/src/orchestrator/flow-runner.js +0 -365
  262. package/src/orchestrator/fs-leak-detector.js +0 -228
  263. package/src/orchestrator/hu-scheduler.js +0 -114
  264. package/src/orchestrator/hu-sub-pipeline.js +0 -642
  265. package/src/orchestrator/iteration-gate.js +0 -73
  266. package/src/orchestrator/iteration-stages.js +0 -9
  267. package/src/orchestrator/parallel-limiter.js +0 -74
  268. package/src/orchestrator/pipeline-context.js +0 -72
  269. package/src/orchestrator/post-loop-stages.js +0 -468
  270. package/src/orchestrator/pre-loop-stages.js +0 -11
  271. package/src/orchestrator/preflight-checks.js +0 -487
  272. package/src/orchestrator/repair/repair-detector.js +0 -117
  273. package/src/orchestrator/repair/repair-runner.js +0 -142
  274. package/src/orchestrator/reviewer-fallback.js +0 -45
  275. package/src/orchestrator/role-output-compressor.js +0 -189
  276. package/src/orchestrator/session-journal.js +0 -308
  277. package/src/orchestrator/solomon-escalation.js +0 -331
  278. package/src/orchestrator/solomon-rules.js +0 -212
  279. package/src/orchestrator/stages/acceptance-coverage-stage.js +0 -47
  280. package/src/orchestrator/stages/architect-stage.js +0 -172
  281. package/src/orchestrator/stages/coder-stage.js +0 -506
  282. package/src/orchestrator/stages/domain-curator-stage.js +0 -82
  283. package/src/orchestrator/stages/format-stage.js +0 -61
  284. package/src/orchestrator/stages/hu-reviewer-phases/detect-and-apply-splits.js +0 -127
  285. package/src/orchestrator/stages/hu-reviewer-stage.js +0 -419
  286. package/src/orchestrator/stages/perf-stage.js +0 -140
  287. package/src/orchestrator/stages/planner-stage.js +0 -85
  288. package/src/orchestrator/stages/rag-context-stage.js +0 -80
  289. package/src/orchestrator/stages/rag-preload-decisor.js +0 -58
  290. package/src/orchestrator/stages/research-stage.js +0 -69
  291. package/src/orchestrator/stages/reviewer-stage.js +0 -431
  292. package/src/orchestrator/stages/sonar-stage.js +0 -439
  293. package/src/orchestrator/stages/stage-classes.js +0 -84
  294. package/src/orchestrator/stages/stage-executor.js +0 -155
  295. package/src/orchestrator/stages/suite-green-stage.js +0 -62
  296. package/src/orchestrator/stages/tdd-discipline-stage.js +0 -56
  297. package/src/orchestrator/stages/tool-judge-stage.js +0 -53
  298. package/src/orchestrator/stages/triage-stage.js +0 -172
  299. package/src/orchestrator/standby.js +0 -71
  300. package/src/orchestrator/verification-gate.js +0 -183
  301. package/src/orchestrator.js +0 -22
  302. package/src/plan/adr-generator.js +0 -170
  303. package/src/plan/adr-loader.js +0 -60
  304. package/src/plan/plan-executor.js +0 -100
  305. package/src/plan/plan-validation.js +0 -4
  306. package/src/prompts/acceptance-coverage.js +0 -32
  307. package/src/prompts/arbiter.js +0 -38
  308. package/src/prompts/architect.js +0 -103
  309. package/src/prompts/hu-reviewer.js +0 -244
  310. package/src/prompts/tool-correctness-judge.js +0 -31
  311. package/src/prompts/triage.js +0 -57
  312. package/src/rag/embedder.js +0 -2
  313. package/src/rag/embedders/_cloud-base.js +0 -2
  314. package/src/rag/embedders/cohere.js +0 -2
  315. package/src/rag/embedders/mistral.js +0 -2
  316. package/src/rag/embedders/onnx.js +0 -2
  317. package/src/rag/embedders/openai.js +0 -2
  318. package/src/rag/embedders/voyage.js +0 -2
  319. package/src/rag/rerank.js +0 -4
  320. package/src/rag/where-parser.js +0 -4
  321. package/src/repeat-detector.js +0 -88
  322. package/src/review/diff-generator.js +0 -112
  323. package/src/review/git-stash-helper.js +0 -104
  324. package/src/review/schema.js +0 -31
  325. package/src/review/scope-filter.js +0 -152
  326. package/src/review/snapshot-diff.js +0 -122
  327. package/src/review/tdd-discipline.js +0 -90
  328. package/src/review/tdd-policy.js +0 -69
  329. package/src/roles/acceptance-coverage-role.js +0 -78
  330. package/src/roles/architect-role.js +0 -77
  331. package/src/roles/coder-role.js +0 -113
  332. package/src/roles/commiter-role.js +0 -113
  333. package/src/roles/domain-curator-role.js +0 -134
  334. package/src/roles/hu-reviewer-role.js +0 -64
  335. package/src/roles/impeccable-role.js +0 -85
  336. package/src/roles/index.js +0 -18
  337. package/src/roles/karajan-brain-role.js +0 -134
  338. package/src/roles/perf-role.js +0 -122
  339. package/src/roles/planner-role.js +0 -151
  340. package/src/roles/refactorer-role.js +0 -30
  341. package/src/roles/repairer-role.js +0 -181
  342. package/src/roles/researcher-role.js +0 -70
  343. package/src/roles/reviewer-role.js +0 -115
  344. package/src/roles/security-role.js +0 -73
  345. package/src/roles/solomon-role.js +0 -271
  346. package/src/roles/sonar-role.js +0 -72
  347. package/src/roles/tester-role.js +0 -235
  348. package/src/roles/tool-correctness-judge-role.js +0 -78
  349. package/src/roles/triage-role.js +0 -99
  350. package/src/session/journal/decisions-writer.js +0 -200
  351. package/src/session/journal/iteration-logger.js +0 -194
  352. package/src/session/journal/summary-writer.js +0 -320
  353. package/src/session/journal/tree-writer.js +0 -164
  354. package/src/session/journal/write-all.js +0 -89
  355. package/src/session-cleanup.js +0 -116
  356. package/src/skills/semantic-detector.js +0 -167
  357. package/src/skills/skill-detector.js +0 -385
  358. package/src/sonar/cloud-scanner.js +0 -78
  359. package/src/tracker-bootstrap.js +0 -44
  360. package/src/types/index.js +0 -38
  361. package/src/types/policy.js +0 -43
  362. package/src/types/solomon.js +0 -87
  363. package/src/utils/async-lock.js +0 -31
  364. package/src/utils/budget.js +0 -229
  365. package/src/utils/cwd-confirm.js +0 -39
  366. package/src/utils/display/event-handlers.js +0 -403
  367. package/src/utils/display/formatters.js +0 -132
  368. package/src/utils/display/header.js +0 -47
  369. package/src/utils/display/session-summary.js +0 -118
  370. package/src/utils/display/solomon.js +0 -42
  371. package/src/utils/pricing.js +0 -29
  372. package/src/utils/quota-simulator.js +0 -56
  373. package/src/utils/role-assigner.js +0 -137
  374. package/src/utils/rtk-wrapper.js +0 -87
  375. package/src/utils/run-registry.js +0 -9
  376. package/src/utils/status-dashboard.js +0 -254
  377. package/src/utils/tool-call-extractor.js +0 -56
  378. package/src/webperf/devtools-detect.js +0 -112
  379. package/src/webperf/webperf-role-integration.js +0 -66
  380. package/templates/skills/kj-run.md +0 -73
@@ -1,125 +0,0 @@
1
- /**
2
- * Iteration phase: quality gates (TDD check, SonarQube local + cloud,
3
- * Impeccable design audit).
4
- *
5
- * Extracted verbatim from `src/orchestrator/drivers/iteration-loop.js` in
6
- * the v2.7.x audit follow-up to keep the iteration-loop driver under the
7
- * 600-LOC ceiling. Behaviour is byte-for-byte identical to the inlined
8
- * version.
9
- *
10
- * Returns { action: "ok" | "return" | "continue", result? }.
11
- * - "ok" → caller continues to the next phase.
12
- * - "return" → caller returns `result` (pause / stalled / blocked).
13
- * - "continue" → caller continues the iteration loop (next iteration).
14
- */
15
-
16
- import { generateDiff } from "../../../review/diff-generator.js";
17
- import { withLock } from "../../../utils/async-lock.js";
18
- import {
19
- runTddCheckStage, runSonarStage, runSonarCloudStage,
20
- } from "../../iteration-stages.js";
21
- import { runImpeccableStage } from "../../post-loop-stages.js";
22
- import { runPerfStage } from "../../stages/perf-stage.js";
23
- import { runTddDisciplineStage } from "../../stages/tdd-discipline-stage.js";
24
- import { runSuiteGreenStage, suiteGreenRequired } from "../../stages/suite-green-stage.js";
25
- import { runToolJudgeStage } from "../../stages/tool-judge-stage.js";
26
- import { runFormatStage } from "../../stages/format-stage.js";
27
- import { tryCiComment } from "../../ci-integration.js";
28
-
29
- export async function runQualityGateStages({ config, logger, emitter, eventBase, session, trackBudget, i, askQuestion, repeatDetector, budgetSummary, sonarState, task, stageResults, coderRole, pipelineFlags, brainCtx }) {
30
- // KJC-TSK-1237 (#2565): the coder's files reach every gate formatted.
31
- await runFormatStage({ config, logger, emitter, eventBase, session });
32
-
33
- const tddResult = await runTddCheckStage({ config, logger, emitter, eventBase, session, trackBudget, iteration: i, askQuestion, task, brainCtx });
34
- if (tddResult.action === "pause") return { action: "return", result: tddResult.result };
35
- if (tddResult.action === "continue") return { action: "continue" };
36
-
37
- // KJC-BUG-0298 (#1993): with TDD, a red suite never reaches the reviewer.
38
- if (config.development?.methodology === "tdd" && suiteGreenRequired(config)) {
39
- const green = await runSuiteGreenStage({ config, logger, emitter, eventBase, session, iteration: i });
40
- if (green.action === "continue") return { action: "continue" };
41
- }
42
-
43
- // KJC-TSK-0398 PR3: opt-in red-then-green check.
44
- if (config.development?.require_red_then_green) {
45
- const disc = await runTddDisciplineStage({
46
- config, logger, emitter, eventBase,
47
- sourceFiles: tddResult.sourceFiles || [],
48
- testFiles: tddResult.testFiles || [],
49
- });
50
- if (disc.action === "continue") return { action: "continue" };
51
- }
52
-
53
- // Sonar runs for code tasks per policy. Since v2.7.4 it is NOT
54
- // toggleable via config — that's intrinsic to Karajan. The taskType
55
- // policy (resolved_policies.sonar) is the single source of truth.
56
- // Solomon may skip a single iteration via rule alerts; that's a
57
- // runtime decision, not a config option.
58
- //
59
- // Test-harness escape hatch via config.testHarness.disableSonarStage
60
- // — production code reads `config?.testHarness?.disableSonarStage`,
61
- // never `globalThis.*`. The legacy override surface is documented
62
- // (and exclusively read) in src/config/test-harness.js. ESLint rule
63
- // (#557) blocks any re-introduction of `globalThis.__KJ_*` outside
64
- // that one file.
65
- const sonarStageDisabledForTest = config?.testHarness?.disableSonarStage === true;
66
- if (!sonarStageDisabledForTest && session.resolved_policies?.sonar !== false) {
67
- // Serialize across parallel HU lanes (KJC-TSK-0625): the SonarQube
68
- // server scans one project key at a time. No-op on sequential runs.
69
- const sonarResult = await withLock("sonar-scan", () => runSonarStage({
70
- config, logger, emitter, eventBase, session, trackBudget, iteration: i,
71
- repeatDetector, budgetSummary, sonarState, askQuestion, task, brainCtx
72
- }));
73
- if (sonarResult.action === "stalled" || sonarResult.action === "pause") return { action: "return", result: sonarResult.result };
74
- if (sonarResult.action === "continue") return { action: "continue" };
75
- if (sonarResult.stageResult) {
76
- stageResults.sonar = sonarResult.stageResult;
77
- await tryCiComment({ config, session, logger, agent: "Sonar", body: `SonarQube scan: ${sonarResult.stageResult.summary || "completed"}` });
78
- }
79
- }
80
-
81
- if (config.sonarcloud?.enabled) {
82
- const cloudResult = await runSonarCloudStage({
83
- config, logger, emitter, eventBase, session, trackBudget, iteration: i
84
- });
85
- if (cloudResult.stageResult) {
86
- stageResults.sonarcloud = cloudResult.stageResult;
87
- }
88
- }
89
-
90
- if (pipelineFlags?.impeccableEnabled) {
91
- const diff = await generateDiff({ baseRef: session.session_start_sha, projectDir: config?.projectDir || null });
92
- const impeccableMode = pipelineFlags?.impeccableMode || "audit";
93
- const impeccableResult = await runImpeccableStage({
94
- config, logger, emitter, eventBase, session, coderRole, trackBudget,
95
- iteration: i, task, diff, mode: impeccableMode
96
- });
97
- if (impeccableResult.stageResult) {
98
- stageResults.impeccable = impeccableResult.stageResult;
99
- }
100
- }
101
-
102
- if (pipelineFlags?.perfEnabled) {
103
- const perfResult = await runPerfStage({
104
- config, logger, emitter, eventBase, session, trackBudget,
105
- iteration: i, task, brainCtx
106
- });
107
- if (perfResult.stageResult) {
108
- stageResults.perf = perfResult.stageResult;
109
- }
110
- if (perfResult.action === "continue") return { action: "continue" };
111
- }
112
-
113
- // KJC-TSK-0375 PR3: opt-in tool-call quality judge. Non-blocking.
114
- if (pipelineFlags?.toolJudgeEnabled) {
115
- const judgeResult = await runToolJudgeStage({
116
- config, logger, emitter, eventBase, session, coderRole, trackBudget,
117
- iteration: i, task,
118
- });
119
- if (judgeResult.stageResult) {
120
- stageResults.toolJudge = judgeResult.stageResult;
121
- }
122
- }
123
-
124
- return { action: "ok" };
125
- }
@@ -1,62 +0,0 @@
1
- /**
2
- * Iteration phase: reviewer stage with standby handling.
3
- *
4
- * Extracted verbatim from `src/orchestrator/drivers/iteration-loop.js` in
5
- * the v2.7.x audit follow-up to keep the iteration-loop driver under the
6
- * 600-LOC ceiling. Behaviour is byte-for-byte identical to the inlined
7
- * version.
8
- *
9
- * Returns { action: "ok" | "return" | "retry", review?, result? }.
10
- * - "ok" → caller proceeds with `review` (approved or with blocking
11
- * issues).
12
- * - "return" → caller returns `result` (pause / stalled).
13
- * - "retry" → caller decrements its iteration counter and retries.
14
- */
15
-
16
- import { stageRegistry } from "../../stages/stage-classes.js";
17
- import { runStage } from "../../stages/stage-executor.js";
18
- import { handleStandbyResult } from "../error-recovery.js";
19
-
20
- export async function runReviewerGateStage({ pipelineFlags, reviewerRole, config, logger, emitter, eventBase, session, trackBudget, i, reviewRules, task, repeatDetector, budgetSummary, askQuestion, brainCtx }) {
21
- // Reviewer via StageRegistry (TSK-0336). ReviewerStage.canRun returns
22
- // `reviewerEnabled !== false`; when false, runStage returns null and we
23
- // synthesize the "disabled-by-pipeline" stub (same shape as the previous
24
- // early-return). Otherwise execute() runs runReviewerStage.
25
- const reviewerCtx = {
26
- reviewerRole, config, logger, emitter, eventBase, session, trackBudget,
27
- iteration: i, reviewRules, task, repeatDetector, budgetSummary, askQuestion,
28
- brainCtx, pipelineFlags,
29
- };
30
- const reviewerResult = await runStage(stageRegistry.get("reviewer"), reviewerCtx);
31
- if (reviewerResult === null) {
32
- // KJC-BUG-0297 (#1993): `reviewed: false` so the pipeline never stamps a
33
- // verdict nobody gave nor commits on it (finalizeGitAutomation).
34
- return {
35
- action: "ok",
36
- review: { approved: true, reviewed: false, blocking_issues: [], non_blocking_suggestions: [], summary: "Reviewer disabled by pipeline: nothing was reviewed", confidence: 0 }
37
- };
38
- }
39
- if (reviewerResult.action === "pause") return { action: "return", result: reviewerResult.result };
40
- const revStandby = await handleStandbyResult({ stageResult: reviewerResult, session, emitter, eventBase, i, stage: "reviewer", logger, config, askQuestion });
41
- if (revStandby.handled) {
42
- if (revStandby.action === "return") return { action: "return", result: revStandby.result };
43
- if (revStandby.action === "skip") {
44
- // Solomon said skip review — treat as approved
45
- return { action: "ok", review: { approved: true, blocking_issues: [], non_blocking_suggestions: [], summary: "Review skipped (agent rate-limited, Solomon approved)", confidence: 0.7 } };
46
- }
47
- if (revStandby.action === "retry_reviewer_only") {
48
- // Retry just the reviewer — use alternative agent if Solomon recommended one
49
- let retryReviewerRole = reviewerRole;
50
- const alt = session._alternative_agent;
51
- if (alt?.stage === "reviewer" && alt?.provider) {
52
- retryReviewerRole = { provider: alt.provider, model: null };
53
- logger.info(`Retrying reviewer with alternative agent: ${alt.provider}`);
54
- delete session._alternative_agent;
55
- }
56
- return runReviewerGateStage({ pipelineFlags: { reviewerEnabled: true }, reviewerRole: retryReviewerRole, config, logger, emitter, eventBase, session, trackBudget, i, reviewRules, task, repeatDetector, budgetSummary, askQuestion });
57
- }
58
- return { action: "retry" };
59
- }
60
- if (reviewerResult.stalled) return { action: "return", result: reviewerResult.stalledResult };
61
- return { action: "ok", review: reviewerResult.review };
62
- }
@@ -1,404 +0,0 @@
1
- /**
2
- * Post-loop driver — extracted from src/orchestrator/flow-runner.js in
3
- * TSK-0335 (Oleada 3 of the v2.7.4 audit refactor).
4
- *
5
- * Handlers for everything that happens AFTER the iteration loop decides
6
- * an outcome (approved, max-iterations, or simple finalization):
7
- *
8
- * - handlePostLoopStages: run tester → security → final audit
9
- * after the reviewer has approved; any of
10
- * them can demand one more coder pass.
11
- * - finalizeApprovedSession: commit/push/PR + PG card transition +
12
- * full session journal + session:end event.
13
- * - handleMaxIterationsReached: Brain-owned decision at the iteration
14
- * cap (extend vs finalize vs escalate).
15
- * Legacy path delegates to Solomon.
16
- * - tryAutoStartBoard: auto-launch HU Board when config opts in.
17
- * - writeHistoryRecord: non-blocking HU history write on session end.
18
- *
19
- * Extracted verbatim; no behavior change. flow-runner.js now imports these
20
- * instead of defining them. Part of breaking up the 2254-LOC god-module —
21
- * see docs/ARCHITECTURE.md and the TSK-0335 acceptance criteria.
22
- */
23
-
24
- import { generateDiff } from "../../review/diff-generator.js";
25
- import { finalizeGitAutomation } from "../../git/automation.js";
26
- import { listCommitsBetween, listFilesChangedSince } from "../../utils/git.js";
27
- import { loadPlan } from "../../plan/plan-store.js";
28
- import { computePlanAdherenceScore } from "../../audit/plan-adherence.js";
29
- import { saveSession, markSessionStatus } from "../../session/store.js";
30
- import {
31
- setReviewerFeedback, setBudget, setRtkSavings, resetRetryCount,
32
- } from "../../session/mutators.js";
33
- import { emitProgress, makeEvent } from "../../utils/events.js";
34
- import { runTesterStage, runSecurityStage, runFinalAuditStage } from "../post-loop-stages.js";
35
- import { runAcceptanceCoverageStage } from "../stages/acceptance-coverage-stage.js";
36
- import { criteriaOfCard } from "../../roles/acceptance-coverage-role.js";
37
- import { invokeSolomon } from "../solomon-escalation.js";
38
- import { tryCiComment } from "../ci-integration.js";
39
- import { getIntegration } from "../integrations.js";
40
-
41
- export async function handlePostLoopStages({ config, session, emitter, eventBase, coderRole, trackBudget, i, task, stageResults, ciEnabled: _ciEnabled, testerEnabled, securityEnabled, askQuestion, logger, brainCtx }) {
42
- const postLoopDiff = await generateDiff({ baseRef: session.session_start_sha });
43
-
44
- if (testerEnabled) {
45
- const testerResult = await runTesterStage({
46
- config, logger, emitter, eventBase, session, coderRole, trackBudget,
47
- iteration: i, task, diff: postLoopDiff, askQuestion
48
- });
49
- if (testerResult.action === "pause") return { action: "return", result: testerResult.result };
50
- if (testerResult.action === "continue") {
51
- const summary = testerResult.stageResult?.summary || "Tester found issues";
52
- setReviewerFeedback(session, `Tester FAILED — fix these issues:\n${summary}`);
53
- await saveSession(session);
54
- if (testerResult.stageResult) stageResults.tester = testerResult.stageResult;
55
- // Brain: push tester failure into feedback queue + compress for next coder iteration
56
- if (brainCtx?.enabled) {
57
- const { processRoleOutput } = await import("../brain-coordinator.js");
58
- processRoleOutput(brainCtx, { roleName: "tester", output: testerResult.stageResult, iteration: i });
59
- }
60
- return { action: "continue" };
61
- }
62
- if (testerResult.stageResult) {
63
- stageResults.tester = testerResult.stageResult;
64
- await tryCiComment({ config, session, logger, agent: "Tester", body: `Tests: ${testerResult.stageResult.summary || "completed"}` });
65
- }
66
- }
67
-
68
- if (securityEnabled) {
69
- const securityResult = await runSecurityStage({
70
- config, logger, emitter, eventBase, session, coderRole, trackBudget,
71
- iteration: i, task, diff: postLoopDiff, askQuestion, brainCtx
72
- });
73
- if (securityResult.action === "pause") return { action: "return", result: securityResult.result };
74
- if (securityResult.action === "continue") {
75
- const summary = securityResult.stageResult?.summary || "Security found issues";
76
- setReviewerFeedback(session, `Security FAILED — fix these issues:\n${summary}`);
77
- await saveSession(session);
78
- if (securityResult.stageResult) stageResults.security = securityResult.stageResult;
79
- // Brain: push security findings into feedback queue + compress for next coder iteration
80
- if (brainCtx?.enabled) {
81
- const { processRoleOutput } = await import("../brain-coordinator.js");
82
- processRoleOutput(brainCtx, { roleName: "security", output: securityResult.stageResult, iteration: i });
83
- }
84
- return { action: "continue" };
85
- }
86
- if (securityResult.stageResult) {
87
- stageResults.security = securityResult.stageResult;
88
- await tryCiComment({ config, session, logger, agent: "Security", body: `Security scan: ${securityResult.stageResult.summary || "completed"}` });
89
- }
90
- }
91
-
92
- // Final audit — last quality gate before declaring success
93
- const auditResult = await runFinalAuditStage({
94
- config, logger, emitter, eventBase, session, coderRole, trackBudget,
95
- iteration: i, task, diff: postLoopDiff
96
- });
97
- if (auditResult.stageResult) {
98
- stageResults.audit = auditResult.stageResult;
99
- await tryCiComment({ config, session, logger, agent: "Audit", body: `Final audit: ${auditResult.stageResult.summary || "completed"}` });
100
- }
101
- if (auditResult.action === "retry") {
102
- // Audit found actionable issues — loop back to coder
103
- setReviewerFeedback(session, auditResult.feedback);
104
- await saveSession(session);
105
- return { action: "continue" };
106
- }
107
-
108
- // KJC-TSK-0987 (#1894): with a card, each acceptance criterion is read against
109
- // the diff by a different AI before the run is approved. An uncovered one goes
110
- // back to the coder; a judge with no verdict stops the approval, never grants it.
111
- const coverage = await runAcceptanceCoverageStage({
112
- config, logger, emitter, eventBase, trackBudget, iteration: i, task,
113
- criteria: criteriaOfCard(session.pg_card), diff: postLoopDiff,
114
- });
115
- if (coverage.stageResult) stageResults.acceptanceCoverage = coverage.stageResult;
116
- if (coverage.action === "retry") {
117
- setReviewerFeedback(session, coverage.feedback);
118
- await saveSession(session);
119
- return { action: "continue" };
120
- }
121
- if (coverage.action === "fail") {
122
- return { action: "return", result: { approved: false, sessionId: session.id, reason: "acceptance_coverage_unavailable", error: coverage.stageResult.summary } };
123
- }
124
-
125
- return { action: "proceed" };
126
- }
127
-
128
- export async function finalizeApprovedSession({ config, gitCtx, task, logger, session, stageResults, emitter, eventBase, budgetSummary, pgCard, pgProject, review, i, rtkTracker }) {
129
- const gitResult = await finalizeGitAutomation({ config, gitCtx, task, logger, session, stageResults, review });
130
-
131
- // Accumulate final commits for PG card lifecycle tracking
132
- if (gitResult?.commits?.length) {
133
- const tracker = getIntegration("tracker");
134
- for (const c of gitResult.commits) tracker?.onCommit?.(session, c);
135
- }
136
-
137
- if (stageResults.planner?.ok) {
138
- stageResults.planner.completedSteps = [...(stageResults.planner.steps ?? [])];
139
- }
140
- setBudget(session, budgetSummary());
141
- await markSessionStatus(session, "approved");
142
-
143
- await getIntegration("tracker")?.onSessionApproved?.({ pgCard, pgProject, config, session, gitResult, logger });
144
-
145
- const deferredIssues = session.deferred_issues || [];
146
- const rtkSavings = rtkTracker?.hasData() ? rtkTracker.summary() : undefined;
147
- if (rtkSavings) setRtkSavings(session, rtkSavings);
148
- await saveSession(session);
149
-
150
- // --- Journal: write final files (shared writer, KJC-BUG-0084) ---
151
- const journalDir = session._journalDir;
152
- if (journalDir) {
153
- // 2026-05-07 dogfooding: gitResult.commits only carries the post-loop
154
- // commit (scaffold). Compute the full range from session_start_sha so
155
- // every commit the run produced shows up in execution order.
156
- let allCommits;
157
- try { allCommits = (await listCommitsBetween(session.head_at_start || session.session_start_sha)) || []; }
158
- catch { allCommits = gitResult?.commits || []; }
159
- const summaryCommits = allCommits.length > 0 ? allCommits : (gitResult?.commits || []);
160
-
161
- // KJC-TSK-0376 — plan adherence metric (deepeval-inspired). When the
162
- // run executed against a known plan (`kj run --plan <id>`), score how
163
- // faithfully the coder followed it. Pure offline; safe-by-default
164
- // (try/catch swallows missing helper or unreadable plan).
165
- let planAdherence = null;
166
- try {
167
- const planId = session._planRef?.planId
168
- || stageResults?.huReviewer?.planId
169
- || null;
170
- if (planId) {
171
- const projectDir = config?.projectDir
172
- || session.config_snapshot?.projectDir
173
- || process.cwd();
174
- const plan = await loadPlan(projectDir, planId).catch(() => null);
175
- if (plan && Array.isArray(plan.hus) && plan.hus.length > 0) {
176
- const filesChanged = await listFilesChangedSince(
177
- session.head_at_start || session.session_start_sha,
178
- ).catch(() => []);
179
- planAdherence = computePlanAdherenceScore({
180
- commits: summaryCommits,
181
- plan,
182
- filesChanged,
183
- });
184
- }
185
- }
186
- } catch (err) {
187
- logger?.warn?.(`Plan adherence calculation skipped: ${err.message}`);
188
- }
189
-
190
- const { writeSessionJournal } = await import("../../session/journal/write-all.js");
191
- await writeSessionJournal({
192
- session, logger,
193
- result: "APPROVED",
194
- iterations: i,
195
- budget: budgetSummary(),
196
- stages: stageResults,
197
- commits: summaryCommits,
198
- planAdherence,
199
- });
200
- }
201
-
202
- // Mirror the same enriched commit list into the session:end event so the
203
- // terminal `🏁 Result` banner (printSessionGit) shows every commit the
204
- // run produced, not just the post-loop scaffold one. We compute again
205
- // (cheap: one git log call) rather than threading a variable through
206
- // because the journal block is wrapped in try/catch and may have set
207
- // `summaryCommits` to a fallback we don't want for the event detail.
208
- // try/catch tolerates both promise rejection and sync undefined returns
209
- // (see the journal block above for the detailed rationale).
210
- let eventCommits = null;
211
- try { eventCommits = await listCommitsBetween(session.head_at_start || session.session_start_sha); }
212
- catch { /* leave null — we'll use gitResult unchanged */ }
213
- const gitForEvent = (Array.isArray(eventCommits) && eventCommits.length > 0)
214
- ? { ...gitResult, commits: eventCommits }
215
- : gitResult;
216
- const endDetail = { approved: true, iterations: i, stages: stageResults, git: gitForEvent, budget: budgetSummary(), deferredIssues };
217
- if (rtkSavings) endDetail.rtk_savings = rtkSavings;
218
- emitProgress(
219
- emitter,
220
- makeEvent("session:end", { ...eventBase, stage: "done" }, {
221
- message: deferredIssues.length > 0
222
- ? `Session approved (${deferredIssues.length} deferred issue(s) tracked as tech debt)`
223
- : "Session approved",
224
- detail: endDetail
225
- })
226
- );
227
- const result = { approved: true, sessionId: session.id, review, git: gitResult, deferredIssues };
228
- if (rtkSavings) result.rtk_savings = rtkSavings;
229
- return result;
230
- }
231
-
232
- export async function handleMaxIterationsReached({ session, budgetSummary, emitter, eventBase, config, stageResults, logger, askQuestion, task, rtkTracker, brainCtx }) {
233
- const budget = budgetSummary();
234
-
235
- // Brain-owned decision: max_iterations is guidance, not a hard rule.
236
- // Brain evaluates the feedback queue state to decide extend / finalize / escalate.
237
- // Solomon is only consulted if Brain cannot decide on its own.
238
- if (brainCtx?.enabled) {
239
- const entries = brainCtx.feedbackQueue?.entries || [];
240
- const pending = entries.map(e => ({ source: e.source, category: e.category, severity: e.severity, description: e.description }));
241
- const hasSecurity = entries.some(e => e.category === "security" || e.source === "security");
242
- const hasCorrectness = entries.some(e => ["correctness", "tests"].includes(e.category));
243
-
244
- if (hasSecurity) {
245
- // Brain: security issues unresolved → cannot finalize, escalate
246
- logger.warn(`Brain: max_iterations reached with ${entries.filter(e => e.category === "security" || e.source === "security").length} unresolved security issue(s) — cannot finalize`);
247
- return { paused: true, sessionId: session.id, question: "Brain: unresolved security issues at max_iterations. Review manually or extend pipeline.", context: "brain_security_block", pending };
248
- }
249
-
250
- if (hasCorrectness) {
251
- // Brain: correctness/test issues pending. Cap at MAX_EXTENSIONS to avoid infinite extensions.
252
- const MAX_EXTENSIONS = 2;
253
- if (brainCtx.extensionCount >= MAX_EXTENSIONS) {
254
- logger.warn(`Brain: ${brainCtx.extensionCount} extensions exhausted with correctness issues still pending — escalating to human`);
255
- return { paused: true, sessionId: session.id, question: `Brain exhausted ${MAX_EXTENSIONS} extensions with correctness/tests still pending. Manual intervention needed.`, context: "brain_extension_cap", pending };
256
- }
257
- brainCtx.extensionCount += 1;
258
- logger.info(`Brain: max_iterations reached with ${entries.filter(e => ["correctness", "tests"].includes(e.category)).length} correctness issue(s) pending — extending iterations (extension ${brainCtx.extensionCount}/${MAX_EXTENSIONS})`);
259
- resetRetryCount(session, "reviewer");
260
- await saveSession(session);
261
- return { approved: false, sessionId: session.id, reason: "max_iterations_extended", extraIterations: Math.ceil(config.max_iterations / 2) };
262
- }
263
-
264
- if (entries.length === 0) {
265
- // Brain: no pending feedback → last reviewer approved, finalize
266
- logger.info("Brain: max_iterations reached with clean feedback queue — finalizing as approved");
267
- return { approved: true, sessionId: session.id, reason: "brain_approved" };
268
- }
269
-
270
- // hasStyleOnly: genuine dilemma → Brain consults Solomon
271
- logger.info(`Brain: max_iterations with ${entries.length} style-only issue(s) — consulting Solomon on dilemma`);
272
- const solomonResult = await invokeSolomon({
273
- config, logger, emitter, eventBase, stage: "max_iterations", askQuestion, session,
274
- iteration: config.max_iterations,
275
- conflict: {
276
- stage: "brain-max-iterations",
277
- task,
278
- iterationCount: config.max_iterations,
279
- maxIterations: config.max_iterations,
280
- budget_usd: budget?.total_cost_usd || 0,
281
- dilemma: `Max iterations reached with ${entries.length} style-only issue(s) pending. Accept as-is or request more work?`,
282
- pendingIssues: pending,
283
- history: [{ agent: "pipeline", feedback: session.last_reviewer_feedback || "Max iterations reached" }]
284
- }
285
- });
286
- // Brain applies Solomon's decision
287
- if (solomonResult.action === "approve") {
288
- logger.info("Brain: Solomon advised approve for style-only pending — finalizing");
289
- return { approved: true, sessionId: session.id, reason: "brain_solomon_approved" };
290
- }
291
- if (solomonResult.action === "continue") {
292
- return { approved: false, sessionId: session.id, reason: "max_iterations_extended", extraIterations: solomonResult.extraIterations || Math.ceil(config.max_iterations / 2) };
293
- }
294
- if (solomonResult.action === "pause") {
295
- return { paused: true, sessionId: session.id, question: solomonResult.question, context: "brain_solomon_dilemma" };
296
- }
297
- // Fallback: escalate to human
298
- return { paused: true, sessionId: session.id, question: `Brain+Solomon cannot resolve: ${entries.length} pending issue(s) at max_iterations`, context: "max_iterations" };
299
- }
300
-
301
- // Legacy path (Brain disabled): original Solomon-driven flow
302
- const solomonResult = await invokeSolomon({
303
- config, logger, emitter, eventBase, stage: "max_iterations", askQuestion, session,
304
- iteration: config.max_iterations,
305
- conflict: {
306
- stage: "max_iterations",
307
- task,
308
- iterationCount: config.max_iterations,
309
- maxIterations: config.max_iterations,
310
- budget_usd: budget?.total_cost_usd || 0,
311
- history: [{ agent: "pipeline", feedback: session.last_reviewer_feedback || "Max iterations reached without reviewer approval" }]
312
- }
313
- });
314
-
315
- if (solomonResult.action === "approve") {
316
- logger.info("Solomon approved coder's work at max_iterations checkpoint");
317
- return { approved: true, sessionId: session.id, reason: "solomon_approved" };
318
- }
319
-
320
- if (solomonResult.action === "continue") {
321
- if (solomonResult.humanGuidance) {
322
- setReviewerFeedback(session, `Solomon guidance: ${solomonResult.humanGuidance}`);
323
- }
324
- resetRetryCount(session, "reviewer");
325
- await saveSession(session);
326
- const extraIterations = solomonResult.extraIterations || config.max_iterations;
327
- return { approved: false, sessionId: session.id, reason: "max_iterations_extended", humanGuidance: solomonResult.humanGuidance, extraIterations };
328
- }
329
-
330
- if (solomonResult.action === "pause") {
331
- return { paused: true, sessionId: session.id, question: solomonResult.question, context: "max_iterations" };
332
- }
333
-
334
- if (solomonResult.action === "subtask") {
335
- return { paused: true, sessionId: session.id, subtask: solomonResult.subtask, context: "max_iterations_subtask" };
336
- }
337
-
338
- // Solomon couldn't resolve — fail
339
- setBudget(session, budgetSummary());
340
- const rtkSavings = rtkTracker?.hasData() ? rtkTracker.summary() : undefined;
341
- if (rtkSavings) setRtkSavings(session, rtkSavings);
342
- await markSessionStatus(session, "failed");
343
- const failDetail = { approved: false, reason: "max_iterations", iterations: config.max_iterations, stages: stageResults, budget: budgetSummary() };
344
- if (rtkSavings) failDetail.rtk_savings = rtkSavings;
345
- emitProgress(
346
- emitter,
347
- makeEvent("session:end", { ...eventBase, stage: "done" }, {
348
- status: "fail",
349
- message: "Max iterations reached (Solomon could not resolve)",
350
- detail: failDetail
351
- })
352
- );
353
- return { approved: false, sessionId: session.id, reason: "max_iterations" };
354
- }
355
-
356
- /**
357
- * KJC-TSK-0884 (ADR 0011): the board starts by itself, like Sonar. Only a
358
- * declared false on either switch opts out; nothing declared means on.
359
- */
360
- export const boardAutoStartWanted = (config) => config?.hu_board?.auto_start !== false && config?.hu_board?.enabled !== false;
361
-
362
- export async function tryAutoStartBoard(config, logger, emitter, eventBase) {
363
- if (!boardAutoStartWanted(config)) return;
364
- // Never auto-start during vitest: races the PID file and starts a detached
365
- // process that outlives the test run.
366
- if (process.env.VITEST || process.env.NODE_ENV === "test") return;
367
-
368
- try {
369
- const { startBoard, renderBoardBanner, boardSlug } = await import("../../commands/board.js");
370
- const boardPort = config.hu_board?.port || 4000;
371
- // KJC-TSK-0884: the project's scoped view (/p/<slug>), the parent repo's
372
- // even from a worktree lane.
373
- const slug = config.projectDir ? boardSlug(config.projectDir) : null;
374
- const boardResult = await startBoard(boardPort, { projectSlug: slug });
375
- const status = boardResult.alreadyRunning ? "already running" : "started";
376
- // Highlighted URL box — visible regardless of log level (matches the
377
- // post-planner auto-HU banner so the user gets the same signal either
378
- // way the board got started).
379
- console.log(renderBoardBanner({ url: boardResult.url, status }));
380
- logger.info(`HU Board ${status} at ${boardResult.url}`);
381
- emitProgress(emitter, makeEvent("board:started", eventBase, {
382
- message: `HU Board running at ${boardResult.url}`,
383
- detail: { pid: boardResult.pid, port: boardPort, url: boardResult.url }
384
- }));
385
- } catch (err) {
386
- logger.warn(`HU Board auto-start failed (non-blocking): ${err.message}`);
387
- }
388
- }
389
-
390
- export async function writeHistoryRecord({ sessionId, task, result, logger }) {
391
- try {
392
- const { createHistoryRecord } = await import("../../hu/store.js");
393
- const approved = Boolean(result?.approved);
394
- const summary = result?.review?.summary || result?.reason || null;
395
- await createHistoryRecord(sessionId, {
396
- task,
397
- result: JSON.stringify(result),
398
- approved,
399
- summary
400
- });
401
- } catch (err) {
402
- logger.warn(`HU history record failed (non-blocking): ${err.message}`);
403
- }
404
- }