karajan-code 4.70.4 → 5.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (390) hide show
  1. package/README.md +2 -2
  2. package/package.json +6 -14
  3. package/packages/hu-board/package.json +1 -1
  4. package/packages/hu-board/public/app.js +4 -18
  5. package/packages/hu-board/public/index.html +5 -2
  6. package/packages/hu-board/public/styles.css +26 -0
  7. package/packages/hu-board/public/utils/api.js +0 -74
  8. package/packages/hu-board/public/utils/board-tour.js +62 -0
  9. package/packages/hu-board/public/utils/board-view.js +49 -144
  10. package/packages/hu-board/public/utils/command-launcher.js +8 -70
  11. package/packages/hu-board/public/utils/formatters.js +10 -0
  12. package/packages/hu-board/public/utils/governance-view.js +13 -1
  13. package/packages/hu-board/public/utils/hu-actions.js +17 -68
  14. package/packages/hu-board/public/utils/init-listeners.js +7 -8
  15. package/packages/hu-board/public/utils/log-panel.js +3 -16
  16. package/packages/hu-board/public/utils/maggle-mode.js +2 -12
  17. package/packages/hu-board/public/utils/modals.js +7 -0
  18. package/packages/hu-board/public/utils/project-picker-view.js +1 -1
  19. package/packages/hu-board/public/utils/server-push.js +3 -22
  20. package/packages/hu-board/public/utils/shared-board-notice.js +33 -0
  21. package/packages/hu-board/public/utils/story-detail-view.js +5 -19
  22. package/packages/hu-board/src/cleanup-zombies.js +0 -1
  23. package/packages/hu-board/src/command-runner.js +36 -25
  24. package/packages/hu-board/src/db-connection.js +282 -0
  25. package/packages/hu-board/src/db-paths.js +113 -0
  26. package/packages/hu-board/src/db-queries.js +188 -0
  27. package/packages/hu-board/src/db-tombstones.js +51 -0
  28. package/packages/hu-board/src/db.js +28 -619
  29. package/packages/hu-board/src/ephemeral-cleaner.js +2 -3
  30. package/packages/hu-board/src/hu-zombie-reaper.js +5 -1
  31. package/packages/hu-board/src/plan-mutations.js +3 -153
  32. package/packages/hu-board/src/plans-service.js +55 -0
  33. package/packages/hu-board/src/routes/api/commands.js +122 -0
  34. package/packages/hu-board/src/routes/api/plans.js +55 -0
  35. package/packages/hu-board/src/routes/api/projects.js +267 -0
  36. package/packages/hu-board/src/routes/api/prompts.js +135 -0
  37. package/packages/hu-board/src/routes/api/sessions.js +95 -0
  38. package/packages/hu-board/src/routes/api/stories.js +183 -0
  39. package/packages/hu-board/src/routes/api/system.js +241 -0
  40. package/packages/hu-board/src/routes/api/tombstones.js +38 -0
  41. package/packages/hu-board/src/routes/api.js +24 -1371
  42. package/packages/hu-board/src/routes/governance.js +23 -1
  43. package/packages/hu-board/src/routes/lanes.js +40 -0
  44. package/packages/hu-board/src/routes/rag.js +4 -3
  45. package/packages/hu-board/src/server.js +20 -34
  46. package/packages/hu-board/src/sync-files.js +318 -0
  47. package/packages/hu-board/src/sync-project.js +99 -0
  48. package/packages/hu-board/src/sync.js +22 -566
  49. package/packages/hu-board/src/zombie-reaper.js +1 -1
  50. package/scripts/dual-publish.mjs +19 -3
  51. package/scripts/postinstall.js +15 -2
  52. package/scripts/verify-pack-mcp.mjs +11 -7
  53. package/scripts/verify-pack.mjs +4 -4
  54. package/src/audit/audit-history.js +3 -2
  55. package/src/audit/dead-exports.js +68 -59
  56. package/src/audit/deterministic-summary.js +33 -13
  57. package/src/audit/npm-signatures.js +41 -0
  58. package/src/audit/sbom.js +35 -0
  59. package/src/checks/agent-token.js +112 -0
  60. package/src/checks/dir-setup.js +34 -1
  61. package/src/checks/native-build.js +21 -39
  62. package/src/checks/runner.js +128 -142
  63. package/src/cli/advanced-commands.js +6 -6
  64. package/src/cli/register-meta.js +42 -82
  65. package/src/cli/register-pipeline.js +8 -143
  66. package/src/cli/register-plan.js +9 -100
  67. package/src/cli/register-roles-skills.js +1 -1
  68. package/src/cli/retired-commands.js +49 -0
  69. package/src/cli.js +18 -5
  70. package/src/commands/agent-run.js +40 -26
  71. package/src/commands/audit.js +127 -124
  72. package/src/commands/board.js +5 -9
  73. package/src/commands/check.js +29 -16
  74. package/src/commands/doctor.js +2 -0
  75. package/src/commands/env.js +176 -150
  76. package/src/commands/go.js +71 -53
  77. package/src/commands/harden.js +90 -81
  78. package/src/commands/hu-start.js +52 -0
  79. package/src/commands/hu.js +288 -221
  80. package/src/commands/identity.js +111 -78
  81. package/src/commands/init-atril.js +47 -0
  82. package/src/commands/init.js +11 -40
  83. package/src/commands/install-tools.js +70 -85
  84. package/src/commands/main-guard.js +78 -0
  85. package/src/commands/policy.js +226 -184
  86. package/src/commands/qmd.js +27 -21
  87. package/src/commands/rag.js +121 -55
  88. package/src/commands/review-gate.js +421 -341
  89. package/src/commands/skills.js +4 -1
  90. package/src/commands/start.js +4 -5
  91. package/src/commands/steward.js +96 -47
  92. package/src/commands/tournament.js +46 -37
  93. package/src/commands/worktree.js +107 -26
  94. package/src/config/defaults.js +1 -0
  95. package/src/config/loader.js +34 -17
  96. package/src/config/role-resolver.js +1 -0
  97. package/src/config/schema.js +1 -0
  98. package/src/config/secrets.js +36 -0
  99. package/src/config.js +1 -0
  100. package/src/environment/adr.js +16 -2
  101. package/src/git/karajan-label.js +20 -8
  102. package/src/guards/main-guard.js +54 -0
  103. package/src/harden/hook-templates.js +16 -1
  104. package/src/harden/sentinel/posttooluse.mjs +18 -6
  105. package/src/harden/sentinel/pretooluse-sentinel.mjs +64 -36
  106. package/src/harden/sentinel/sentinel-lib.mjs +129 -26
  107. package/src/harden/sentinel/sentinel-shell.mjs +5 -16
  108. package/src/harden/sentinel/sessionstart.mjs +3 -2
  109. package/src/harden/sentinel/stop.mjs +5 -4
  110. package/src/harden/workflow-templates.js +1 -1
  111. package/src/hu/board-lookup.js +29 -0
  112. package/src/hu/gh-identity.js +23 -0
  113. package/src/hu/github-board.js +4 -2
  114. package/src/hu/lane-prune.js +83 -13
  115. package/src/hu/lane-setup.js +65 -0
  116. package/src/hu/lanes.js +66 -0
  117. package/src/hu/team-board-mirror.js +3 -2
  118. package/src/infrastructure/command-runner.js +1 -1
  119. package/src/infrastructure/file-system-service.js +1 -1
  120. package/src/mcp/handlers/direct-handlers.js +2 -292
  121. package/src/mcp/handlers/hu-handlers.js +1 -35
  122. package/src/mcp/handlers/management-handlers.js +2 -42
  123. package/src/mcp/handlers/rag-handler.js +9 -1
  124. package/src/mcp/server-handlers.js +16 -22
  125. package/src/mcp/tools.js +1 -196
  126. package/src/plan/lane-plans.js +54 -0
  127. package/src/plan/plan-store.js +7 -4
  128. package/src/policy/add.js +26 -12
  129. package/src/policy/adr-number-check.js +31 -0
  130. package/src/prompts/audit.js +299 -339
  131. package/src/prompts/card-context.js +10 -5
  132. package/src/prompts/reviewer.js +5 -2
  133. package/src/rag/auto-update.js +71 -44
  134. package/src/rag/bootstrap-index.js +46 -54
  135. package/src/rag/indexer.js +9 -4
  136. package/src/rag/migrate.js +1 -1
  137. package/src/rag/onnx-fallback.js +2 -2
  138. package/src/rag/pid-lease.js +181 -0
  139. package/src/rag/project-store.js +2 -12
  140. package/src/review/card-first.js +57 -46
  141. package/src/review/gate-gitignore.js +23 -4
  142. package/src/review/gate-hook.js +12 -4
  143. package/src/review/one-shot-review.js +45 -35
  144. package/src/review/publish-pr.js +14 -2
  145. package/src/review/repo-docs.js +73 -0
  146. package/src/review/repo-stack.js +59 -0
  147. package/src/review/reviewer-fallback.js +19 -4
  148. package/src/review/seal-commit.js +29 -0
  149. package/src/review/sonar-pregate.js +59 -44
  150. package/src/review/third-party-review.js +90 -16
  151. package/src/review/third-party-size.js +43 -0
  152. package/src/review/third-party-skills.js +54 -0
  153. package/src/review/verify-pr.js +1 -24
  154. package/src/roles/audit-role.js +106 -125
  155. package/src/skills/atril-cli.js +19 -1
  156. package/src/skills/atril-skills.js +5 -4
  157. package/src/skills/skills-search.js +72 -0
  158. package/src/skills/translate.js +62 -0
  159. package/src/sonar/scanner.js +116 -101
  160. package/src/steward/invariants.js +5 -4
  161. package/src/steward/phantom-sweep.js +66 -0
  162. package/src/tournament/judge.js +60 -53
  163. package/src/utils/gh-account.js +37 -0
  164. package/src/utils/git.js +0 -13
  165. package/src/utils/home-migration.js +7 -1
  166. package/src/utils/main-checkout.js +53 -0
  167. package/src/utils/qmd-collection.js +3 -1
  168. package/src/utils/welcome.js +3 -3
  169. package/templates/{skills → atril/commands}/kj-architect.md +5 -0
  170. package/templates/{skills → atril/commands}/kj-audit.md +5 -0
  171. package/templates/{skills → atril/commands}/kj-board.md +5 -0
  172. package/templates/{skills → atril/commands}/kj-code.md +5 -0
  173. package/templates/{skills → atril/commands}/kj-csv-transform.md +5 -0
  174. package/templates/{skills → atril/commands}/kj-data-report.md +5 -0
  175. package/templates/{skills → atril/commands}/kj-discover.md +5 -0
  176. package/templates/{skills → atril/commands}/kj-rag-query.md +5 -0
  177. package/templates/{skills → atril/commands}/kj-review.md +5 -0
  178. package/templates/{skills → atril/commands}/kj-security.md +5 -0
  179. package/templates/{skills → atril/commands}/kj-sonar.md +5 -0
  180. package/templates/{skills → atril/commands}/kj-sql-analysis.md +5 -0
  181. package/templates/{skills → atril/commands}/kj-test.md +5 -0
  182. package/packages/hu-board/public/utils/run-launcher.js +0 -169
  183. package/packages/hu-board/src/run-tracker.js +0 -121
  184. package/src/activity-log.js +0 -59
  185. package/src/agents/host-agent.js +0 -38
  186. package/src/agents/model-registry.js +0 -142
  187. package/src/audit/plan-adherence.js +0 -224
  188. package/src/autonomy/arbiter-role.js +0 -71
  189. package/src/autonomy/arbiter.js +0 -22
  190. package/src/autonomy/decider.js +0 -18
  191. package/src/autonomy/decision-resolver.js +0 -58
  192. package/src/autonomy/outcome-report.js +0 -55
  193. package/src/autonomy/stage-ask.js +0 -30
  194. package/src/brain/decision-tracker.js +0 -125
  195. package/src/brain/decisor.js +0 -243
  196. package/src/brain/solomon-consult.js +0 -171
  197. package/src/brain/standby-scheduler.js +0 -8
  198. package/src/budget/comparison.js +0 -96
  199. package/src/canvas/parse-md.js +0 -238
  200. package/src/canvas/schema.js +0 -101
  201. package/src/canvas/to-flat.js +0 -85
  202. package/src/canvas/validate.js +0 -163
  203. package/src/ci/dispatch.js +0 -99
  204. package/src/ci/index.js +0 -3
  205. package/src/ci/pr-diff.js +0 -26
  206. package/src/cli/register-standby.js +0 -26
  207. package/src/commands/architect.js +0 -111
  208. package/src/commands/autorun.js +0 -49
  209. package/src/commands/researcher.js +0 -54
  210. package/src/commands/resume.js +0 -72
  211. package/src/commands/review.js +0 -89
  212. package/src/commands/run.js +0 -185
  213. package/src/commands/standby.js +0 -117
  214. package/src/commands/status.js +0 -36
  215. package/src/commands/triage.js +0 -78
  216. package/src/commands/undo.js +0 -62
  217. package/src/domains/domain-loader.js +0 -245
  218. package/src/domains/domain-registry.js +0 -140
  219. package/src/domains/domain-synthesizer.js +0 -129
  220. package/src/git/automation.js +0 -433
  221. package/src/git/coder-commit-guard.js +0 -40
  222. package/src/git/hu-automation.js +0 -243
  223. package/src/git/hu-snapshot.js +0 -10
  224. package/src/git/symlink-targets.js +0 -57
  225. package/src/golden/asserter.js +0 -92
  226. package/src/golden/loader.js +0 -52
  227. package/src/golden/runner.js +0 -92
  228. package/src/golden/schema.js +0 -41
  229. package/src/guards/duplicate-members.js +0 -86
  230. package/src/guards/intent-guard.js +0 -161
  231. package/src/guards/perf-guard.js +0 -126
  232. package/src/guards/policy-guard.js +0 -90
  233. package/src/guards/policy-resolver.js +0 -85
  234. package/src/guards/secret-redactor.js +0 -71
  235. package/src/hu/acceptance-runner.js +0 -138
  236. package/src/hu/lazy-planner.js +0 -109
  237. package/src/hu/parallel-executor.js +0 -94
  238. package/src/hu/routing-metrics.js +0 -17
  239. package/src/hu/split-validator.js +0 -143
  240. package/src/hu/splitting-detector.js +0 -158
  241. package/src/hu/splitting-generator.js +0 -175
  242. package/src/hu/store.js +0 -394
  243. package/src/infrastructure/mocks.js +0 -182
  244. package/src/mcp/handlers/run-handler.js +0 -318
  245. package/src/mcp/sovereignty-guard.js +0 -113
  246. package/src/mcp/tool-arg-normalizers.js +0 -16
  247. package/src/mutate/reviewer-signal.js +0 -76
  248. package/src/orchestrator/agent-fallback.js +0 -81
  249. package/src/orchestrator/brain-coordinator.js +0 -186
  250. package/src/orchestrator/ci-integration.js +0 -139
  251. package/src/orchestrator/config-init.js +0 -426
  252. package/src/orchestrator/direct-actions.js +0 -217
  253. package/src/orchestrator/drivers/error-recovery.js +0 -287
  254. package/src/orchestrator/drivers/init-context.js +0 -238
  255. package/src/orchestrator/drivers/iteration-loop.js +0 -382
  256. package/src/orchestrator/drivers/iteration-phases/coder-and-refactorer.js +0 -69
  257. package/src/orchestrator/drivers/iteration-phases/guards.js +0 -91
  258. package/src/orchestrator/drivers/iteration-phases/handle-approved.js +0 -29
  259. package/src/orchestrator/drivers/iteration-phases/quality-gates.js +0 -125
  260. package/src/orchestrator/drivers/iteration-phases/reviewer-gate.js +0 -62
  261. package/src/orchestrator/drivers/post-loop.js +0 -404
  262. package/src/orchestrator/drivers/pre-loop-phases/auto-hu-batch.js +0 -137
  263. package/src/orchestrator/drivers/pre-loop-phases/config-deprecations.js +0 -47
  264. package/src/orchestrator/drivers/pre-loop-phases/ensure-addyosmani-skills.js +0 -84
  265. package/src/orchestrator/drivers/pre-loop-phases/inject-loaded-plan.js +0 -393
  266. package/src/orchestrator/drivers/pre-loop.js +0 -524
  267. package/src/orchestrator/drivers/run-hu-batch.js +0 -468
  268. package/src/orchestrator/feedback-enrichment.js +0 -140
  269. package/src/orchestrator/feedback-queue.js +0 -151
  270. package/src/orchestrator/flow-control.js +0 -170
  271. package/src/orchestrator/flow-runner.js +0 -365
  272. package/src/orchestrator/fs-leak-detector.js +0 -228
  273. package/src/orchestrator/hu-scheduler.js +0 -114
  274. package/src/orchestrator/hu-sub-pipeline.js +0 -642
  275. package/src/orchestrator/iteration-gate.js +0 -73
  276. package/src/orchestrator/iteration-stages.js +0 -9
  277. package/src/orchestrator/parallel-limiter.js +0 -74
  278. package/src/orchestrator/pipeline-context.js +0 -72
  279. package/src/orchestrator/post-loop-stages.js +0 -468
  280. package/src/orchestrator/pre-loop-stages.js +0 -11
  281. package/src/orchestrator/preflight-checks.js +0 -487
  282. package/src/orchestrator/repair/repair-detector.js +0 -117
  283. package/src/orchestrator/repair/repair-runner.js +0 -142
  284. package/src/orchestrator/reviewer-fallback.js +0 -45
  285. package/src/orchestrator/role-output-compressor.js +0 -189
  286. package/src/orchestrator/session-journal.js +0 -308
  287. package/src/orchestrator/solomon-escalation.js +0 -331
  288. package/src/orchestrator/solomon-rules.js +0 -212
  289. package/src/orchestrator/stages/acceptance-coverage-stage.js +0 -47
  290. package/src/orchestrator/stages/architect-stage.js +0 -172
  291. package/src/orchestrator/stages/coder-stage.js +0 -506
  292. package/src/orchestrator/stages/domain-curator-stage.js +0 -82
  293. package/src/orchestrator/stages/format-stage.js +0 -61
  294. package/src/orchestrator/stages/hu-reviewer-phases/detect-and-apply-splits.js +0 -127
  295. package/src/orchestrator/stages/hu-reviewer-stage.js +0 -419
  296. package/src/orchestrator/stages/perf-stage.js +0 -140
  297. package/src/orchestrator/stages/planner-stage.js +0 -85
  298. package/src/orchestrator/stages/rag-context-stage.js +0 -80
  299. package/src/orchestrator/stages/rag-preload-decisor.js +0 -58
  300. package/src/orchestrator/stages/research-stage.js +0 -69
  301. package/src/orchestrator/stages/reviewer-stage.js +0 -431
  302. package/src/orchestrator/stages/sonar-stage.js +0 -439
  303. package/src/orchestrator/stages/stage-classes.js +0 -84
  304. package/src/orchestrator/stages/stage-executor.js +0 -155
  305. package/src/orchestrator/stages/suite-green-stage.js +0 -62
  306. package/src/orchestrator/stages/tdd-discipline-stage.js +0 -56
  307. package/src/orchestrator/stages/tool-judge-stage.js +0 -53
  308. package/src/orchestrator/stages/triage-stage.js +0 -172
  309. package/src/orchestrator/standby.js +0 -71
  310. package/src/orchestrator/verification-gate.js +0 -183
  311. package/src/orchestrator.js +0 -22
  312. package/src/plan/adr-generator.js +0 -170
  313. package/src/plan/adr-loader.js +0 -60
  314. package/src/plan/plan-executor.js +0 -100
  315. package/src/plan/plan-validation.js +0 -4
  316. package/src/prompts/acceptance-coverage.js +0 -32
  317. package/src/prompts/arbiter.js +0 -38
  318. package/src/prompts/architect.js +0 -103
  319. package/src/prompts/hu-reviewer.js +0 -244
  320. package/src/prompts/tool-correctness-judge.js +0 -31
  321. package/src/prompts/triage.js +0 -57
  322. package/src/rag/embedder.js +0 -2
  323. package/src/rag/embedders/_cloud-base.js +0 -2
  324. package/src/rag/embedders/cohere.js +0 -2
  325. package/src/rag/embedders/mistral.js +0 -2
  326. package/src/rag/embedders/onnx.js +0 -2
  327. package/src/rag/embedders/openai.js +0 -2
  328. package/src/rag/embedders/voyage.js +0 -2
  329. package/src/rag/rerank.js +0 -4
  330. package/src/rag/where-parser.js +0 -4
  331. package/src/repeat-detector.js +0 -88
  332. package/src/review/diff-generator.js +0 -112
  333. package/src/review/git-stash-helper.js +0 -104
  334. package/src/review/schema.js +0 -31
  335. package/src/review/scope-filter.js +0 -152
  336. package/src/review/snapshot-diff.js +0 -122
  337. package/src/review/tdd-discipline.js +0 -90
  338. package/src/review/tdd-policy.js +0 -69
  339. package/src/roles/acceptance-coverage-role.js +0 -78
  340. package/src/roles/architect-role.js +0 -77
  341. package/src/roles/coder-role.js +0 -113
  342. package/src/roles/commiter-role.js +0 -113
  343. package/src/roles/domain-curator-role.js +0 -134
  344. package/src/roles/hu-reviewer-role.js +0 -64
  345. package/src/roles/impeccable-role.js +0 -85
  346. package/src/roles/index.js +0 -18
  347. package/src/roles/karajan-brain-role.js +0 -134
  348. package/src/roles/perf-role.js +0 -122
  349. package/src/roles/planner-role.js +0 -151
  350. package/src/roles/refactorer-role.js +0 -30
  351. package/src/roles/repairer-role.js +0 -181
  352. package/src/roles/researcher-role.js +0 -70
  353. package/src/roles/reviewer-role.js +0 -115
  354. package/src/roles/security-role.js +0 -73
  355. package/src/roles/solomon-role.js +0 -271
  356. package/src/roles/sonar-role.js +0 -72
  357. package/src/roles/tester-role.js +0 -235
  358. package/src/roles/tool-correctness-judge-role.js +0 -78
  359. package/src/roles/triage-role.js +0 -99
  360. package/src/session/journal/decisions-writer.js +0 -200
  361. package/src/session/journal/iteration-logger.js +0 -194
  362. package/src/session/journal/summary-writer.js +0 -320
  363. package/src/session/journal/tree-writer.js +0 -164
  364. package/src/session/journal/write-all.js +0 -89
  365. package/src/session-cleanup.js +0 -116
  366. package/src/skills/semantic-detector.js +0 -167
  367. package/src/skills/skill-detector.js +0 -385
  368. package/src/sonar/cloud-scanner.js +0 -78
  369. package/src/tracker-bootstrap.js +0 -44
  370. package/src/types/index.js +0 -38
  371. package/src/types/policy.js +0 -43
  372. package/src/types/solomon.js +0 -87
  373. package/src/utils/async-lock.js +0 -31
  374. package/src/utils/budget.js +0 -229
  375. package/src/utils/cwd-confirm.js +0 -39
  376. package/src/utils/display/event-handlers.js +0 -403
  377. package/src/utils/display/formatters.js +0 -132
  378. package/src/utils/display/header.js +0 -47
  379. package/src/utils/display/session-summary.js +0 -118
  380. package/src/utils/display/solomon.js +0 -42
  381. package/src/utils/pricing.js +0 -29
  382. package/src/utils/quota-simulator.js +0 -56
  383. package/src/utils/role-assigner.js +0 -137
  384. package/src/utils/rtk-wrapper.js +0 -87
  385. package/src/utils/run-registry.js +0 -9
  386. package/src/utils/status-dashboard.js +0 -254
  387. package/src/utils/tool-call-extractor.js +0 -56
  388. package/src/webperf/devtools-detect.js +0 -112
  389. package/src/webperf/webperf-role-integration.js +0 -66
  390. package/templates/skills/kj-run.md +0 -73
@@ -1,142 +0,0 @@
1
- /**
2
- * Repair runner — orchestrates the Repairer role end-to-end.
3
- *
4
- * Called from run-hu-batch when an acceptance test failure has been
5
- * classified as `infeasible` by repair-detector. The runner:
6
- * 1. Builds the prompt context (failing test, error output, HU
7
- * intent, sibling tests).
8
- * 2. Invokes RepairerRole.
9
- * 3. If verdict=fixable: patches the plan JSON's acceptance_tests
10
- * AND the in-memory batch story so the next coder iteration sees
11
- * the corrected test. Saves both. Returns { repaired: true }.
12
- * 4. If verdict=unfixable: returns { repaired: false, escalate: true,
13
- * reason } so the caller can hand off to Solomon / FDE.
14
- * 5. If RepairerRole itself fails (agent error): returns
15
- * { repaired: false, escalate: false, error } so the caller
16
- * decides whether to retry coder or escalate.
17
- */
18
-
19
- import { RepairerRole } from "../../roles/repairer-role.js";
20
- import { saveHuBatch } from "../../hu/store.js";
21
- import { emitProgress, makeEvent } from "../../utils/events.js";
22
-
23
- /**
24
- * @param {object} args
25
- * @param {object} args.story — the HU story object (in-memory batch slice). MUTATED.
26
- * @param {number} args.testIndex — index in story.acceptance_tests of the failing test.
27
- * @param {string} args.errorOutput — last failing run's stderr+stdout.
28
- * @param {string} args.batchSessionId
29
- * @param {object} args.batch — full batch object. MUTATED (story is a slice).
30
- * @param {object} args.config
31
- * @param {object} args.logger
32
- * @param {object} args.emitter
33
- * @param {object} args.eventBase
34
- * @param {string} args.failureKind — repair-detector's `kind` (e.g. "jq-as-binding-misuse").
35
- * @param {Function} [args.savePlanPatch] — async (huId, fieldPatch) => void; if provided,
36
- * patches the plan JSON on disk too.
37
- * @returns {Promise<{repaired: boolean, escalate?: boolean, reason?: string, error?: string}>}
38
- */
39
- export async function runRepair({
40
- story, testIndex, errorOutput, batchSessionId, batch,
41
- config, logger, emitter, eventBase, failureKind, savePlanPatch,
42
- }) {
43
- if (!story || !Array.isArray(story.acceptance_tests) || !story.acceptance_tests[testIndex]) {
44
- return { repaired: false, escalate: false, error: "repair-runner: invalid story or testIndex" };
45
- }
46
-
47
- const failingTest = story.acceptance_tests[testIndex];
48
- const siblingTests = story.acceptance_tests.filter((_, i) => i !== testIndex);
49
-
50
- emitProgress(emitter, makeEvent("repair:start", { ...eventBase, stage: "repair" }, {
51
- message: `Repairer invoked for HU ${story.id} test #${testIndex} (kind=${failureKind})`,
52
- detail: {
53
- huId: story.id,
54
- testIndex,
55
- testContent: typeof failingTest === "object" ? failingTest.content : failingTest,
56
- kind: failureKind,
57
- },
58
- }));
59
-
60
- const repairer = new RepairerRole({ config, logger, emitter });
61
- await repairer.init({ task: story.scope || story.title || story.id, sessionId: batchSessionId, iteration: 0 });
62
-
63
- let result;
64
- try {
65
- result = await repairer.run({
66
- failingTest,
67
- errorOutput,
68
- huTitle: story.title || story.id,
69
- huScope: story.scope || "",
70
- siblingTests,
71
- iteration: 0,
72
- });
73
- } catch (err) {
74
- logger.warn(`Repairer threw: ${err.message}`);
75
- emitProgress(emitter, makeEvent("repair:end", { ...eventBase, stage: "repair" }, {
76
- status: "fail",
77
- message: `Repairer error: ${err.message}`,
78
- detail: { huId: story.id, testIndex },
79
- }));
80
- return { repaired: false, escalate: false, error: err.message };
81
- }
82
-
83
- if (!result?.ok) {
84
- logger.warn(`Repairer failed: ${result?.summary || "unknown"}`);
85
- emitProgress(emitter, makeEvent("repair:end", { ...eventBase, stage: "repair" }, {
86
- status: "fail",
87
- message: `Repairer could not produce a verdict: ${result?.summary || "unknown"}`,
88
- detail: { huId: story.id, testIndex },
89
- }));
90
- return { repaired: false, escalate: false, error: result?.summary || "no verdict" };
91
- }
92
-
93
- const { verdict, fixed_test: fixedTest, reason } = result.result;
94
-
95
- if (verdict === "unfixable") {
96
- logger.info(`Repairer: HU ${story.id} test #${testIndex} unfixable — ${reason}`);
97
- emitProgress(emitter, makeEvent("repair:end", { ...eventBase, stage: "repair" }, {
98
- status: "escalate",
99
- message: `Repairer: unfixable — ${reason}`,
100
- detail: { huId: story.id, testIndex, reason },
101
- }));
102
- return { repaired: false, escalate: true, reason };
103
- }
104
-
105
- if (verdict !== "fixable" || !fixedTest) {
106
- logger.warn(`Repairer returned unexpected verdict: ${verdict}`);
107
- return { repaired: false, escalate: false, error: `unexpected verdict: ${verdict}` };
108
- }
109
-
110
- // Apply the fix in-memory and persist when we have the batch handle.
111
- // Some callers can't pass `batch` from their scope (closure depth);
112
- // the in-memory mutation of `story.acceptance_tests` is enough for
113
- // the next iteration of the same HU loop because every acceptance
114
- // run reads the live story object. Disk persistence is a "next run
115
- // sees the fix too" optimisation; PR #544's reconcile keeps the
116
- // plan JSON consistent across runs in either case.
117
- story.acceptance_tests[testIndex] = fixedTest;
118
- if (batch && batchSessionId) {
119
- await saveHuBatch(batchSessionId, batch);
120
- }
121
-
122
- if (typeof savePlanPatch === "function") {
123
- try {
124
- await savePlanPatch(story.id, { acceptance_tests: story.acceptance_tests });
125
- } catch (err) {
126
- logger.warn(`Repairer: in-memory + batch fixed but plan-patch failed: ${err.message}`);
127
- }
128
- }
129
-
130
- logger.info(`Repairer: HU ${story.id} test #${testIndex} REPAIRED — ${reason}`);
131
- emitProgress(emitter, makeEvent("repair:end", { ...eventBase, stage: "repair" }, {
132
- status: "ok",
133
- message: `Repairer fixed HU ${story.id} test #${testIndex}: ${reason}`,
134
- detail: {
135
- huId: story.id,
136
- testIndex,
137
- reason,
138
- fixedContent: typeof fixedTest === "object" ? fixedTest.content : fixedTest,
139
- },
140
- }));
141
- return { repaired: true, reason };
142
- }
@@ -1,45 +0,0 @@
1
- import { ReviewerRole } from "../roles/reviewer-role.js";
2
- import { createAgent } from "../agents/index.js";
3
- import { addCheckpoint } from "../session/store.js";
4
-
5
- export async function runReviewerWithFallback({ reviewerName, config, logger, emitter, reviewInput, session, iteration, onAttemptResult }) {
6
- const fallbackReviewer = config.reviewer_options?.fallback_reviewer;
7
- const retries = Math.max(0, Number(config.reviewer_options?.retries ?? 1));
8
- const candidates = [reviewerName];
9
- if (fallbackReviewer && fallbackReviewer !== reviewerName) {
10
- candidates.push(fallbackReviewer);
11
- }
12
-
13
- const attempts = [];
14
- for (const name of candidates) {
15
- const reviewerConfig = { ...config, roles: { ...config.roles, reviewer: { ...config.roles?.reviewer, provider: name } } };
16
- const role = new ReviewerRole({ config: reviewerConfig, logger, emitter, createAgentFn: createAgent });
17
- await role.init();
18
- for (let attempt = 1; attempt <= retries + 1; attempt += 1) {
19
- let execResult;
20
- try {
21
- execResult = await role.execute(reviewInput);
22
- } catch (err) {
23
- logger.warn(`Reviewer ${name} attempt ${attempt} threw: ${err.message}`);
24
- execResult = { ok: false, result: { error: err.message }, summary: `Reviewer error: ${err.message}` };
25
- }
26
- if (onAttemptResult) {
27
- await onAttemptResult({ reviewer: name, result: execResult.result });
28
- }
29
- attempts.push({ reviewer: name, attempt, ok: execResult.ok, result: execResult.result, execResult });
30
- await addCheckpoint(session, {
31
- stage: "reviewer-attempt",
32
- iteration,
33
- reviewer: name,
34
- attempt,
35
- ok: execResult.ok
36
- });
37
-
38
- if (execResult.ok) {
39
- return { execResult, attempts };
40
- }
41
- }
42
- }
43
-
44
- return { execResult: null, attempts };
45
- }
@@ -1,189 +0,0 @@
1
- // Compress role outputs before passing as context to the next role.
2
- // Reduces token usage by extracting essentials and dropping verbose explanations.
3
-
4
- /**
5
- * Compression strategies per role output type.
6
- */
7
- const COMPRESSORS = {
8
- researcher: compressResearcher,
9
- architect: compressArchitect,
10
- planner: compressPlanner,
11
- reviewer: compressReviewer,
12
- tester: compressTester,
13
- security: compressSecurity,
14
- sonar: compressSonar,
15
- default: compressDefault
16
- };
17
-
18
- /**
19
- * Extract essentials from researcher output.
20
- */
21
- function compressResearcher(output) {
22
- if (!output || typeof output !== "object") return output;
23
- const parts = [];
24
- if (output.affected_files?.length) parts.push(`Files: ${output.affected_files.join(", ")}`);
25
- if (output.patterns?.length) parts.push(`Patterns: ${output.patterns.join(", ")}`);
26
- if (output.risks?.length) parts.push(`Risks: ${output.risks.join(", ")}`);
27
- if (output.constraints?.length) parts.push(`Constraints: ${output.constraints.join(", ")}`);
28
- return parts.join("\n");
29
- }
30
-
31
- /**
32
- * Extract essentials from architect output.
33
- */
34
- function compressArchitect(output) {
35
- if (!output || typeof output !== "object") return output;
36
- const arch = output.architecture || output;
37
- const parts = [];
38
- if (arch.type) parts.push(`Type: ${arch.type}`);
39
- if (arch.layers?.length) parts.push(`Layers: ${arch.layers.join(" → ")}`);
40
- if (arch.patterns?.length) parts.push(`Patterns: ${arch.patterns.join(", ")}`);
41
- const entities = arch.dataModel?.entities;
42
- if (entities?.length) {
43
- const names = entities.map(e => typeof e === "string" ? e : e.name).filter(Boolean);
44
- if (names.length) parts.push(`Entities: ${names.join(", ")}`);
45
- }
46
- if (output.verdict) parts.push(`Verdict: ${output.verdict}`);
47
- return parts.join("\n");
48
- }
49
-
50
- /**
51
- * Extract essentials from planner output — keep numbered steps only.
52
- */
53
- function compressPlanner(output) {
54
- if (!output || typeof output !== "object") return output;
55
- const plan = output.plan || output;
56
- if (typeof plan !== "string") return JSON.stringify(plan);
57
-
58
- // Keep only numbered steps, drop prose
59
- const lines = plan.split("\n").filter(l => l.trim());
60
- const steps = lines.filter(l => /^\s*\d+[.)]\s/.test(l) || /^\s*[-*]\s/.test(l));
61
- if (steps.length >= 3) return steps.join("\n");
62
- return plan.slice(0, 1500);
63
- }
64
-
65
- /**
66
- * Compress reviewer output — drop non-blocking suggestions, keep blocking.
67
- */
68
- function compressReviewer(output) {
69
- if (!output || typeof output !== "object") return output;
70
- const blocking = output.blocking_issues || [];
71
- if (!blocking.length) return `Approved${output.summary ? `: ${output.summary.slice(0, 200)}` : ""}`;
72
-
73
- const items = blocking.map((x, i) => {
74
- const sev = x.severity ? `[${x.severity}]` : "";
75
- const loc = x.file ? ` (${x.file}${x.line ? `:${x.line}` : ""})` : "";
76
- return `${i + 1}. ${sev}${loc} ${x.description || "no description"}${x.suggested_fix ? ` — Fix: ${x.suggested_fix}` : ""}`;
77
- });
78
- return `Rejected (${blocking.length} blocking):\n${items.join("\n")}`;
79
- }
80
-
81
- /**
82
- * Compress tester output — keep verdict + coverage + missing scenarios.
83
- */
84
- function compressTester(output) {
85
- if (!output || typeof output !== "object") return output;
86
- const parts = [];
87
- parts.push(`Verdict: ${output.verdict || "unknown"}`);
88
- if (output.coverage?.overall != null) parts.push(`Coverage: ${output.coverage.overall}%`);
89
- if (output.missing_scenarios?.length) {
90
- parts.push(`Missing: ${output.missing_scenarios.slice(0, 5).join("; ")}`);
91
- }
92
- if (output.quality_issues?.length) {
93
- parts.push(`Quality: ${output.quality_issues.slice(0, 3).join("; ")}`);
94
- }
95
- return parts.join("\n");
96
- }
97
-
98
- /**
99
- * Compress security output — keep verdict + grouped vulnerabilities.
100
- */
101
- function compressSecurity(output) {
102
- if (!output || typeof output !== "object") return output;
103
- const vulns = output.vulnerabilities || [];
104
- if (vulns.length === 0) return `Verdict: ${output.verdict || "pass"}; no vulnerabilities`;
105
-
106
- const bySev = {};
107
- for (const v of vulns) {
108
- const sev = v.severity || "unknown";
109
- bySev[sev] = bySev[sev] || [];
110
- bySev[sev].push(`${v.file || "?"}${v.line ? `:${v.line}` : ""} ${v.description}`);
111
- }
112
-
113
- const sevOrder = ["critical", "high", "medium", "low"];
114
- const lines = [`Verdict: ${output.verdict || "fail"}`];
115
- for (const sev of sevOrder) {
116
- if (bySev[sev]?.length) lines.push(`${sev}: ${bySev[sev].slice(0, 3).join("; ")}`);
117
- }
118
- return lines.join("\n");
119
- }
120
-
121
- /**
122
- * Compress sonar output — keep gate status + top issues.
123
- */
124
- function compressSonar(output) {
125
- if (!output || typeof output !== "object") return output;
126
- const parts = [];
127
- if (output.gateStatus) parts.push(`Gate: ${output.gateStatus}`);
128
- if (output.issues?.length) {
129
- parts.push(`${output.issues.length} issue(s)`);
130
- const top = output.issues.slice(0, 5).map(i => `${i.severity}: ${i.message}`);
131
- parts.push(top.join("; "));
132
- }
133
- return parts.join("\n");
134
- }
135
-
136
- /**
137
- * Default compression: truncate long strings, drop noise.
138
- */
139
- function compressDefault(output) {
140
- if (!output) return "";
141
- if (typeof output === "string") {
142
- return output.length > 2000 ? output.slice(0, 2000) + "...[truncated]" : output;
143
- }
144
- if (typeof output === "object") {
145
- const str = JSON.stringify(output, null, 2);
146
- return str.length > 2000 ? str.slice(0, 2000) + "...[truncated]" : str;
147
- }
148
- return String(output);
149
- }
150
-
151
- /**
152
- * Compress a role output.
153
- * @param {string} roleName - e.g. "researcher", "reviewer"
154
- * @param {*} output - role's result object
155
- * @returns {string} compressed text
156
- */
157
- export function compressRoleOutput(roleName, output) {
158
- const compressor = COMPRESSORS[roleName] || COMPRESSORS.default;
159
- try {
160
- return compressor(output);
161
- } catch {
162
- return COMPRESSORS.default(output);
163
- }
164
- }
165
-
166
- /**
167
- * Estimate token count for a compressed string (rough: chars/4).
168
- */
169
- export function estimateTokens(text) {
170
- if (!text) return 0;
171
- return Math.ceil(String(text).length / 4);
172
- }
173
-
174
- /**
175
- * Measure compression ratio.
176
- */
177
- export function measureCompression(original, compressed) {
178
- const origTokens = estimateTokens(typeof original === "string" ? original : JSON.stringify(original));
179
- const compTokens = estimateTokens(compressed);
180
- const saved = origTokens - compTokens;
181
- const ratio = origTokens > 0 ? saved / origTokens : 0;
182
- return {
183
- originalTokens: origTokens,
184
- compressedTokens: compTokens,
185
- savedTokens: saved,
186
- savedPct: Number((ratio * 100).toFixed(1))
187
- };
188
- }
189
-
@@ -1,308 +0,0 @@
1
- // Session Journal: persists structured stage outputs and generates summaries.
2
- // Creates .reviews/session_*/ directories containing markdown files per stage.
3
- import fs from "node:fs/promises";
4
- import path from "node:path";
5
-
6
- /**
7
- * Create the journal directory for a session.
8
- * @param {string} reportDir -base directory (e.g. ".reviews")
9
- * @param {string} sessionId
10
- * @returns {Promise<string>} absolute path to the journal directory
11
- */
12
- export async function createJournalDir(reportDir, sessionId) {
13
- const journalDir = path.resolve(reportDir, sessionId);
14
- await fs.mkdir(journalDir, { recursive: true });
15
- return journalDir;
16
- }
17
-
18
- /**
19
- * Write a markdown file to the journal directory.
20
- * Only writes if content is non-empty. Skips silently otherwise.
21
- */
22
- async function writeJournalFile(journalDir, filename, content) {
23
- if (!content || !journalDir) return;
24
- const filePath = path.join(journalDir, filename);
25
- await fs.writeFile(filePath, content, "utf8");
26
- }
27
-
28
- // ── Stage serializers ────────────────────────────────────────────────────────
29
-
30
- function serializeDiscovery(stageResult) {
31
- if (!stageResult) return null;
32
- const lines = ["# Discovery\n"];
33
- lines.push(`**Verdict**: ${stageResult.verdict || "N/A"}`);
34
- lines.push(`**Mode**: ${stageResult.mode || "gaps"}\n`);
35
-
36
- const gaps = stageResult.gaps || [];
37
- if (gaps.length) {
38
- lines.push("## Gaps Found\n");
39
- for (const gap of gaps) {
40
- const severity = gap.severity ? ` [${gap.severity}]` : "";
41
- lines.push(`- ${gap.title || gap.description || gap}${severity}`);
42
- }
43
- }
44
-
45
- if (stageResult.momTestQuestions?.length) {
46
- lines.push("\n## Mom Test Questions\n");
47
- for (const q of stageResult.momTestQuestions) lines.push(`- ${q}`);
48
- }
49
- if (stageResult.wendelChecklist?.length) {
50
- lines.push("\n## Wendel Checklist\n");
51
- for (const item of stageResult.wendelChecklist) lines.push(`- [${item.status}] ${item.condition}`);
52
- }
53
-
54
- return lines.join("\n");
55
- }
56
-
57
- function serializeResearch(stageResult) {
58
- if (!stageResult) return null;
59
- const lines = ["# Research\n"];
60
-
61
- const sections = [
62
- { key: "affected_files", title: "Affected Files" },
63
- { key: "patterns", title: "Patterns" },
64
- { key: "constraints", title: "Constraints" },
65
- { key: "risks", title: "Risks" },
66
- { key: "prior_decisions", title: "Prior Decisions" }
67
- ];
68
-
69
- for (const { key, title } of sections) {
70
- const items = stageResult[key];
71
- if (items?.length) {
72
- lines.push(`## ${title}\n`);
73
- for (const item of items) lines.push(`- ${item}`);
74
- lines.push("");
75
- }
76
- }
77
-
78
- if (stageResult.test_coverage) {
79
- lines.push(`## Test Coverage\n\n${stageResult.test_coverage}`);
80
- }
81
-
82
- return lines.join("\n");
83
- }
84
-
85
- function serializeArchitecture(stageResult) {
86
- if (!stageResult) return null;
87
- const lines = ["# Architecture\n"];
88
- lines.push(`**Verdict**: ${stageResult.verdict || "N/A"}\n`);
89
-
90
- const arch = stageResult.architecture || {};
91
- if (arch.type) lines.push(`**Type**: ${arch.type}\n`);
92
- if (arch.layers?.length) {
93
- lines.push("## Layers\n");
94
- for (const l of arch.layers) lines.push(`- ${l}`);
95
- lines.push("");
96
- }
97
- if (arch.patterns?.length) {
98
- lines.push("## Patterns\n");
99
- for (const p of arch.patterns) lines.push(`- ${p}`);
100
- lines.push("");
101
- }
102
- if (arch.dataModel?.entities?.length) {
103
- lines.push("## Data Model\n");
104
- for (const e of arch.dataModel.entities) lines.push(`- ${typeof e === "string" ? e : e.name || JSON.stringify(e)}`);
105
- lines.push("");
106
- }
107
- if (arch.apiContracts?.length) {
108
- lines.push("## API Contracts\n");
109
- for (const a of arch.apiContracts) lines.push(`- ${typeof a === "string" ? a : JSON.stringify(a)}`);
110
- lines.push("");
111
- }
112
- if (arch.tradeoffs?.length) {
113
- lines.push("## Tradeoffs\n");
114
- for (const t of arch.tradeoffs) lines.push(`- ${t}`);
115
- }
116
- if (stageResult.questions?.length) {
117
- lines.push("\n## Open Questions\n");
118
- for (const q of stageResult.questions) lines.push(`- ${q}`);
119
- }
120
-
121
- return lines.join("\n");
122
- }
123
-
124
- function serializePlan(stageResult) {
125
- if (!stageResult?.plan) return null;
126
- return `# Implementation Plan\n\n${stageResult.plan}`;
127
- }
128
-
129
- function serializeTriage(stageResult) {
130
- if (!stageResult) return null;
131
- const lines = ["# Triage\n"];
132
- lines.push(`**Level**: ${stageResult.level || "N/A"}`);
133
- lines.push(`**Task Type**: ${stageResult.taskType || "N/A"}`);
134
- lines.push(`**Roles**: ${(stageResult.roles || []).join(", ") || "none"}`);
135
- if (stageResult.reasoning) lines.push(`\n**Reasoning**: ${stageResult.reasoning}`);
136
- if (stageResult.shouldDecompose) {
137
- lines.push("\n## Decomposition\n");
138
- for (const sub of stageResult.subtasks || []) lines.push(`- ${sub}`);
139
- }
140
- return lines.join("\n");
141
- }
142
-
143
- // ── Iteration log ────────────────────────────────────────────────────────────
144
-
145
- /**
146
- * Append one iteration entry to the iterations buffer.
147
- * Called after each iteration completes.
148
- */
149
- export function formatIteration({ iteration, coderSummary, reviewerSummary, sonarSummary, solomonRuling, testerSummary, securitySummary, durationMs }) {
150
- const lines = [`## Iteration ${iteration}\n`];
151
- lines.push(`**Duration**: ${Math.round((durationMs || 0) / 1000)}s\n`);
152
-
153
- if (coderSummary) lines.push(`**Coder**: ${coderSummary}`);
154
- if (reviewerSummary) lines.push(`**Reviewer**: ${reviewerSummary}`);
155
- if (sonarSummary) lines.push(`**Sonar**: ${sonarSummary}`);
156
- if (testerSummary) lines.push(`**Tester**: ${testerSummary}`);
157
- if (securitySummary) lines.push(`**Security**: ${securitySummary}`);
158
- if (solomonRuling) lines.push(`**Solomon**: ${solomonRuling}`);
159
-
160
- lines.push("");
161
- return lines.join("\n");
162
- }
163
-
164
- // ── Decisions log ────────────────────────────────────────────────────────────
165
-
166
- export function formatDecision({ timestamp, trigger, context, action, reasoning }) {
167
- const lines = [`## ${timestamp || new Date().toISOString()}\n`];
168
- lines.push(`**Trigger**: ${trigger}`);
169
- if (context) lines.push(`**Context**: ${context}`);
170
- lines.push(`**Action**: ${action}`);
171
- if (reasoning) lines.push(`**Reasoning**: ${reasoning}`);
172
- lines.push("");
173
- return lines.join("\n");
174
- }
175
-
176
- // ── Summary ──────────────────────────────────────────────────────────────────
177
-
178
- export function generateSummary({ task, result, sessionId, iterations, durationMs, budget, stages, commits, files }) {
179
- const lines = ["# Session Summary\n"];
180
- lines.push(`**Session**: ${sessionId}`);
181
- lines.push(`**Task**: ${task}`);
182
- lines.push(`**Result**: ${result}`);
183
- lines.push(`**Iterations**: ${iterations}`);
184
- lines.push(`**Duration**: ${Math.round((durationMs || 0) / 1000)}s`);
185
-
186
- if (budget) {
187
- lines.push(`**Budget**: ~$${budget.total_cost_usd?.toFixed(2) || "?"} / ~${budget.total_tokens?.toLocaleString() || "?"} tokens`);
188
- }
189
-
190
- if (stages && Object.keys(stages).length) {
191
- lines.push("\n## Stages Executed\n");
192
- for (const [name, stageResult] of Object.entries(stages)) {
193
- const status = stageResult?.ok !== false ? "pass" : "fail";
194
- const summary = stageResult?.summary || "";
195
- lines.push(`- **${name}**: ${status}${summary ? ` -${summary}` : ""}`);
196
- }
197
- }
198
-
199
- if (commits?.length) {
200
- lines.push("\n## Commits\n");
201
- for (const c of commits) lines.push(`- \`${(c.hash || "").slice(0, 7)}\` ${c.message || ""}`);
202
- }
203
-
204
- // List journal files
205
- lines.push("\n## Journal Files\n");
206
- for (const f of files) lines.push(`- [${f}](./${f})`);
207
-
208
- return lines.join("\n");
209
- }
210
-
211
- // ── Pipeline plan display ────────────────────────────────────────────────────
212
-
213
- /**
214
- * Build a console-friendly pipeline plan summary.
215
- * Shown before the iteration loop starts.
216
- */
217
- export function buildPlanSummary({ pipelineFlags, config, stageResults, task }) {
218
- const lines = [];
219
- lines.push("┌─ Pipeline Plan ─────────────────────────────");
220
-
221
- // Task (truncated)
222
- const taskPreview = task.length > 80 ? task.slice(0, 77) + "..." : task;
223
- lines.push(`│ Task: ${taskPreview}`);
224
-
225
- // Triage result
226
- const triage = stageResults?.triage;
227
- if (triage) {
228
- lines.push(`│ Triage: ${triage.level} (${triage.taskType || "sw"}) → roles: ${(triage.roles || []).join(", ")}`);
229
- }
230
-
231
- // Active stages
232
- const activeStages = [];
233
- if (pipelineFlags.researcherEnabled) activeStages.push("Researcher");
234
- if (pipelineFlags.architectEnabled) activeStages.push("Architect");
235
- if (pipelineFlags.plannerEnabled) activeStages.push("Planner");
236
- activeStages.push("Coder");
237
- if (pipelineFlags.refactorerEnabled) activeStages.push("Refactorer");
238
- if (pipelineFlags.reviewerEnabled) activeStages.push("Reviewer");
239
- if (pipelineFlags.testerEnabled) activeStages.push("Tester");
240
- if (pipelineFlags.securityEnabled) activeStages.push("Security");
241
- if (pipelineFlags.impeccableEnabled) activeStages.push("Impeccable");
242
- if (pipelineFlags.perfEnabled) activeStages.push("Perf");
243
- lines.push(`│ Stages: ${activeStages.join(" → ")}`);
244
-
245
- // Config
246
- const methodology = config.development?.methodology || "standard";
247
- const maxIter = config.max_iterations || 5;
248
- const solomonOn = config.pipeline?.solomon?.enabled !== false;
249
- lines.push(`│ Method: ${methodology} | Max iterations: ${maxIter} | Solomon: ${solomonOn ? "on" : "off"}`);
250
-
251
- // Plan summary (if planner ran)
252
- const plan = stageResults?.planner;
253
- if (plan?.plan) {
254
- const planLines = plan.plan.split("\n").filter(l => l.trim());
255
- const preview = planLines.slice(0, 5);
256
- lines.push("│");
257
- lines.push("│ Plan:");
258
- for (const pl of preview) lines.push(`│ ${pl}`);
259
- if (planLines.length > 5) lines.push(`│ ... (${planLines.length - 5} more steps)`);
260
- }
261
-
262
- lines.push("└──────────────────────────────────────────────");
263
- return lines.join("\n");
264
- }
265
-
266
- // ── Main write functions ─────────────────────────────────────────────────────
267
-
268
- /**
269
- * Write all pre-loop stage outputs to the journal.
270
- */
271
- export async function writePreLoopJournal(journalDir, stageResults) {
272
- const writes = [
273
- { file: "triage.md", content: serializeTriage(stageResults.triage) },
274
- { file: "discovery.md", content: serializeDiscovery(stageResults.discover) },
275
- { file: "research.md", content: serializeResearch(stageResults.researcher) },
276
- { file: "architecture.md", content: serializeArchitecture(stageResults.architect) },
277
- { file: "plan.md", content: serializePlan(stageResults.planner) }
278
- ];
279
-
280
- await Promise.all(
281
- writes.filter(w => w.content).map(w => writeJournalFile(journalDir, w.file, w.content))
282
- );
283
-
284
- return writes.filter(w => w.content).map(w => w.file);
285
- }
286
-
287
- /**
288
- * Write the iterations log.
289
- */
290
- export async function writeIterationsJournal(journalDir, iterationEntries) {
291
- if (!iterationEntries?.length) return;
292
- const content = "# Iterations\n\n" + iterationEntries.join("\n");
293
- await writeJournalFile(journalDir, "iterations.md", content);
294
- }
295
-
296
- /**
297
- * Write the decisions log.
298
- */
299
- export async function writeDecisionsJournal(journalDir, decisionEntries) {
300
- if (!decisionEntries?.length) return;
301
- const content = "# Solomon Decisions\n\n" + decisionEntries.join("\n");
302
- await writeJournalFile(journalDir, "decisions.md", content);
303
- }
304
-
305
- // writeTreeJournal / writeSummaryJournal / generateFileTree were
306
- // superseded in v2.7.x by src/session/journal/{tree-writer,summary-writer}.js
307
- // (the V2 split). post-loop.js dynamically imports the V2 versions; this
308
- // orchestrator-side copy is no longer wired anywhere. KJC-TSK-0354 PR-D.