@karajan-family/code 4.21.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 (746) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +98 -0
  3. package/bin/karajan-mcp.js +2 -0
  4. package/bin/kj-rag-mcp.js +75 -0
  5. package/bin/kj-tail +361 -0
  6. package/bin/kj.js +2 -0
  7. package/docs/README.es.md +80 -0
  8. package/docs/karajan-code-logo-small.png +0 -0
  9. package/library/logical-clocks-lamport.md +40 -0
  10. package/package.json +140 -0
  11. package/packages/ai-trash/README.md +37 -0
  12. package/packages/ai-trash/bin/kj-trash.js +10 -0
  13. package/packages/ai-trash/package.json +43 -0
  14. package/packages/ai-trash/src/cli.js +200 -0
  15. package/packages/ai-trash/src/destructive-parser.js +74 -0
  16. package/packages/ai-trash/src/git-snapshot.js +128 -0
  17. package/packages/ai-trash/src/hook.js +137 -0
  18. package/packages/ai-trash/src/index.js +14 -0
  19. package/packages/ai-trash/src/install.js +73 -0
  20. package/packages/ai-trash/src/logger.js +60 -0
  21. package/packages/ai-trash/src/manifest.js +91 -0
  22. package/packages/ai-trash/src/permissions.js +26 -0
  23. package/packages/ai-trash/src/snapshot.js +66 -0
  24. package/packages/ai-trash/src/ulid.js +66 -0
  25. package/packages/hu-board/README.md +69 -0
  26. package/packages/hu-board/package.json +28 -0
  27. package/packages/hu-board/public/app.js +259 -0
  28. package/packages/hu-board/public/index.html +77 -0
  29. package/packages/hu-board/public/pipeline.css +132 -0
  30. package/packages/hu-board/public/pipeline.html +48 -0
  31. package/packages/hu-board/public/pipeline.js +200 -0
  32. package/packages/hu-board/public/rag.html +21 -0
  33. package/packages/hu-board/public/rag.js +39 -0
  34. package/packages/hu-board/public/styles.css +973 -0
  35. package/packages/hu-board/public/utils/api.js +139 -0
  36. package/packages/hu-board/public/utils/board-view.js +473 -0
  37. package/packages/hu-board/public/utils/command-launcher.js +213 -0
  38. package/packages/hu-board/public/utils/config-editor.js +181 -0
  39. package/packages/hu-board/public/utils/dashboard-view.js +103 -0
  40. package/packages/hu-board/public/utils/formatters.js +300 -0
  41. package/packages/hu-board/public/utils/graph-view.js +216 -0
  42. package/packages/hu-board/public/utils/hu-actions.js +224 -0
  43. package/packages/hu-board/public/utils/init-listeners.js +180 -0
  44. package/packages/hu-board/public/utils/log-panel.js +222 -0
  45. package/packages/hu-board/public/utils/modals.js +309 -0
  46. package/packages/hu-board/public/utils/plan-rollup-view.js +53 -0
  47. package/packages/hu-board/public/utils/preflight-view.js +89 -0
  48. package/packages/hu-board/public/utils/project-actions.js +143 -0
  49. package/packages/hu-board/public/utils/project-picker-view.js +139 -0
  50. package/packages/hu-board/public/utils/run-launcher.js +169 -0
  51. package/packages/hu-board/public/utils/server-push.js +252 -0
  52. package/packages/hu-board/public/utils/sessions-view.js +199 -0
  53. package/packages/hu-board/public/utils/story-detail-view.js +324 -0
  54. package/packages/hu-board/public/utils/story-edit-form.js +271 -0
  55. package/packages/hu-board/public/wiki.html +32 -0
  56. package/packages/hu-board/public/wiki.js +53 -0
  57. package/packages/hu-board/src/auth.js +92 -0
  58. package/packages/hu-board/src/boot-info.js +16 -0
  59. package/packages/hu-board/src/cleanup-zombies.js +145 -0
  60. package/packages/hu-board/src/command-runner.js +133 -0
  61. package/packages/hu-board/src/config-yaml.js +531 -0
  62. package/packages/hu-board/src/db.js +963 -0
  63. package/packages/hu-board/src/ephemeral-cleaner.js +196 -0
  64. package/packages/hu-board/src/event-bus.js +58 -0
  65. package/packages/hu-board/src/format.js +207 -0
  66. package/packages/hu-board/src/hu-zombie-reaper.js +103 -0
  67. package/packages/hu-board/src/journal-parser.js +180 -0
  68. package/packages/hu-board/src/plan-mutations.js +424 -0
  69. package/packages/hu-board/src/preflight.js +286 -0
  70. package/packages/hu-board/src/routes/api.js +1374 -0
  71. package/packages/hu-board/src/routes/pipeline.js +45 -0
  72. package/packages/hu-board/src/routes/rag.js +42 -0
  73. package/packages/hu-board/src/routes/wiki.js +43 -0
  74. package/packages/hu-board/src/run-tracker.js +121 -0
  75. package/packages/hu-board/src/server.js +438 -0
  76. package/packages/hu-board/src/sync.js +732 -0
  77. package/packages/hu-board/src/token-store.js +56 -0
  78. package/packages/hu-board/src/zombie-reaper.js +206 -0
  79. package/scripts/ai-attribution-guard.yml +84 -0
  80. package/scripts/audit-test-diet.mjs +151 -0
  81. package/scripts/build-sea.mjs +150 -0
  82. package/scripts/diet-baseline.mjs +170 -0
  83. package/scripts/dual-publish.mjs +67 -0
  84. package/scripts/esbuild-sea.config.mjs +273 -0
  85. package/scripts/git-hooks/post-merge +18 -0
  86. package/scripts/install-binary.ps1 +174 -0
  87. package/scripts/install-binary.sh +159 -0
  88. package/scripts/install-guard-all-repos.sh +85 -0
  89. package/scripts/install-kj.sh +193 -0
  90. package/scripts/install.js +901 -0
  91. package/scripts/install.sh +7 -0
  92. package/scripts/postinstall.js +117 -0
  93. package/scripts/protect-all-repos.sh +88 -0
  94. package/scripts/quickstart-gate.mjs +97 -0
  95. package/scripts/regen-arch-stats.sh +71 -0
  96. package/scripts/setup-multi-instance.sh +150 -0
  97. package/scripts/verify-pack.mjs +278 -0
  98. package/src/activity-log.js +59 -0
  99. package/src/agents/agy-agent.js +62 -0
  100. package/src/agents/aider-agent.js +78 -0
  101. package/src/agents/availability.js +52 -0
  102. package/src/agents/base-agent.js +134 -0
  103. package/src/agents/claude-agent.js +413 -0
  104. package/src/agents/codex-agent.js +112 -0
  105. package/src/agents/copilot-agent.js +65 -0
  106. package/src/agents/gemini-agent.js +85 -0
  107. package/src/agents/host-agent.js +38 -0
  108. package/src/agents/index.js +59 -0
  109. package/src/agents/kimi-agent.js +45 -0
  110. package/src/agents/model-registry.js +137 -0
  111. package/src/agents/opencode-agent.js +72 -0
  112. package/src/agents/qwen-agent.js +20 -0
  113. package/src/agents/resolve-bin.js +73 -0
  114. package/src/audit/agent-readiness.js +259 -0
  115. package/src/audit/ai-slop-findings.js +102 -0
  116. package/src/audit/audit-fallback.js +66 -0
  117. package/src/audit/audit-history-display.js +61 -0
  118. package/src/audit/audit-history.js +102 -0
  119. package/src/audit/basal-cost.js +281 -0
  120. package/src/audit/circular-deps.js +144 -0
  121. package/src/audit/dead-exports.js +186 -0
  122. package/src/audit/deterministic-summary.js +327 -0
  123. package/src/audit/harness-scorecard.js +100 -0
  124. package/src/audit/harness-section.js +81 -0
  125. package/src/audit/infra-findings.js +100 -0
  126. package/src/audit/injection-findings.js +114 -0
  127. package/src/audit/issue-filter.js +133 -0
  128. package/src/audit/osv-findings.js +167 -0
  129. package/src/audit/plan-adherence.js +224 -0
  130. package/src/audit/semgrep-findings.js +129 -0
  131. package/src/audit/sonar-findings.js +93 -0
  132. package/src/audit/webperf-input.js +133 -0
  133. package/src/autonomy/arbiter-role.js +71 -0
  134. package/src/autonomy/arbiter.js +22 -0
  135. package/src/autonomy/decider.js +18 -0
  136. package/src/autonomy/decision-resolver.js +58 -0
  137. package/src/autonomy/outcome-report.js +55 -0
  138. package/src/autonomy/policy.js +41 -0
  139. package/src/autonomy/stage-ask.js +30 -0
  140. package/src/bootstrap.js +276 -0
  141. package/src/brain/agent-error-classifier.js +116 -0
  142. package/src/brain/decision-tracker.js +125 -0
  143. package/src/brain/decisor.js +243 -0
  144. package/src/brain/solomon-consult.js +171 -0
  145. package/src/brain/standby-scheduler.js +8 -0
  146. package/src/brain/standby-store.js +12 -0
  147. package/src/brain/with-brain-recovery.js +235 -0
  148. package/src/budget/comparison.js +96 -0
  149. package/src/canvas/parse-md.js +238 -0
  150. package/src/canvas/schema.js +101 -0
  151. package/src/canvas/to-flat.js +85 -0
  152. package/src/canvas/validate.js +163 -0
  153. package/src/checks/ai-surface.js +79 -0
  154. package/src/checks/ai-trash.js +34 -0
  155. package/src/checks/binaries.js +207 -0
  156. package/src/checks/ci.js +105 -0
  157. package/src/checks/config-files.js +217 -0
  158. package/src/checks/dir-setup.js +103 -0
  159. package/src/checks/guarantee-level.js +38 -0
  160. package/src/checks/hardware.js +150 -0
  161. package/src/checks/harness-scorecard.js +41 -0
  162. package/src/checks/mcp-health.js +169 -0
  163. package/src/checks/method.js +73 -0
  164. package/src/checks/native-build.js +67 -0
  165. package/src/checks/node.js +70 -0
  166. package/src/checks/ollama.js +41 -0
  167. package/src/checks/orphans.js +77 -0
  168. package/src/checks/ports.js +188 -0
  169. package/src/checks/project-checks.js +245 -0
  170. package/src/checks/qmd.js +41 -0
  171. package/src/checks/rag-hooks.js +54 -0
  172. package/src/checks/release-check.js +102 -0
  173. package/src/checks/rtk.js +36 -0
  174. package/src/checks/runner.js +326 -0
  175. package/src/checks/skills.js +53 -0
  176. package/src/checks/sonar.js +67 -0
  177. package/src/checks/squeezr.js +36 -0
  178. package/src/checks/system.js +53 -0
  179. package/src/checks/tokens.js +172 -0
  180. package/src/checks/types.js +103 -0
  181. package/src/ci/dispatch.js +99 -0
  182. package/src/ci/index.js +3 -0
  183. package/src/ci/pr-diff.js +26 -0
  184. package/src/ci/repo.js +45 -0
  185. package/src/cli/_shared.js +30 -0
  186. package/src/cli/advanced-commands.js +61 -0
  187. package/src/cli/register-meta.js +772 -0
  188. package/src/cli/register-pipeline.js +335 -0
  189. package/src/cli/register-plan.js +224 -0
  190. package/src/cli/register-roles-skills.js +54 -0
  191. package/src/cli/register-sonar.js +28 -0
  192. package/src/cli/register-standby.js +26 -0
  193. package/src/cli.js +155 -0
  194. package/src/commands/advanced.js +31 -0
  195. package/src/commands/agent-run.js +63 -0
  196. package/src/commands/agents.js +105 -0
  197. package/src/commands/architect.js +123 -0
  198. package/src/commands/audit.js +430 -0
  199. package/src/commands/autorun.js +49 -0
  200. package/src/commands/board.js +458 -0
  201. package/src/commands/check.js +40 -0
  202. package/src/commands/clean.js +145 -0
  203. package/src/commands/code.js +45 -0
  204. package/src/commands/config.js +74 -0
  205. package/src/commands/discover.js +105 -0
  206. package/src/commands/doctor.js +251 -0
  207. package/src/commands/env.js +207 -0
  208. package/src/commands/harden.js +203 -0
  209. package/src/commands/hu.js +210 -0
  210. package/src/commands/identity.js +60 -0
  211. package/src/commands/init.js +950 -0
  212. package/src/commands/install-tools.js +432 -0
  213. package/src/commands/mutate.js +94 -0
  214. package/src/commands/ollama.js +44 -0
  215. package/src/commands/onboard.js +45 -0
  216. package/src/commands/plan/_shared.js +55 -0
  217. package/src/commands/plan/add-hu.js +23 -0
  218. package/src/commands/plan/delete.js +9 -0
  219. package/src/commands/plan/fix.js +99 -0
  220. package/src/commands/plan/generate.js +532 -0
  221. package/src/commands/plan/index.js +13 -0
  222. package/src/commands/plan/list.js +21 -0
  223. package/src/commands/plan/migrate-result.js +41 -0
  224. package/src/commands/plan/ready.js +46 -0
  225. package/src/commands/plan/remove-hu.js +17 -0
  226. package/src/commands/plan/share.js +85 -0
  227. package/src/commands/plan/show.js +81 -0
  228. package/src/commands/plan/unshare.js +41 -0
  229. package/src/commands/plan/validate.js +20 -0
  230. package/src/commands/plan.js +17 -0
  231. package/src/commands/policy.js +164 -0
  232. package/src/commands/privacy.js +45 -0
  233. package/src/commands/qmd.js +86 -0
  234. package/src/commands/rag-mcp.js +18 -0
  235. package/src/commands/rag.js +173 -0
  236. package/src/commands/report-issue.js +77 -0
  237. package/src/commands/report.js +469 -0
  238. package/src/commands/researcher.js +54 -0
  239. package/src/commands/resume.js +68 -0
  240. package/src/commands/review-gate.js +355 -0
  241. package/src/commands/review.js +89 -0
  242. package/src/commands/roles.js +116 -0
  243. package/src/commands/run.js +185 -0
  244. package/src/commands/scan.js +18 -0
  245. package/src/commands/skills.js +86 -0
  246. package/src/commands/sonar.js +53 -0
  247. package/src/commands/standby.js +117 -0
  248. package/src/commands/start.js +121 -0
  249. package/src/commands/status.js +36 -0
  250. package/src/commands/sync.js +103 -0
  251. package/src/commands/telemetry.js +70 -0
  252. package/src/commands/tournament.js +85 -0
  253. package/src/commands/triage.js +78 -0
  254. package/src/commands/undo.js +62 -0
  255. package/src/commands/watch.js +46 -0
  256. package/src/commands/webperf.js +162 -0
  257. package/src/commands/worktree.js +76 -0
  258. package/src/config/defaults.js +270 -0
  259. package/src/config/loader.js +204 -0
  260. package/src/config/overrides.js +220 -0
  261. package/src/config/role-resolver.js +171 -0
  262. package/src/config/schema.js +299 -0
  263. package/src/config/test-harness.js +78 -0
  264. package/src/config.js +34 -0
  265. package/src/domains/domain-loader.js +245 -0
  266. package/src/domains/domain-registry.js +140 -0
  267. package/src/domains/domain-synthesizer.js +129 -0
  268. package/src/environment/adr.js +45 -0
  269. package/src/environment/board-access.js +97 -0
  270. package/src/environment/board-select.js +59 -0
  271. package/src/environment/briefs.js +129 -0
  272. package/src/environment/issue-report.js +72 -0
  273. package/src/environment/mcp-wiring.js +44 -0
  274. package/src/environment/playbook.js +127 -0
  275. package/src/git/automation.js +334 -0
  276. package/src/git/hu-automation.js +171 -0
  277. package/src/git/hu-snapshot.js +10 -0
  278. package/src/golden/asserter.js +92 -0
  279. package/src/golden/loader.js +52 -0
  280. package/src/golden/runner.js +92 -0
  281. package/src/golden/schema.js +41 -0
  282. package/src/guards/intent-guard.js +161 -0
  283. package/src/guards/output-guard.js +149 -0
  284. package/src/guards/perf-guard.js +126 -0
  285. package/src/guards/policy-guard.js +90 -0
  286. package/src/guards/policy-resolver.js +85 -0
  287. package/src/guards/secret-redactor.js +71 -0
  288. package/src/harden/advisory.js +203 -0
  289. package/src/harden/alternatives.js +50 -0
  290. package/src/harden/check.js +81 -0
  291. package/src/harden/config-engine.js +128 -0
  292. package/src/harden/config-templates.js +122 -0
  293. package/src/harden/guidelines-engine.js +48 -0
  294. package/src/harden/guidelines-templates.js +36 -0
  295. package/src/harden/harden-engine.js +80 -0
  296. package/src/harden/harness-hooks.js +107 -0
  297. package/src/harden/hook-commands.js +25 -0
  298. package/src/harden/hook-templates.js +183 -0
  299. package/src/harden/interactive.js +76 -0
  300. package/src/harden/sentinel-hooks.js +721 -0
  301. package/src/harden/stack-roots.js +105 -0
  302. package/src/harden/test-on-push.js +38 -0
  303. package/src/harden/workflow-engine.js +116 -0
  304. package/src/harden/workflow-templates.js +285 -0
  305. package/src/hu/acceptance-runner.js +138 -0
  306. package/src/hu/auto-generator.js +358 -0
  307. package/src/hu/graph.js +71 -0
  308. package/src/hu/lazy-planner.js +109 -0
  309. package/src/hu/model-router.js +108 -0
  310. package/src/hu/parallel-executor.js +94 -0
  311. package/src/hu/split-validator.js +143 -0
  312. package/src/hu/splitting-detector.js +158 -0
  313. package/src/hu/splitting-generator.js +175 -0
  314. package/src/hu/store.js +392 -0
  315. package/src/hu/worktree-bootstrap.js +59 -0
  316. package/src/identity/bootstrap.js +48 -0
  317. package/src/identity/compare.js +38 -0
  318. package/src/identity/detect.js +51 -0
  319. package/src/identity/store.js +66 -0
  320. package/src/infrastructure/command-runner.js +44 -0
  321. package/src/infrastructure/environment.js +38 -0
  322. package/src/infrastructure/file-system-service.js +63 -0
  323. package/src/infrastructure/mocks.js +182 -0
  324. package/src/lang/chunk-go.js +94 -0
  325. package/src/lang/chunk-java.js +90 -0
  326. package/src/lang/chunk-python.js +88 -0
  327. package/src/lang/chunk-rust.js +102 -0
  328. package/src/lang/go.js +14 -0
  329. package/src/lang/java.js +16 -0
  330. package/src/lang/js.js +8 -0
  331. package/src/lang/python.js +14 -0
  332. package/src/lang/registry.js +79 -0
  333. package/src/lang/rust.js +14 -0
  334. package/src/lang/tree-sitter-loader.js +45 -0
  335. package/src/mcp/direct-role-runner.js +112 -0
  336. package/src/mcp/error-classifiers.js +66 -0
  337. package/src/mcp/handlers/direct-handlers.js +486 -0
  338. package/src/mcp/handlers/hu-handlers.js +93 -0
  339. package/src/mcp/handlers/management-handlers.js +265 -0
  340. package/src/mcp/handlers/rag-handler.js +52 -0
  341. package/src/mcp/handlers/run-handler.js +313 -0
  342. package/src/mcp/orphan-guard.js +131 -0
  343. package/src/mcp/preflight.js +47 -0
  344. package/src/mcp/progress.js +149 -0
  345. package/src/mcp/response-compressor.js +81 -0
  346. package/src/mcp/run-kj.js +135 -0
  347. package/src/mcp/server-handlers.js +79 -0
  348. package/src/mcp/server.js +66 -0
  349. package/src/mcp/shared-helpers.js +297 -0
  350. package/src/mcp/sovereignty-guard.js +112 -0
  351. package/src/mcp/suggest-handler.js +92 -0
  352. package/src/mcp/tool-arg-normalizers.js +16 -0
  353. package/src/mcp/tools.js +432 -0
  354. package/src/mutate/diff-scope.js +105 -0
  355. package/src/mutate/reviewer-signal.js +76 -0
  356. package/src/mutate/runner.js +72 -0
  357. package/src/mutate/tool-registry.js +90 -0
  358. package/src/onboarder/cache.js +24 -0
  359. package/src/onboarder/collectors/framework-multilang.js +64 -0
  360. package/src/onboarder/collectors/index.js +136 -0
  361. package/src/orchestrator/agent-fallback.js +81 -0
  362. package/src/orchestrator/brain-coordinator.js +186 -0
  363. package/src/orchestrator/ci-integration.js +139 -0
  364. package/src/orchestrator/config-init.js +510 -0
  365. package/src/orchestrator/direct-actions.js +217 -0
  366. package/src/orchestrator/drivers/error-recovery.js +287 -0
  367. package/src/orchestrator/drivers/init-context.js +227 -0
  368. package/src/orchestrator/drivers/iteration-loop.js +380 -0
  369. package/src/orchestrator/drivers/iteration-phases/coder-and-refactorer.js +69 -0
  370. package/src/orchestrator/drivers/iteration-phases/guards.js +84 -0
  371. package/src/orchestrator/drivers/iteration-phases/handle-approved.js +29 -0
  372. package/src/orchestrator/drivers/iteration-phases/quality-gates.js +114 -0
  373. package/src/orchestrator/drivers/iteration-phases/reviewer-gate.js +60 -0
  374. package/src/orchestrator/drivers/post-loop.js +383 -0
  375. package/src/orchestrator/drivers/pre-loop-phases/auto-hu-batch.js +136 -0
  376. package/src/orchestrator/drivers/pre-loop-phases/config-deprecations.js +47 -0
  377. package/src/orchestrator/drivers/pre-loop-phases/ensure-addyosmani-skills.js +84 -0
  378. package/src/orchestrator/drivers/pre-loop-phases/inject-loaded-plan.js +391 -0
  379. package/src/orchestrator/drivers/pre-loop.js +507 -0
  380. package/src/orchestrator/drivers/run-hu-batch.js +427 -0
  381. package/src/orchestrator/feedback-enrichment.js +140 -0
  382. package/src/orchestrator/feedback-queue.js +151 -0
  383. package/src/orchestrator/flow-control.js +170 -0
  384. package/src/orchestrator/flow-runner.js +364 -0
  385. package/src/orchestrator/fs-leak-detector.js +210 -0
  386. package/src/orchestrator/hu-scheduler.js +114 -0
  387. package/src/orchestrator/hu-sub-pipeline.js +616 -0
  388. package/src/orchestrator/integrations.js +81 -0
  389. package/src/orchestrator/iteration-gate.js +73 -0
  390. package/src/orchestrator/iteration-stages.js +9 -0
  391. package/src/orchestrator/parallel-limiter.js +74 -0
  392. package/src/orchestrator/pipeline-context.js +72 -0
  393. package/src/orchestrator/post-loop-stages.js +468 -0
  394. package/src/orchestrator/pre-loop-stages.js +11 -0
  395. package/src/orchestrator/preflight-checks.js +462 -0
  396. package/src/orchestrator/repair/repair-detector.js +117 -0
  397. package/src/orchestrator/repair/repair-runner.js +142 -0
  398. package/src/orchestrator/reviewer-fallback.js +45 -0
  399. package/src/orchestrator/role-output-compressor.js +189 -0
  400. package/src/orchestrator/session-journal.js +308 -0
  401. package/src/orchestrator/solomon-escalation.js +305 -0
  402. package/src/orchestrator/solomon-rules.js +212 -0
  403. package/src/orchestrator/stages/architect-stage.js +172 -0
  404. package/src/orchestrator/stages/coder-stage.js +480 -0
  405. package/src/orchestrator/stages/domain-curator-stage.js +82 -0
  406. package/src/orchestrator/stages/hu-reviewer-phases/detect-and-apply-splits.js +127 -0
  407. package/src/orchestrator/stages/hu-reviewer-stage.js +394 -0
  408. package/src/orchestrator/stages/perf-stage.js +140 -0
  409. package/src/orchestrator/stages/planner-stage.js +85 -0
  410. package/src/orchestrator/stages/rag-context-stage.js +77 -0
  411. package/src/orchestrator/stages/rag-preload-decisor.js +58 -0
  412. package/src/orchestrator/stages/research-stage.js +69 -0
  413. package/src/orchestrator/stages/reviewer-stage.js +422 -0
  414. package/src/orchestrator/stages/sonar-stage.js +421 -0
  415. package/src/orchestrator/stages/stage-classes.js +84 -0
  416. package/src/orchestrator/stages/stage-executor.js +155 -0
  417. package/src/orchestrator/stages/tdd-discipline-stage.js +56 -0
  418. package/src/orchestrator/stages/tool-judge-stage.js +53 -0
  419. package/src/orchestrator/stages/triage-stage.js +172 -0
  420. package/src/orchestrator/standby.js +71 -0
  421. package/src/orchestrator/verification-gate.js +183 -0
  422. package/src/orchestrator.js +22 -0
  423. package/src/plan/adr-generator.js +170 -0
  424. package/src/plan/adr-loader.js +60 -0
  425. package/src/plan/plan-executor.js +100 -0
  426. package/src/plan/plan-fixer.js +192 -0
  427. package/src/plan/plan-hu-ops.js +16 -0
  428. package/src/plan/plan-id.js +4 -0
  429. package/src/plan/plan-migrate-result.js +24 -0
  430. package/src/plan/plan-reviewer.js +236 -0
  431. package/src/plan/plan-schema.js +334 -0
  432. package/src/plan/plan-store.js +260 -0
  433. package/src/plan/plan-structural-pass.js +122 -0
  434. package/src/plan/plan-validation.js +4 -0
  435. package/src/plan/preflight-hu.js +105 -0
  436. package/src/plan/spec-detector.js +61 -0
  437. package/src/plan/tests-synthesizer.js +131 -0
  438. package/src/planning-game/adapter.js +108 -0
  439. package/src/planning-game/architect-adrs.js +45 -0
  440. package/src/planning-game/client.js +108 -0
  441. package/src/planning-game/decomposition.js +87 -0
  442. package/src/planning-game/pipeline-adapter.js +251 -0
  443. package/src/plugins/loader.js +67 -0
  444. package/src/policy/add.js +111 -0
  445. package/src/policy/decisions.js +42 -0
  446. package/src/policy/engine.js +82 -0
  447. package/src/policy/exceptions.js +60 -0
  448. package/src/privacy/onboarding.js +35 -0
  449. package/src/privacy/scan.js +120 -0
  450. package/src/prompts/arbiter.js +38 -0
  451. package/src/prompts/architect.js +103 -0
  452. package/src/prompts/audit.js +474 -0
  453. package/src/prompts/coder.js +287 -0
  454. package/src/prompts/diff-clip.js +27 -0
  455. package/src/prompts/discover.js +222 -0
  456. package/src/prompts/hu-reviewer.js +219 -0
  457. package/src/prompts/planner.js +312 -0
  458. package/src/prompts/prompt-layout.js +80 -0
  459. package/src/prompts/prompt-resolver.js +120 -0
  460. package/src/prompts/reviewer.js +75 -0
  461. package/src/prompts/rtk-snippet.js +25 -0
  462. package/src/prompts/spec-reviewer.js +66 -0
  463. package/src/prompts/split-signal.js +82 -0
  464. package/src/prompts/start-decision.js +52 -0
  465. package/src/prompts/tool-correctness-judge.js +31 -0
  466. package/src/prompts/triage.js +57 -0
  467. package/src/rag/auto-update.js +72 -0
  468. package/src/rag/chunker-ast.js +56 -0
  469. package/src/rag/chunker.js +132 -0
  470. package/src/rag/embedder.js +2 -0
  471. package/src/rag/embedders/_cloud-base.js +2 -0
  472. package/src/rag/embedders/cohere.js +2 -0
  473. package/src/rag/embedders/factory.js +2 -0
  474. package/src/rag/embedders/mistral.js +2 -0
  475. package/src/rag/embedders/onnx.js +2 -0
  476. package/src/rag/embedders/openai.js +2 -0
  477. package/src/rag/embedders/voyage.js +2 -0
  478. package/src/rag/eval.js +61 -0
  479. package/src/rag/governed-embedder.js +39 -0
  480. package/src/rag/indexer.js +199 -0
  481. package/src/rag/library.js +62 -0
  482. package/src/rag/ollama-capability.js +59 -0
  483. package/src/rag/ollama-manager.js +98 -0
  484. package/src/rag/onnx-fallback.js +69 -0
  485. package/src/rag/rerank.js +4 -0
  486. package/src/rag/retriever.js +2 -0
  487. package/src/rag/vec-store.js +17 -0
  488. package/src/rag/watcher.js +62 -0
  489. package/src/rag/where-parser.js +4 -0
  490. package/src/repeat-detector.js +88 -0
  491. package/src/review/card-first.js +99 -0
  492. package/src/review/card-verify.js +83 -0
  493. package/src/review/diff-generator.js +112 -0
  494. package/src/review/gate-gitignore.js +77 -0
  495. package/src/review/git-stash-helper.js +104 -0
  496. package/src/review/mutation-pregate.js +48 -0
  497. package/src/review/one-shot-review.js +122 -0
  498. package/src/review/parser.js +80 -0
  499. package/src/review/policy-gate.js +26 -0
  500. package/src/review/profiles.js +66 -0
  501. package/src/review/reviewer-fallback.js +125 -0
  502. package/src/review/schema.js +31 -0
  503. package/src/review/scope-filter.js +152 -0
  504. package/src/review/snapshot-diff.js +122 -0
  505. package/src/review/solomon-arbitration.js +113 -0
  506. package/src/review/sonar-pregate.js +63 -0
  507. package/src/review/tdd-discipline.js +90 -0
  508. package/src/review/tdd-policy.js +69 -0
  509. package/src/review/tests-with-code.js +33 -0
  510. package/src/review/verdict-store.js +87 -0
  511. package/src/review/workspace.js +21 -0
  512. package/src/roles/agent-role.js +194 -0
  513. package/src/roles/architect-role.js +77 -0
  514. package/src/roles/audit-role.js +258 -0
  515. package/src/roles/base-role.js +165 -0
  516. package/src/roles/coder-role.js +107 -0
  517. package/src/roles/commiter-role.js +110 -0
  518. package/src/roles/discover-role.js +81 -0
  519. package/src/roles/domain-curator-role.js +141 -0
  520. package/src/roles/hu-reviewer-role.js +64 -0
  521. package/src/roles/impeccable-role.js +85 -0
  522. package/src/roles/index.js +18 -0
  523. package/src/roles/karajan-brain-role.js +134 -0
  524. package/src/roles/onboarder-role.js +61 -0
  525. package/src/roles/perf-role.js +122 -0
  526. package/src/roles/planner-role.js +151 -0
  527. package/src/roles/refactorer-role.js +30 -0
  528. package/src/roles/repairer-role.js +181 -0
  529. package/src/roles/researcher-role.js +70 -0
  530. package/src/roles/reviewer-role.js +104 -0
  531. package/src/roles/security-role.js +73 -0
  532. package/src/roles/solomon-role.js +265 -0
  533. package/src/roles/sonar-role.js +70 -0
  534. package/src/roles/spec-reviewer-role.js +106 -0
  535. package/src/roles/tester-role.js +235 -0
  536. package/src/roles/tool-correctness-judge-role.js +78 -0
  537. package/src/roles/triage-role.js +99 -0
  538. package/src/session/journal/decisions-writer.js +200 -0
  539. package/src/session/journal/iteration-logger.js +194 -0
  540. package/src/session/journal/summary-writer.js +320 -0
  541. package/src/session/journal/tree-writer.js +164 -0
  542. package/src/session/journal/write-all.js +89 -0
  543. package/src/session/mutators.js +339 -0
  544. package/src/session/runtime-overrides.js +59 -0
  545. package/src/session/store.js +106 -0
  546. package/src/session-cleanup.js +116 -0
  547. package/src/skills/addyosmani-catalog.js +315 -0
  548. package/src/skills/addyosmani-role-map.js +139 -0
  549. package/src/skills/openskills-client.js +157 -0
  550. package/src/skills/semantic-detector.js +167 -0
  551. package/src/skills/skill-detector.js +385 -0
  552. package/src/skills/skill-loader.js +219 -0
  553. package/src/skills/skills-cache.js +128 -0
  554. package/src/sonar/api.js +128 -0
  555. package/src/sonar/cloud-scanner.js +78 -0
  556. package/src/sonar/config-resolver.js +88 -0
  557. package/src/sonar/credentials.js +60 -0
  558. package/src/sonar/discovery.js +124 -0
  559. package/src/sonar/enforcer.js +19 -0
  560. package/src/sonar/issue-filter.js +12 -0
  561. package/src/sonar/manager.js +181 -0
  562. package/src/sonar/project-key.js +120 -0
  563. package/src/sonar/scanner.js +307 -0
  564. package/src/sonar/token-bootstrap.js +205 -0
  565. package/src/sonar/token-recovery.js +67 -0
  566. package/src/spec-review/refine-loop.js +58 -0
  567. package/src/spec-review/run-spec-review.js +119 -0
  568. package/src/start/assessment.js +74 -0
  569. package/src/start/maturity.js +73 -0
  570. package/src/start/start-decider-role.js +79 -0
  571. package/src/start/sweep.js +157 -0
  572. package/src/sync/apply-canvas-patch.js +55 -0
  573. package/src/sync/detect-drift.js +113 -0
  574. package/src/tournament/crown.js +88 -0
  575. package/src/tournament/judge.js +150 -0
  576. package/src/tournament/run.js +142 -0
  577. package/src/tournament/scoreboard.js +124 -0
  578. package/src/tracker-bootstrap.js +44 -0
  579. package/src/types/agent.js +55 -0
  580. package/src/types/config.js +114 -0
  581. package/src/types/hu.js +47 -0
  582. package/src/types/index.js +38 -0
  583. package/src/types/policy.js +43 -0
  584. package/src/types/session.js +75 -0
  585. package/src/types/solomon.js +87 -0
  586. package/src/types/stage.js +68 -0
  587. package/src/utils/agent-detect.js +93 -0
  588. package/src/utils/ai-trash.js +48 -0
  589. package/src/utils/async-lock.js +31 -0
  590. package/src/utils/atomic-write.js +6 -0
  591. package/src/utils/banner.js +66 -0
  592. package/src/utils/binary-sources.js +70 -0
  593. package/src/utils/board-prompt-bridge.js +108 -0
  594. package/src/utils/budget.js +229 -0
  595. package/src/utils/cli-ask-question.js +93 -0
  596. package/src/utils/cli-progress.js +220 -0
  597. package/src/utils/cli-run-log.js +83 -0
  598. package/src/utils/cwd-confirm.js +39 -0
  599. package/src/utils/derive-project-name-from-cwd.js +119 -0
  600. package/src/utils/display/event-handlers.js +403 -0
  601. package/src/utils/display/formatters.js +132 -0
  602. package/src/utils/display/header.js +47 -0
  603. package/src/utils/display/resume-hint.js +41 -0
  604. package/src/utils/display/session-summary.js +118 -0
  605. package/src/utils/display/solomon.js +42 -0
  606. package/src/utils/display/spec-findings.js +44 -0
  607. package/src/utils/doc-links.js +29 -0
  608. package/src/utils/docker-install.js +34 -0
  609. package/src/utils/escape-regexp.js +15 -0
  610. package/src/utils/events.js +35 -0
  611. package/src/utils/fs.js +19 -0
  612. package/src/utils/garbage-collector.js +481 -0
  613. package/src/utils/git.js +279 -0
  614. package/src/utils/home-migration.js +87 -0
  615. package/src/utils/injection-guard.js +186 -0
  616. package/src/utils/install-hints.js +180 -0
  617. package/src/utils/json-extract.js +64 -0
  618. package/src/utils/locale.js +59 -0
  619. package/src/utils/logger.js +96 -0
  620. package/src/utils/managed-markers.js +93 -0
  621. package/src/utils/manifest-sniff.js +82 -0
  622. package/src/utils/messages.js +61 -0
  623. package/src/utils/model-selector.js +107 -0
  624. package/src/utils/os-detect.js +79 -0
  625. package/src/utils/paths.js +13 -0
  626. package/src/utils/pending-user-action.js +95 -0
  627. package/src/utils/port-check.js +6 -0
  628. package/src/utils/port-occupant.js +96 -0
  629. package/src/utils/pricing.js +29 -0
  630. package/src/utils/process.js +4 -0
  631. package/src/utils/project-detect.js +160 -0
  632. package/src/utils/prompt-project-name.js +35 -0
  633. package/src/utils/provider-env.js +116 -0
  634. package/src/utils/qmd-collection.js +72 -0
  635. package/src/utils/qmd-detect.js +18 -0
  636. package/src/utils/qmd-install.js +37 -0
  637. package/src/utils/quota-simulator.js +56 -0
  638. package/src/utils/rate-limit-detector.js +181 -0
  639. package/src/utils/repo-cleaner.js +79 -0
  640. package/src/utils/retry.js +88 -0
  641. package/src/utils/role-assigner.js +137 -0
  642. package/src/utils/role-env.js +58 -0
  643. package/src/utils/rtk-detect.js +18 -0
  644. package/src/utils/rtk-install.js +38 -0
  645. package/src/utils/rtk-wrapper.js +87 -0
  646. package/src/utils/run-context.js +75 -0
  647. package/src/utils/run-log.js +217 -0
  648. package/src/utils/run-registry.js +9 -0
  649. package/src/utils/shared-paths.js +12 -0
  650. package/src/utils/squeezr-detect.js +21 -0
  651. package/src/utils/squeezr-install.js +37 -0
  652. package/src/utils/stack-detect.js +135 -0
  653. package/src/utils/stall-detector.js +159 -0
  654. package/src/utils/status-dashboard.js +254 -0
  655. package/src/utils/task-file.js +109 -0
  656. package/src/utils/telemetry.js +124 -0
  657. package/src/utils/templates-root.js +61 -0
  658. package/src/utils/tool-call-extractor.js +56 -0
  659. package/src/utils/tool-governor.js +116 -0
  660. package/src/utils/tool-installer.js +93 -0
  661. package/src/utils/update-check.js +280 -0
  662. package/src/utils/vector-store-orphans.js +89 -0
  663. package/src/utils/welcome.js +47 -0
  664. package/src/utils/with-timeout.js +42 -0
  665. package/src/utils/wizard.js +47 -0
  666. package/src/webperf/cwv-gate.js +94 -0
  667. package/src/webperf/devtools-detect.js +112 -0
  668. package/src/webperf/scanner.js +209 -0
  669. package/src/webperf/webperf-role-integration.js +66 -0
  670. package/templates/coder-rules.md +45 -0
  671. package/templates/docker-compose.sonar.yml +60 -0
  672. package/templates/domains/example-dental.md +57 -0
  673. package/templates/kj.config.yml +128 -0
  674. package/templates/review-rules.md +17 -0
  675. package/templates/roles/architect/anthropic.md +74 -0
  676. package/templates/roles/architect/default.md +72 -0
  677. package/templates/roles/architect/google.md +61 -0
  678. package/templates/roles/architect/openai.md +60 -0
  679. package/templates/roles/architect/opencode.md +59 -0
  680. package/templates/roles/architect.md +76 -0
  681. package/templates/roles/audit.md +68 -0
  682. package/templates/roles/coder/anthropic.md +81 -0
  683. package/templates/roles/coder/default.md +78 -0
  684. package/templates/roles/coder/google.md +87 -0
  685. package/templates/roles/coder/openai.md +68 -0
  686. package/templates/roles/coder/opencode.md +58 -0
  687. package/templates/roles/coder.md +152 -0
  688. package/templates/roles/commiter.md +44 -0
  689. package/templates/roles/discover.md +167 -0
  690. package/templates/roles/domain-curator.md +52 -0
  691. package/templates/roles/hu-reviewer.md +236 -0
  692. package/templates/roles/impeccable-design.md +87 -0
  693. package/templates/roles/impeccable.md +125 -0
  694. package/templates/roles/karajan-brain.md +95 -0
  695. package/templates/roles/onboarder.md +45 -0
  696. package/templates/roles/planner/anthropic.md +59 -0
  697. package/templates/roles/planner/default.md +57 -0
  698. package/templates/roles/planner/google.md +75 -0
  699. package/templates/roles/planner/openai.md +55 -0
  700. package/templates/roles/planner/opencode.md +62 -0
  701. package/templates/roles/planner.md +61 -0
  702. package/templates/roles/refactorer.md +48 -0
  703. package/templates/roles/repairer.md +103 -0
  704. package/templates/roles/researcher.md +41 -0
  705. package/templates/roles/reviewer/anthropic.md +61 -0
  706. package/templates/roles/reviewer/default.md +62 -0
  707. package/templates/roles/reviewer/google.md +63 -0
  708. package/templates/roles/reviewer/openai.md +57 -0
  709. package/templates/roles/reviewer/opencode.md +42 -0
  710. package/templates/roles/reviewer-paranoid.md +38 -0
  711. package/templates/roles/reviewer-relaxed.md +34 -0
  712. package/templates/roles/reviewer-strict.md +37 -0
  713. package/templates/roles/reviewer.md +62 -0
  714. package/templates/roles/security.md +54 -0
  715. package/templates/roles/solomon/anthropic.md +71 -0
  716. package/templates/roles/solomon/default.md +83 -0
  717. package/templates/roles/solomon/google.md +61 -0
  718. package/templates/roles/solomon/openai.md +53 -0
  719. package/templates/roles/solomon/opencode.md +55 -0
  720. package/templates/roles/solomon.md +83 -0
  721. package/templates/roles/sonar.md +49 -0
  722. package/templates/roles/spec-reviewer.md +47 -0
  723. package/templates/roles/tester.md +50 -0
  724. package/templates/roles/triage.md +69 -0
  725. package/templates/skills/kj-architect.md +45 -0
  726. package/templates/skills/kj-audit.md +63 -0
  727. package/templates/skills/kj-board.md +16 -0
  728. package/templates/skills/kj-code.md +51 -0
  729. package/templates/skills/kj-csv-transform.md +40 -0
  730. package/templates/skills/kj-data-report.md +44 -0
  731. package/templates/skills/kj-discover.md +24 -0
  732. package/templates/skills/kj-rag-query.md +50 -0
  733. package/templates/skills/kj-review.md +47 -0
  734. package/templates/skills/kj-run.md +73 -0
  735. package/templates/skills/kj-security.md +49 -0
  736. package/templates/skills/kj-sonar.md +41 -0
  737. package/templates/skills/kj-sql-analysis.md +40 -0
  738. package/templates/skills/kj-test.md +40 -0
  739. package/templates/workflows/automerge.yml +30 -0
  740. package/templates/workflows/houston-override.yml +46 -0
  741. package/templates/workflows/kj-ci-gateway.yml +58 -0
  742. package/vendor/tree-sitter-grammars/README.md +21 -0
  743. package/vendor/tree-sitter-grammars/go.wasm +0 -0
  744. package/vendor/tree-sitter-grammars/java.wasm +0 -0
  745. package/vendor/tree-sitter-grammars/python.wasm +0 -0
  746. package/vendor/tree-sitter-grammars/rust.wasm +0 -0
@@ -0,0 +1,227 @@
1
+ /**
2
+ * Init-context driver — extracted from src/orchestrator/flow-runner.js in
3
+ * TSK-0335 (Oleada 3 of the v2.7.4 audit refactor).
4
+ *
5
+ * Builds the PipelineContext for runFlow: loads config, resolves roles,
6
+ * wires budget tracker, attaches RTK wrappers, starts the HU Board,
7
+ * loads product context, creates the session, runs the pre-loop stages,
8
+ * and sets up the session journal + git automation.
9
+ *
10
+ * Extracted verbatim; no behavior change. Split from pre-loop.js because
11
+ * together they would exceed the 600-LOC/driver ceiling set by the
12
+ * TSK-0335 acceptance criteria.
13
+ */
14
+
15
+ import { createAgent } from "../../agents/index.js";
16
+ import { resolveRole } from "../../config.js";
17
+ import { resolveReviewProfile } from "../../review/profiles.js";
18
+ import { RepeatDetector, getRepeatThreshold } from "../../repeat-detector.js";
19
+ import { emitProgress, makeEvent } from "../../utils/events.js";
20
+ import { prepareGitAutomation } from "../../git/automation.js";
21
+ import { CoderRole } from "../../roles/coder-role.js";
22
+ import { PipelineContext } from "../pipeline-context.js";
23
+ import { detectRtk } from "../../utils/rtk-detect.js";
24
+ import { RtkSavingsTracker } from "../../utils/rtk-wrapper.js";
25
+ import { setProjectDir as setDiffProjectDir } from "../../review/diff-generator.js";
26
+ import {
27
+ loadProductContext, resolvePipelineFlags, createBudgetManager,
28
+ initializeSession, autoInit,
29
+ } from "../config-init.js";
30
+ import {
31
+ createJournalDir, writePreLoopJournal, buildPlanSummary,
32
+ } from "../session-journal.js";
33
+ import { setPgCard, setJournalContext } from "../../session/mutators.js";
34
+ import { getRunContext } from "../../utils/run-context.js";
35
+ import { getIntegration } from "../integrations.js";
36
+ import { tryAutoStartBoard } from "./post-loop.js";
37
+ import { runPreLoopStages } from "./pre-loop.js";
38
+
39
+ export async function initFlowContext({ task, config, logger, emitter, askQuestion, pgTaskId, pgProject, flags }) {
40
+ // Auto-init .karajan/ if missing (copies coder-rules, review-rules, role templates)
41
+ const initProjectDir = config.projectDir || process.cwd();
42
+ await autoInit(initProjectDir, logger);
43
+
44
+ // Smart role assignment: detect installed AIs and assign to roles
45
+ // Only runs if: (a) no roles configured AND (b) not in test environment
46
+ const needsAssignment = !config.roles?.coder?.provider && !config.coder && process.env.NODE_ENV !== "test" && !process.env.VITEST;
47
+ if (needsAssignment) {
48
+ try {
49
+ const { autoAssignRoles, applyRoleAssignments } = await import("../../utils/role-assigner.js");
50
+ const { assignments } = await autoAssignRoles(logger);
51
+ if (assignments) config = applyRoleAssignments({ ...config }, assignments);
52
+ } catch { /* non-blocking — defaults will be used */ }
53
+ }
54
+
55
+ // Scope all git diffs to projectDir (prevents leaking unrelated branch changes)
56
+ // When running from a subdirectory of a git repo, use relative path as scope
57
+ let diffScope = config.projectDir || null;
58
+ if (!diffScope) {
59
+ try {
60
+ // Audit follow-up: same execSync→execFileSync migration as #555.
61
+ const { execFileSync } = await import("node:child_process");
62
+ const repoRoot = execFileSync("git", ["rev-parse", "--show-toplevel"], { encoding: "utf8" }).trim();
63
+ const cwd = process.cwd();
64
+ if (cwd !== repoRoot && cwd.startsWith(repoRoot)) {
65
+ diffScope = cwd.slice(repoRoot.length + 1);
66
+ logger.info(`Running from subdirectory — diff scoped to ${diffScope}/`);
67
+ }
68
+ } catch { /* git not available */ }
69
+ }
70
+ // TSK-0338: write into the per-run AsyncLocalStorage context instead of
71
+ // mutating module-level state. Falls back to setDiffProjectDir() when no
72
+ // run context is active (legacy CLI callers, tests not going through
73
+ // runFlow). The write-to-both keeps back-compat without trading isolation.
74
+ const runCtx = getRunContext();
75
+ if (runCtx) runCtx.projectDir = diffScope;
76
+ else setDiffProjectDir(diffScope);
77
+
78
+ // Auto-detect Chrome DevTools MCP
79
+ const { detectDevToolsMcp } = await import("../../webperf/devtools-detect.js");
80
+ const devToolsAvailable = await detectDevToolsMcp(logger);
81
+ if (devToolsAvailable) {
82
+ config = { ...config, webperf: { ...config.webperf, devtools_mcp: true } };
83
+ }
84
+
85
+ const ctx = new PipelineContext({ config, session: null, logger, emitter, task, flags });
86
+ ctx.askQuestion = askQuestion;
87
+ ctx.pgTaskId = pgTaskId;
88
+ ctx.pgProject = pgProject;
89
+
90
+ ctx.coderRole = resolveRole(config, "coder");
91
+ ctx.reviewerRole = resolveRole(config, "reviewer");
92
+ ctx.refactorerRole = resolveRole(config, "refactorer");
93
+ ctx.pipelineFlags = resolvePipelineFlags(config);
94
+ ctx.repeatDetector = new RepeatDetector({ threshold: getRepeatThreshold(config) });
95
+ ctx.coderRoleInstance = new CoderRole({ config, logger, emitter, createAgentFn: createAgent, askHost: askQuestion });
96
+ ctx.startedAt = Date.now();
97
+ ctx.eventBase = { sessionId: null, iteration: 0, stage: null, startedAt: ctx.startedAt };
98
+ const { budgetTracker, budgetLimit, budgetSummary, trackBudget } = createBudgetManager({
99
+ config,
100
+ emitter,
101
+ eventBase: ctx.eventBase,
102
+ // Provides fresh compression data for "With KJ vs Without KJ" comparison
103
+ // (KJC-TSK-0274). Invoked on every budgetSummary() call.
104
+ getCompressionStats: () => ({
105
+ rtkSavings: ctx.rtkTracker?.hasData() ? ctx.rtkTracker.summary() : (ctx.session?.rtk_savings || null),
106
+ brainCtx: ctx.brainCtx || null,
107
+ }),
108
+ });
109
+ ctx.budgetTracker = budgetTracker;
110
+ ctx.budgetLimit = budgetLimit;
111
+ ctx.budgetSummary = budgetSummary;
112
+ ctx.trackBudget = trackBudget;
113
+
114
+ // --- RTK detection ---
115
+ const rtkResult = await detectRtk();
116
+ if (rtkResult.available) {
117
+ config = { ...config, rtk: { available: true, version: rtkResult.version } };
118
+ // KJC-BUG-0115: rtk MUST NOT wrap the pipeline's internal git/diff
119
+ // commands. `rtk git diff` emits a compressed summary without
120
+ // `diff --git` headers, so every consumer that parses the output
121
+ // (tdd-policy extractChangedFiles, reviewer diffs, status checks)
122
+ // sees an empty change set — in the field this made the TDD gate
123
+ // fail forever with "(2 src, 0 test)" while real tests existed.
124
+ // RTK still saves tokens where it belongs: inside the coder agent's
125
+ // own shell, via its Claude Code hook. Detection is kept so the
126
+ // config advertises availability to agents.
127
+ ctx.rtkTracker = new RtkSavingsTracker();
128
+ logger.info(`RTK detected (${rtkResult.version}) — available to agents (internal git/diff stay unwrapped)`);
129
+ emitProgress(emitter, makeEvent("rtk:detected", ctx.eventBase, {
130
+ message: "RTK detected — available to agents",
131
+ detail: { version: rtkResult.version, executorType: "local" }
132
+ }));
133
+ }
134
+
135
+ // --- HU Board auto-start ---
136
+ await tryAutoStartBoard(config, logger, emitter, ctx.eventBase);
137
+
138
+ // --- Product Context ---
139
+ const ctxProjectDir = config.projectDir || process.cwd();
140
+ const { content: productContext, source: productContextSource } = await loadProductContext(ctxProjectDir);
141
+ if (productContext) {
142
+ config = { ...config, productContext };
143
+ logger.info(`Product context loaded from ${productContextSource}`);
144
+ emitProgress(emitter, makeEvent("context:loaded", ctx.eventBase, {
145
+ message: "Product context loaded",
146
+ detail: { source: productContextSource }
147
+ }));
148
+ }
149
+
150
+ ctx.session = await initializeSession({ task, config, flags, pgTaskId, pgProject });
151
+ ctx.eventBase.sessionId = ctx.session.id;
152
+
153
+ // Karajan Brain: initialize runtime context (opt-in via config.brain.enabled)
154
+ const { createBrainContext, isBrainEnabled } = await import("../brain-coordinator.js");
155
+ ctx.brainCtx = createBrainContext({ enabled: isBrainEnabled(config) });
156
+ if (ctx.brainCtx.enabled) {
157
+ logger.info("Karajan Brain enabled — feedback queue, verification, compression active");
158
+ }
159
+
160
+ const trackerResult = await getIntegration("tracker")?.onSessionStart?.({
161
+ session: ctx.session, config, logger, pgTaskId, pgProject,
162
+ });
163
+ ctx.pgCard = trackerResult?.pgCard ?? null;
164
+ setPgCard(ctx.session, ctx.pgCard || null);
165
+
166
+ emitProgress(
167
+ emitter,
168
+ makeEvent("session:start", ctx.eventBase, {
169
+ message: "Session started",
170
+ detail: { task, coder: ctx.coderRole.provider, reviewer: ctx.reviewerRole.provider, maxIterations: config.max_iterations }
171
+ })
172
+ );
173
+
174
+ // KJC-BUG-0058: on `kj resume`, rehydrate stage results from the loaded
175
+ // session so completed pre-loop stages (researcher, architect, planner…)
176
+ // are skipped instead of re-executed. `setStageResult` mirrors writes
177
+ // into both `stage_results` (full payload) and `stages_completed` (flat
178
+ // array) — copying `stage_results` here is sufficient because
179
+ // `runPreLoopStages` only checks membership in `stageResults`.
180
+ ctx.stageResults = { ...(ctx.session?.stage_results || {}) };
181
+ ctx.sonarState = { issuesInitial: null, issuesFinal: null };
182
+
183
+ const preLoopResult = await runPreLoopStages({ config, logger, emitter, eventBase: ctx.eventBase, session: ctx.session, flags, pipelineFlags: ctx.pipelineFlags, coderRole: ctx.coderRole, trackBudget: ctx.trackBudget, task, askQuestion, pgTaskId, pgProject, stageResults: ctx.stageResults, brainCtx: ctx.brainCtx });
184
+ ctx.plannedTask = preLoopResult.plannedTask;
185
+ ctx.config = preLoopResult.updatedConfig;
186
+
187
+ // --- Session Journal: persist pre-loop outputs + display plan summary ---
188
+ const reportDir = ctx.config.output?.report_dir || ".reviews";
189
+ try {
190
+ ctx.journalDir = await createJournalDir(reportDir, ctx.session.id);
191
+ const journalFiles = await writePreLoopJournal(ctx.journalDir, ctx.stageResults);
192
+ ctx.journalFiles = journalFiles;
193
+ ctx.journalIterations = [];
194
+ ctx.journalDecisions = [];
195
+
196
+ // Attach journal state to session so finalizeApprovedSession can access it
197
+ setJournalContext(ctx.session, {
198
+ dir: ctx.journalDir,
199
+ files: journalFiles,
200
+ iterations: ctx.journalIterations,
201
+ decisions: ctx.journalDecisions,
202
+ startedAt: ctx.startedAt,
203
+ });
204
+
205
+ // Display plan summary in console before iteration loop
206
+ const planSummary = buildPlanSummary({
207
+ pipelineFlags: ctx.pipelineFlags,
208
+ config: ctx.config,
209
+ stageResults: ctx.stageResults,
210
+ task
211
+ });
212
+ console.log(planSummary);
213
+ } catch (err) {
214
+ logger.warn(`Journal init failed (non-blocking): ${err.message}`);
215
+ ctx.journalDir = null;
216
+ ctx.journalFiles = [];
217
+ ctx.journalIterations = [];
218
+ ctx.journalDecisions = [];
219
+ }
220
+
221
+ ctx.gitCtx = await prepareGitAutomation({ config: ctx.config, task, logger, session: ctx.session });
222
+ const projectDir = ctx.config.projectDir || process.cwd();
223
+ ctx.reviewRules = (await resolveReviewProfile({ mode: ctx.config.review_mode, projectDir })).rules;
224
+ await ctx.coderRoleInstance.init();
225
+
226
+ return ctx;
227
+ }
@@ -0,0 +1,380 @@
1
+ /**
2
+ * Iteration-loop driver — extracted from src/orchestrator/flow-runner.js
3
+ * in TSK-0335 (Oleada 3 of the v2.7.4 audit refactor).
4
+ *
5
+ * Everything inside the coder→reviewer loop:
6
+ *
7
+ * - runCoderAndRefactorerStages: coder (+ refactorer if enabled), with
8
+ * standby handling per stage.
9
+ * - runGuardStages: deterministic output/perf guards on the diff.
10
+ * - runQualityGateStages: TDD check, Sonar (local + cloud), Impeccable.
11
+ * - runReviewerGateStage: reviewer role, with standby handling.
12
+ * - handleApprovedReview: wire post-loop stages + finalize session.
13
+ * - runSingleIteration: one coder→reviewer cycle (the iteration body).
14
+ * - runIterationLoop: the while loop, checkpoints, budget/time
15
+ * gates, error recovery via Solomon,
16
+ * max-iterations extension path.
17
+ *
18
+ * Extracted verbatim; no behavior change. flow-runner.js now imports these
19
+ * instead of defining them. Part of breaking up the 2254-LOC god-module —
20
+ * see docs/ARCHITECTURE.md and the TSK-0335 acceptance criteria.
21
+ */
22
+
23
+ import { emitProgress, makeEvent } from "../../utils/events.js";
24
+ import { msg, getLang } from "../../utils/messages.js";
25
+ import { saveSession, markSessionStatus } from "../../session/store.js";
26
+ import {
27
+ setReviewerFeedback, resetRetryCount,
28
+ } from "../../session/mutators.js";
29
+ import { invokeSolomon } from "../solomon-escalation.js";
30
+ import { buildIterationReport, handleIterationGate } from "../iteration-gate.js";
31
+ import {
32
+ handleCiEarlyPrOrPush, handleCiReviewDispatch,
33
+ } from "../ci-integration.js";
34
+ import {
35
+ handleCheckpoint, checkSessionTimeout, checkBudgetExceeded,
36
+ takeCheckpointSnapshot,
37
+ } from "../flow-control.js";
38
+ import {
39
+ handleSolomonCheck, handleReviewerRetryAndSolomon,
40
+ } from "./error-recovery.js";
41
+ import { handleMaxIterationsReached } from "./post-loop.js";
42
+ import { runCoderAndRefactorerStages } from "./iteration-phases/coder-and-refactorer.js";
43
+ import { runGuardStages } from "./iteration-phases/guards.js";
44
+ import { runQualityGateStages } from "./iteration-phases/quality-gates.js";
45
+ import { runReviewerGateStage } from "./iteration-phases/reviewer-gate.js";
46
+ import { handleApprovedReview } from "./iteration-phases/handle-approved.js";
47
+
48
+ // `runCoderAndRefactorerStages`, `runGuardStages`, `runQualityGateStages`,
49
+ // `runReviewerGateStage` and `handleApprovedReview` were extracted to
50
+ // ./iteration-phases/ in the v2.7.x audit follow-up (same pattern as
51
+ // pre-loop-phases/). The back-compat re-exports were removed in
52
+ // KJC-TSK-0354 PR-D — no caller imported them via this module.
53
+
54
+ async function runSingleIteration(ctx) {
55
+ // Use plannedTask (HU-scoped or planner-enriched) over the raw original task.
56
+ // When running per-HU sub-pipelines, plannedTask is the HU's text, not the full spec.
57
+ const { config, logger, emitter, eventBase, session, iteration: i } = ctx;
58
+ const task = ctx.plannedTask || ctx.task;
59
+
60
+ const iterStart = Date.now();
61
+ const ciEnabled = Boolean(config.ci?.enabled) && ctx.gitCtx?.enabled;
62
+ logger.setContext({ iteration: i, stage: "iteration" });
63
+
64
+ const reviewerRetryCount = session.reviewer_retry_count || 0;
65
+ const maxReviewerRetries = config.session.max_reviewer_retries ?? config.session.fail_fast_repeats;
66
+ const iterLang = getLang(config);
67
+ const iterMsg = msg("pipeline_iteration", iterLang, { current: i, max: config.max_iterations });
68
+ emitProgress(emitter, makeEvent("iteration:start", { ...eventBase, stage: "iteration" }, {
69
+ message: iterMsg,
70
+ detail: { iteration: i, maxIterations: config.max_iterations, reviewerRetryCount, maxReviewerRetries }
71
+ }));
72
+ logger.info(iterMsg);
73
+
74
+ const crResult = await runCoderAndRefactorerStages({
75
+ coderRoleInstance: ctx.coderRoleInstance, coderRole: ctx.coderRole, refactorerRole: ctx.refactorerRole,
76
+ pipelineFlags: ctx.pipelineFlags, config, logger, emitter, eventBase, session,
77
+ plannedTask: ctx.plannedTask, trackBudget: ctx.trackBudget, i, brainCtx: ctx.brainCtx
78
+ });
79
+ if (crResult.action === "return" || crResult.action === "retry") return crResult;
80
+
81
+ const guardResult = await runGuardStages({ config, logger, emitter, eventBase, session, iteration: i });
82
+ if (guardResult.action === "return") return guardResult;
83
+
84
+ const qgResult = await runQualityGateStages({
85
+ config, logger, emitter, eventBase, session, trackBudget: ctx.trackBudget, i,
86
+ askQuestion: ctx.askQuestion, repeatDetector: ctx.repeatDetector, budgetSummary: ctx.budgetSummary,
87
+ sonarState: ctx.sonarState, task, stageResults: ctx.stageResults, coderRole: ctx.coderRole,
88
+ pipelineFlags: ctx.pipelineFlags, brainCtx: ctx.brainCtx
89
+ });
90
+ if (qgResult.action === "return" || qgResult.action === "continue") return qgResult;
91
+
92
+ await handleCiEarlyPrOrPush({
93
+ ciEnabled, config, session, emitter, eventBase, gitCtx: ctx.gitCtx, task, logger,
94
+ stageResults: ctx.stageResults, i
95
+ });
96
+
97
+ const revResult = await runReviewerGateStage({
98
+ pipelineFlags: ctx.pipelineFlags, reviewerRole: ctx.reviewerRole, config, logger, emitter, eventBase,
99
+ session, trackBudget: ctx.trackBudget, i, reviewRules: ctx.reviewRules, task,
100
+ repeatDetector: ctx.repeatDetector, budgetSummary: ctx.budgetSummary, askQuestion: ctx.askQuestion,
101
+ brainCtx: ctx.brainCtx
102
+ });
103
+ if (revResult.action === "return" || revResult.action === "retry") return revResult;
104
+ const review = revResult.review;
105
+
106
+ const iterDuration = Date.now() - iterStart;
107
+ emitProgress(emitter, makeEvent("iteration:end", { ...eventBase, stage: "iteration" }, {
108
+ message: `Iteration ${i} completed`, detail: { duration: iterDuration }
109
+ }));
110
+ resetRetryCount(session, "standby");
111
+
112
+ // --- Journal: record iteration ---
113
+ // Uses the richer iteration-logger from TSK-0286: captures blocking-issue
114
+ // details, sonar counts and Solomon rulings in addition to summaries.
115
+ if (ctx.journalIterations) {
116
+ try {
117
+ const { recordIteration, extractIterationData } = await import("../../session/journal/iteration-logger.js");
118
+ const iterationData = extractIterationData({
119
+ iteration: i,
120
+ durationMs: iterDuration,
121
+ stageResults: ctx.stageResults,
122
+ session: ctx.session,
123
+ });
124
+ // Derive a richer reviewer summary if none was produced.
125
+ if (!iterationData.reviewerSummary && review) {
126
+ iterationData.reviewerSummary = review.approved
127
+ ? `Approved: ${review.raw_summary || ""}`
128
+ : `Rejected: ${(review?.blocking_issues || []).length} blocking issue(s)`;
129
+ }
130
+ if (!iterationData.blockingIssues || iterationData.blockingIssues.length === 0) {
131
+ iterationData.blockingIssues = review?.blocking_issues || [];
132
+ }
133
+ recordIteration(ctx.session, iterationData);
134
+ } catch (err) {
135
+ logger.warn(`Iteration journal record failed (non-blocking): ${err.message}`);
136
+ }
137
+ }
138
+
139
+ const solomonResult = await handleSolomonCheck({
140
+ config, session, emitter, eventBase, logger, task, i, askQuestion: ctx.askQuestion,
141
+ ciEnabled, blockingIssues: review?.blocking_issues, brainCtx: ctx.brainCtx
142
+ });
143
+ if (solomonResult.action === "pause") return { action: "return", result: solomonResult.result };
144
+
145
+ await handleCiReviewDispatch({ ciEnabled, config, session, review, i, logger });
146
+
147
+ if (review.approved) {
148
+ const approvedResult = await handleApprovedReview({
149
+ config, session, emitter, eventBase, coderRole: ctx.coderRole, trackBudget: ctx.trackBudget, i, task,
150
+ stageResults: ctx.stageResults, pipelineFlags: ctx.pipelineFlags, askQuestion: ctx.askQuestion, logger,
151
+ gitCtx: ctx.gitCtx, budgetSummary: ctx.budgetSummary, pgCard: ctx.pgCard, pgProject: ctx.pgProject, review,
152
+ rtkTracker: ctx.rtkTracker, brainCtx: ctx.brainCtx
153
+ });
154
+ if (approvedResult.action === "return" || approvedResult.action === "continue") return approvedResult;
155
+ }
156
+
157
+ // Solomon already evaluated the rejection in runReviewerStage -> handleReviewerRejection
158
+ // Only use retry counter as fallback if Solomon is disabled
159
+ if (!config.pipeline?.solomon?.enabled) {
160
+ const retryResult = await handleReviewerRetryAndSolomon({ config, session, emitter, eventBase, logger, review, task, i, askQuestion: ctx.askQuestion });
161
+ if (retryResult.action === "return") return retryResult;
162
+ } else {
163
+ // Solomon is enabled — feed back the blocking issues for the next coder iteration
164
+ setReviewerFeedback(session, review.blocking_issues
165
+ .map((x) => {
166
+ const parts = [`[${x.severity || "high"}] ${x.id || "ISSUE"}: ${x.description || "Missing description"}`];
167
+ if (x.file) parts.push(` File: ${x.file}${x.line ? `:${x.line}` : ""}`);
168
+ if (x.suggested_fix) parts.push(` Fix: ${x.suggested_fix}`);
169
+ return parts.join("\n");
170
+ })
171
+ .join("\n\n"));
172
+ await saveSession(session);
173
+ }
174
+
175
+ return { action: "next" };
176
+ }
177
+
178
+
179
+ /**
180
+ * Run the standard iteration loop for a given task using the pipeline context.
181
+ * Returns a result object with at least { approved: boolean }.
182
+ * Used both as the main loop and as the per-HU callback in sub-pipeline mode.
183
+ */
184
+ export async function runIterationLoop(ctx, { task: loopTask, askQuestion, emitter, logger }) {
185
+ ctx.plannedTask = loopTask;
186
+
187
+ const checkpointIntervalMs = (ctx.config.session.checkpoint_interval_minutes ?? 5) * 60 * 1000;
188
+ let lastCheckpointAt = Date.now();
189
+ let checkpointDisabled = false;
190
+ let lastCheckpointSnapshot = takeCheckpointSnapshot(ctx.session);
191
+
192
+ let i = 0;
193
+ while (i < ctx.config.max_iterations) {
194
+ i += 1;
195
+ const elapsedMinutes = (Date.now() - ctx.startedAt) / 60000;
196
+
197
+ const cpResult = await handleCheckpoint({
198
+ checkpointDisabled, askQuestion, lastCheckpointAt, checkpointIntervalMs, elapsedMinutes,
199
+ i, config: ctx.config, budgetTracker: ctx.budgetTracker, stageResults: ctx.stageResults, emitter, eventBase: ctx.eventBase, session: ctx.session, budgetSummary: ctx.budgetSummary, lastCheckpointSnapshot
200
+ });
201
+ if (cpResult.action === "stop") {
202
+ return cpResult.result;
203
+ }
204
+ checkpointDisabled = cpResult.checkpointDisabled;
205
+ lastCheckpointAt = cpResult.lastCheckpointAt;
206
+ if (cpResult.lastCheckpointSnapshot !== undefined) lastCheckpointSnapshot = cpResult.lastCheckpointSnapshot;
207
+
208
+ await checkSessionTimeout({ askQuestion, elapsedMinutes, config: ctx.config, session: ctx.session, emitter, eventBase: ctx.eventBase, i, budgetSummary: ctx.budgetSummary });
209
+ await checkBudgetExceeded({ budgetTracker: ctx.budgetTracker, config: ctx.config, session: ctx.session, emitter, eventBase: ctx.eventBase, i, budgetLimit: ctx.budgetLimit, budgetSummary: ctx.budgetSummary });
210
+
211
+ ctx.eventBase.iteration = i;
212
+ ctx.iteration = i;
213
+
214
+ let iterResult;
215
+ try {
216
+ iterResult = await runSingleIteration(ctx);
217
+ } catch (stageError) {
218
+ // ANY unhandled error in a stage = out of normal flow → Solomon decides
219
+ logger.warn(`Stage error caught — escalating to Solomon: ${stageError.message}`);
220
+ const solomonResult = await invokeSolomon({
221
+ config: ctx.config, logger, emitter, eventBase: ctx.eventBase,
222
+ stage: "stage_error", askQuestion, session: ctx.session, iteration: i,
223
+ conflict: {
224
+ stage: "stage_error",
225
+ task: loopTask,
226
+ iterationCount: i,
227
+ maxIterations: ctx.config.max_iterations,
228
+ budget_usd: ctx.budgetSummary()?.total_cost_usd || 0,
229
+ history: [{ agent: "pipeline", feedback: `Stage threw: ${stageError.message}` }]
230
+ }
231
+ });
232
+
233
+ if (solomonResult.action === "approve") {
234
+ logger.info("Solomon approved despite stage error");
235
+ return { approved: true, sessionId: ctx.session.id, reason: "solomon_approved_after_error" };
236
+ }
237
+ if (solomonResult.action === "continue") {
238
+ if (solomonResult.humanGuidance) {
239
+ setReviewerFeedback(ctx.session, `Solomon guidance: ${solomonResult.humanGuidance}`);
240
+ }
241
+ continue; // next iteration
242
+ }
243
+ if (solomonResult.action === "pause") {
244
+ return { paused: true, sessionId: ctx.session.id, question: solomonResult.question, context: "stage_error" };
245
+ }
246
+ // Solomon couldn't resolve — fail
247
+ await markSessionStatus(ctx.session, "failed");
248
+ return { approved: false, sessionId: ctx.session.id, reason: "stage_error", error: stageError.message };
249
+ }
250
+
251
+ if (iterResult.action === "return") {
252
+ return iterResult.result;
253
+ }
254
+ if (iterResult.action === "retry") { i -= 1; }
255
+ else {
256
+ await ensureIterationRecorded(ctx, i, logger);
257
+ // Iteration gate (KJC-TSK-0628): opt-in pause with a report before the
258
+ // next iteration; free-text answers become directives for the coder.
259
+ const gate = await handleIterationGate({
260
+ enabled: ctx.config.session?.iteration_gate === true,
261
+ askQuestion, session: ctx.session, logger,
262
+ report: buildIterationReport({
263
+ i, maxIterations: ctx.config.max_iterations, stageResults: ctx.stageResults,
264
+ budgetTracker: ctx.budgetTracker, maxBudgetUsd: ctx.config.max_budget_usd,
265
+ }),
266
+ });
267
+ if (gate.action === "stop") {
268
+ return { approved: false, sessionId: ctx.session.id, reason: "user_stopped_at_gate", iteration: i };
269
+ }
270
+ }
271
+ }
272
+
273
+ // Solomon decides whether to extend iterations or stop
274
+ const maxIterResult = await handleMaxIterationsReached({ session: ctx.session, budgetSummary: ctx.budgetSummary, emitter, eventBase: ctx.eventBase, config: ctx.config, stageResults: ctx.stageResults, logger, askQuestion, task: loopTask, rtkTracker: ctx.rtkTracker, brainCtx: ctx.brainCtx });
275
+
276
+ // Solomon said "continue" — extend iterations and keep going
277
+ if (maxIterResult.reason === "max_iterations_extended") {
278
+ const extra = maxIterResult.extraIterations || ctx.config.max_iterations;
279
+ ctx.config.max_iterations += extra;
280
+ logger.info(`Solomon extended pipeline by ${extra} iterations (new max: ${ctx.config.max_iterations})`);
281
+
282
+ if (maxIterResult.humanGuidance) {
283
+ setReviewerFeedback(ctx.session, `Solomon guidance: ${maxIterResult.humanGuidance}`);
284
+ }
285
+
286
+ // Continue the loop
287
+ while (i < ctx.config.max_iterations) {
288
+ i += 1;
289
+ const elapsedMinutes = (Date.now() - ctx.startedAt) / 60000;
290
+
291
+ const cpResult = await handleCheckpoint({
292
+ checkpointDisabled, askQuestion, lastCheckpointAt, checkpointIntervalMs, elapsedMinutes,
293
+ i, config: ctx.config, budgetTracker: ctx.budgetTracker, stageResults: ctx.stageResults, emitter, eventBase: ctx.eventBase, session: ctx.session, budgetSummary: ctx.budgetSummary, lastCheckpointSnapshot
294
+ });
295
+ if (cpResult.action === "stop") return cpResult.result;
296
+ checkpointDisabled = cpResult.checkpointDisabled;
297
+ lastCheckpointAt = cpResult.lastCheckpointAt;
298
+ if (cpResult.lastCheckpointSnapshot !== undefined) lastCheckpointSnapshot = cpResult.lastCheckpointSnapshot;
299
+
300
+ await checkSessionTimeout({ askQuestion, elapsedMinutes, config: ctx.config, session: ctx.session, emitter, eventBase: ctx.eventBase, i, budgetSummary: ctx.budgetSummary });
301
+ await checkBudgetExceeded({ budgetTracker: ctx.budgetTracker, config: ctx.config, session: ctx.session, emitter, eventBase: ctx.eventBase, i, budgetLimit: ctx.budgetLimit, budgetSummary: ctx.budgetSummary });
302
+
303
+ ctx.eventBase.iteration = i;
304
+ ctx.iteration = i;
305
+
306
+ const iterResult = await runSingleIteration(ctx);
307
+ if (iterResult.action === "return") return iterResult.result;
308
+ if (iterResult.action === "retry") { i -= 1; }
309
+ else {
310
+ await ensureIterationRecorded(ctx, i, logger);
311
+ // Same iteration gate on Solomon-extended iterations (KJC-TSK-0628).
312
+ const gate = await handleIterationGate({
313
+ enabled: ctx.config.session?.iteration_gate === true,
314
+ askQuestion, session: ctx.session, logger,
315
+ report: buildIterationReport({
316
+ i, maxIterations: ctx.config.max_iterations, stageResults: ctx.stageResults,
317
+ budgetTracker: ctx.budgetTracker, maxBudgetUsd: ctx.config.max_budget_usd,
318
+ }),
319
+ });
320
+ if (gate.action === "stop") {
321
+ return { approved: false, sessionId: ctx.session.id, reason: "user_stopped_at_gate", iteration: i };
322
+ }
323
+ }
324
+ }
325
+
326
+ // Extended iterations also exhausted — final Solomon call
327
+ const finalResult = await handleMaxIterationsReached({ session: ctx.session, budgetSummary: ctx.budgetSummary, emitter, eventBase: ctx.eventBase, config: ctx.config, stageResults: ctx.stageResults, logger, askQuestion, task: loopTask, rtkTracker: ctx.rtkTracker, brainCtx: ctx.brainCtx });
328
+ return finalizeMaxIterationsApproval(ctx, finalResult, { task: loopTask, askQuestion, emitter, logger, i });
329
+ }
330
+
331
+ return finalizeMaxIterationsApproval(ctx, maxIterResult, { task: loopTask, askQuestion, emitter, logger, i });
332
+ }
333
+
334
+ // KJC-BUG-0117: iterations that end before the reviewer (TDD/sonar
335
+ // "continue", guard retries) never reached the recordIteration call at
336
+ // the end of runSingleIteration, so session._journalIterations stayed
337
+ // empty and the journal read "Iterations: 0" after a 5-iteration run.
338
+ export async function ensureIterationRecorded(ctx, i, logger) {
339
+ if (!ctx.journalIterations) return;
340
+ if ((ctx.session._journalIterations?.length || 0) >= i) return;
341
+ try {
342
+ const { recordIteration, extractIterationData } = await import("../../session/journal/iteration-logger.js");
343
+ recordIteration(ctx.session, extractIterationData({
344
+ iteration: i, durationMs: 0, stageResults: ctx.stageResults, session: ctx.session,
345
+ }));
346
+ } catch (err) {
347
+ logger.warn(`Iteration journal record failed (non-blocking): ${err.message}`);
348
+ }
349
+ }
350
+
351
+ // KJC-BUG-0116: an "approved" verdict at max_iterations (brain_approved,
352
+ // brain_solomon_approved, solomon_approved) used to be returned as-is,
353
+ // skipping the entire post-loop (tester/security/audit) AND git
354
+ // automation (push/PR) that every reviewer-approved session gets — the
355
+ // session read "approved" with zero verification and zero push. Route it
356
+ // through the same handleApprovedReview path instead.
357
+ export async function finalizeMaxIterationsApproval(ctx, maxIterResult, { task, askQuestion, emitter, logger, i }) {
358
+ if (maxIterResult?.approved !== true) return maxIterResult;
359
+
360
+ const review = {
361
+ approved: true,
362
+ raw_summary: `Finalized at max_iterations (${maxIterResult.reason || "approved"})`,
363
+ blocking_issues: []
364
+ };
365
+ const fin = await handleApprovedReview({
366
+ config: ctx.config, session: ctx.session, emitter, eventBase: ctx.eventBase,
367
+ coderRole: ctx.coderRole, trackBudget: ctx.trackBudget, i, task,
368
+ stageResults: ctx.stageResults, pipelineFlags: ctx.pipelineFlags, askQuestion, logger,
369
+ gitCtx: ctx.gitCtx, budgetSummary: ctx.budgetSummary, pgCard: ctx.pgCard, pgProject: ctx.pgProject,
370
+ review, rtkTracker: ctx.rtkTracker, brainCtx: ctx.brainCtx
371
+ });
372
+ if (fin.action === "return") return fin.result;
373
+
374
+ // Post-loop demanded another coder pass but iterations are exhausted —
375
+ // report honestly instead of a false green.
376
+ logger.warn("Post-loop stages rejected the work at max_iterations — session NOT approved");
377
+ await markSessionStatus(ctx.session, "failed");
378
+ return { approved: false, sessionId: ctx.session.id, reason: "post_loop_rejected_at_max_iterations" };
379
+ }
380
+
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Iteration phase: coder (+ refactorer if enabled) 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. The extraction follows the same pattern as
8
+ * `pre-loop-phases/` (see TSK-0337).
9
+ *
10
+ * Returns { action: "ok" | "return" | "retry", result? }.
11
+ * - "ok" → caller continues to the next phase.
12
+ * - "return" → caller returns `result` to its own caller (pause/abort).
13
+ * - "retry" → caller decrements its iteration counter and retries.
14
+ */
15
+
16
+ import { runRefactorerStage } from "../../iteration-stages.js";
17
+ import { stageRegistry } from "../../stages/stage-classes.js";
18
+ import { runStage } from "../../stages/stage-executor.js";
19
+ import { handleStandbyResult } from "../error-recovery.js";
20
+
21
+ /**
22
+ * A coder/refactorer stage hit a provider quota cap and Brain Recovery
23
+ * hibernated the run. Turn it into a clean loop return carrying
24
+ * `hibernated:true` — the iteration loop and flow-runner read that to
25
+ * seal the session as `hibernated` (NOT `failed`) so it stays resumable.
26
+ */
27
+ function hibernateReturn(stageResult, session) {
28
+ return {
29
+ action: "return",
30
+ result: {
31
+ hibernated: true,
32
+ sessionId: session?.id || null,
33
+ reason: "quota_exhausted",
34
+ standbyFile: stageResult.standbyFile || null,
35
+ recovery: stageResult.recovery || null,
36
+ },
37
+ };
38
+ }
39
+
40
+ export async function runCoderAndRefactorerStages({ coderRoleInstance, coderRole, refactorerRole, pipelineFlags, config, logger, emitter, eventBase, session, plannedTask, trackBudget, i, brainCtx }) {
41
+ // Coder via StageRegistry (TSK-0336). canRun = coderRequired !== false; in
42
+ // analysis-only task types coderRequired is set to false by policy, so the
43
+ // stage is never even entered — matches the previous guard at the top of
44
+ // runFlow.
45
+ const coderCtx = { coderRoleInstance, coderRole, config, logger, emitter, eventBase, session, plannedTask, trackBudget, iteration: i, brainCtx, pipelineFlags };
46
+ const coderResult = await runStage(stageRegistry.get("coder"), coderCtx);
47
+ if (coderResult?.action === "hibernate") return hibernateReturn(coderResult, session);
48
+ if (coderResult?.action === "pause") return { action: "return", result: coderResult.result };
49
+ const coderStandby = await handleStandbyResult({ stageResult: coderResult, session, emitter, eventBase, i, stage: "coder", logger, config });
50
+ if (coderStandby.handled) {
51
+ return coderStandby.action === "return"
52
+ ? { action: "return", result: coderStandby.result }
53
+ : { action: "retry" };
54
+ }
55
+
56
+ if (pipelineFlags.refactorerEnabled) {
57
+ const refResult = await runRefactorerStage({ refactorerRole, config, logger, emitter, eventBase, session, plannedTask, trackBudget, iteration: i });
58
+ if (refResult?.action === "hibernate") return hibernateReturn(refResult, session);
59
+ if (refResult?.action === "pause") return { action: "return", result: refResult.result };
60
+ const refStandby = await handleStandbyResult({ stageResult: refResult, session, emitter, eventBase, i, stage: "refactorer", logger, config });
61
+ if (refStandby.handled) {
62
+ return refStandby.action === "return"
63
+ ? { action: "return", result: refStandby.result }
64
+ : { action: "retry" };
65
+ }
66
+ }
67
+
68
+ return { action: "ok" };
69
+ }