karajan-code 4.70.4 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (380) hide show
  1. package/README.md +2 -2
  2. package/package.json +6 -14
  3. package/packages/hu-board/package.json +1 -1
  4. package/packages/hu-board/public/app.js +4 -18
  5. package/packages/hu-board/public/index.html +5 -2
  6. package/packages/hu-board/public/styles.css +26 -0
  7. package/packages/hu-board/public/utils/api.js +0 -74
  8. package/packages/hu-board/public/utils/board-tour.js +62 -0
  9. package/packages/hu-board/public/utils/board-view.js +49 -144
  10. package/packages/hu-board/public/utils/command-launcher.js +8 -70
  11. package/packages/hu-board/public/utils/formatters.js +10 -0
  12. package/packages/hu-board/public/utils/governance-view.js +13 -1
  13. package/packages/hu-board/public/utils/hu-actions.js +17 -68
  14. package/packages/hu-board/public/utils/init-listeners.js +7 -8
  15. package/packages/hu-board/public/utils/log-panel.js +3 -16
  16. package/packages/hu-board/public/utils/maggle-mode.js +2 -12
  17. package/packages/hu-board/public/utils/modals.js +7 -0
  18. package/packages/hu-board/public/utils/project-picker-view.js +1 -1
  19. package/packages/hu-board/public/utils/server-push.js +3 -22
  20. package/packages/hu-board/public/utils/shared-board-notice.js +33 -0
  21. package/packages/hu-board/public/utils/story-detail-view.js +5 -19
  22. package/packages/hu-board/src/cleanup-zombies.js +0 -1
  23. package/packages/hu-board/src/command-runner.js +36 -25
  24. package/packages/hu-board/src/db-connection.js +282 -0
  25. package/packages/hu-board/src/db-paths.js +113 -0
  26. package/packages/hu-board/src/db-queries.js +188 -0
  27. package/packages/hu-board/src/db-tombstones.js +51 -0
  28. package/packages/hu-board/src/db.js +28 -619
  29. package/packages/hu-board/src/ephemeral-cleaner.js +2 -3
  30. package/packages/hu-board/src/hu-zombie-reaper.js +5 -1
  31. package/packages/hu-board/src/plan-mutations.js +3 -153
  32. package/packages/hu-board/src/plans-service.js +55 -0
  33. package/packages/hu-board/src/routes/api/commands.js +122 -0
  34. package/packages/hu-board/src/routes/api/plans.js +55 -0
  35. package/packages/hu-board/src/routes/api/projects.js +267 -0
  36. package/packages/hu-board/src/routes/api/prompts.js +135 -0
  37. package/packages/hu-board/src/routes/api/sessions.js +95 -0
  38. package/packages/hu-board/src/routes/api/stories.js +183 -0
  39. package/packages/hu-board/src/routes/api/system.js +241 -0
  40. package/packages/hu-board/src/routes/api/tombstones.js +38 -0
  41. package/packages/hu-board/src/routes/api.js +24 -1371
  42. package/packages/hu-board/src/routes/governance.js +23 -1
  43. package/packages/hu-board/src/routes/lanes.js +40 -0
  44. package/packages/hu-board/src/routes/rag.js +4 -3
  45. package/packages/hu-board/src/server.js +20 -34
  46. package/packages/hu-board/src/sync-files.js +318 -0
  47. package/packages/hu-board/src/sync-project.js +99 -0
  48. package/packages/hu-board/src/sync.js +22 -566
  49. package/packages/hu-board/src/zombie-reaper.js +1 -1
  50. package/scripts/dual-publish.mjs +19 -3
  51. package/scripts/postinstall.js +15 -2
  52. package/scripts/verify-pack-mcp.mjs +11 -7
  53. package/scripts/verify-pack.mjs +4 -4
  54. package/src/audit/audit-history.js +3 -2
  55. package/src/audit/dead-exports.js +68 -59
  56. package/src/audit/deterministic-summary.js +33 -13
  57. package/src/audit/npm-signatures.js +41 -0
  58. package/src/audit/sbom.js +35 -0
  59. package/src/checks/agent-token.js +112 -0
  60. package/src/checks/dir-setup.js +34 -1
  61. package/src/checks/native-build.js +21 -39
  62. package/src/checks/runner.js +128 -142
  63. package/src/cli/advanced-commands.js +6 -6
  64. package/src/cli/register-meta.js +42 -82
  65. package/src/cli/register-pipeline.js +8 -143
  66. package/src/cli/register-plan.js +9 -100
  67. package/src/cli/retired-commands.js +49 -0
  68. package/src/cli.js +18 -5
  69. package/src/commands/agent-run.js +40 -26
  70. package/src/commands/audit.js +127 -124
  71. package/src/commands/board.js +5 -9
  72. package/src/commands/check.js +29 -16
  73. package/src/commands/doctor.js +2 -0
  74. package/src/commands/env.js +176 -150
  75. package/src/commands/go.js +71 -53
  76. package/src/commands/harden.js +90 -81
  77. package/src/commands/hu-start.js +52 -0
  78. package/src/commands/hu.js +288 -221
  79. package/src/commands/identity.js +111 -78
  80. package/src/commands/init-atril.js +47 -0
  81. package/src/commands/init.js +11 -40
  82. package/src/commands/install-tools.js +70 -85
  83. package/src/commands/main-guard.js +78 -0
  84. package/src/commands/policy.js +226 -184
  85. package/src/commands/qmd.js +27 -21
  86. package/src/commands/rag.js +75 -48
  87. package/src/commands/review-gate.js +421 -341
  88. package/src/commands/start.js +4 -5
  89. package/src/commands/steward.js +96 -47
  90. package/src/commands/tournament.js +46 -37
  91. package/src/commands/worktree.js +94 -25
  92. package/src/config/loader.js +34 -17
  93. package/src/config/secrets.js +36 -0
  94. package/src/config.js +1 -0
  95. package/src/environment/adr.js +16 -2
  96. package/src/git/karajan-label.js +20 -8
  97. package/src/guards/main-guard.js +54 -0
  98. package/src/harden/hook-templates.js +16 -1
  99. package/src/harden/sentinel/posttooluse.mjs +18 -6
  100. package/src/harden/sentinel/pretooluse-sentinel.mjs +64 -36
  101. package/src/harden/sentinel/sentinel-lib.mjs +129 -26
  102. package/src/harden/sentinel/sentinel-shell.mjs +5 -16
  103. package/src/harden/sentinel/sessionstart.mjs +3 -2
  104. package/src/harden/sentinel/stop.mjs +5 -4
  105. package/src/harden/workflow-templates.js +1 -1
  106. package/src/hu/board-lookup.js +29 -0
  107. package/src/hu/gh-identity.js +23 -0
  108. package/src/hu/github-board.js +4 -2
  109. package/src/hu/lane-prune.js +15 -7
  110. package/src/hu/lane-setup.js +65 -0
  111. package/src/hu/lanes.js +66 -0
  112. package/src/hu/team-board-mirror.js +3 -2
  113. package/src/infrastructure/command-runner.js +1 -1
  114. package/src/infrastructure/file-system-service.js +1 -1
  115. package/src/mcp/handlers/direct-handlers.js +2 -292
  116. package/src/mcp/handlers/hu-handlers.js +1 -35
  117. package/src/mcp/handlers/management-handlers.js +2 -42
  118. package/src/mcp/server-handlers.js +16 -22
  119. package/src/mcp/tools.js +1 -196
  120. package/src/plan/lane-plans.js +54 -0
  121. package/src/plan/plan-store.js +7 -4
  122. package/src/policy/add.js +26 -12
  123. package/src/policy/adr-number-check.js +31 -0
  124. package/src/prompts/audit.js +299 -339
  125. package/src/prompts/card-context.js +10 -5
  126. package/src/prompts/reviewer.js +5 -2
  127. package/src/rag/auto-update.js +56 -43
  128. package/src/rag/bootstrap-index.js +28 -54
  129. package/src/rag/migrate.js +1 -1
  130. package/src/rag/onnx-fallback.js +2 -2
  131. package/src/rag/pid-lease.js +70 -0
  132. package/src/rag/project-store.js +2 -12
  133. package/src/review/card-first.js +57 -46
  134. package/src/review/gate-gitignore.js +23 -4
  135. package/src/review/gate-hook.js +12 -4
  136. package/src/review/one-shot-review.js +45 -35
  137. package/src/review/publish-pr.js +14 -2
  138. package/src/review/repo-docs.js +73 -0
  139. package/src/review/repo-stack.js +59 -0
  140. package/src/review/reviewer-fallback.js +19 -4
  141. package/src/review/seal-commit.js +29 -0
  142. package/src/review/sonar-pregate.js +59 -44
  143. package/src/review/third-party-review.js +90 -16
  144. package/src/review/third-party-size.js +43 -0
  145. package/src/review/third-party-skills.js +54 -0
  146. package/src/review/verify-pr.js +1 -24
  147. package/src/roles/audit-role.js +106 -125
  148. package/src/skills/atril-skills.js +5 -4
  149. package/src/sonar/scanner.js +116 -101
  150. package/src/steward/invariants.js +5 -4
  151. package/src/steward/phantom-sweep.js +66 -0
  152. package/src/tournament/judge.js +60 -53
  153. package/src/utils/gh-account.js +37 -0
  154. package/src/utils/git.js +0 -13
  155. package/src/utils/home-migration.js +7 -1
  156. package/src/utils/main-checkout.js +53 -0
  157. package/src/utils/qmd-collection.js +3 -1
  158. package/src/utils/welcome.js +3 -3
  159. package/templates/{skills → atril/commands}/kj-architect.md +5 -0
  160. package/templates/{skills → atril/commands}/kj-audit.md +5 -0
  161. package/templates/{skills → atril/commands}/kj-board.md +5 -0
  162. package/templates/{skills → atril/commands}/kj-code.md +5 -0
  163. package/templates/{skills → atril/commands}/kj-csv-transform.md +5 -0
  164. package/templates/{skills → atril/commands}/kj-data-report.md +5 -0
  165. package/templates/{skills → atril/commands}/kj-discover.md +5 -0
  166. package/templates/{skills → atril/commands}/kj-rag-query.md +5 -0
  167. package/templates/{skills → atril/commands}/kj-review.md +5 -0
  168. package/templates/{skills → atril/commands}/kj-security.md +5 -0
  169. package/templates/{skills → atril/commands}/kj-sonar.md +5 -0
  170. package/templates/{skills → atril/commands}/kj-sql-analysis.md +5 -0
  171. package/templates/{skills → atril/commands}/kj-test.md +5 -0
  172. package/packages/hu-board/public/utils/run-launcher.js +0 -169
  173. package/packages/hu-board/src/run-tracker.js +0 -121
  174. package/src/activity-log.js +0 -59
  175. package/src/agents/host-agent.js +0 -38
  176. package/src/agents/model-registry.js +0 -142
  177. package/src/audit/plan-adherence.js +0 -224
  178. package/src/autonomy/arbiter-role.js +0 -71
  179. package/src/autonomy/arbiter.js +0 -22
  180. package/src/autonomy/decider.js +0 -18
  181. package/src/autonomy/decision-resolver.js +0 -58
  182. package/src/autonomy/outcome-report.js +0 -55
  183. package/src/autonomy/stage-ask.js +0 -30
  184. package/src/brain/decision-tracker.js +0 -125
  185. package/src/brain/decisor.js +0 -243
  186. package/src/brain/solomon-consult.js +0 -171
  187. package/src/brain/standby-scheduler.js +0 -8
  188. package/src/budget/comparison.js +0 -96
  189. package/src/canvas/parse-md.js +0 -238
  190. package/src/canvas/schema.js +0 -101
  191. package/src/canvas/to-flat.js +0 -85
  192. package/src/canvas/validate.js +0 -163
  193. package/src/ci/dispatch.js +0 -99
  194. package/src/ci/index.js +0 -3
  195. package/src/ci/pr-diff.js +0 -26
  196. package/src/cli/register-standby.js +0 -26
  197. package/src/commands/architect.js +0 -111
  198. package/src/commands/autorun.js +0 -49
  199. package/src/commands/researcher.js +0 -54
  200. package/src/commands/resume.js +0 -72
  201. package/src/commands/review.js +0 -89
  202. package/src/commands/run.js +0 -185
  203. package/src/commands/standby.js +0 -117
  204. package/src/commands/status.js +0 -36
  205. package/src/commands/triage.js +0 -78
  206. package/src/commands/undo.js +0 -62
  207. package/src/domains/domain-loader.js +0 -245
  208. package/src/domains/domain-registry.js +0 -140
  209. package/src/domains/domain-synthesizer.js +0 -129
  210. package/src/git/automation.js +0 -433
  211. package/src/git/coder-commit-guard.js +0 -40
  212. package/src/git/hu-automation.js +0 -243
  213. package/src/git/hu-snapshot.js +0 -10
  214. package/src/git/symlink-targets.js +0 -57
  215. package/src/golden/asserter.js +0 -92
  216. package/src/golden/loader.js +0 -52
  217. package/src/golden/runner.js +0 -92
  218. package/src/golden/schema.js +0 -41
  219. package/src/guards/duplicate-members.js +0 -86
  220. package/src/guards/intent-guard.js +0 -161
  221. package/src/guards/perf-guard.js +0 -126
  222. package/src/guards/policy-guard.js +0 -90
  223. package/src/guards/policy-resolver.js +0 -85
  224. package/src/guards/secret-redactor.js +0 -71
  225. package/src/hu/acceptance-runner.js +0 -138
  226. package/src/hu/lazy-planner.js +0 -109
  227. package/src/hu/parallel-executor.js +0 -94
  228. package/src/hu/routing-metrics.js +0 -17
  229. package/src/hu/split-validator.js +0 -143
  230. package/src/hu/splitting-detector.js +0 -158
  231. package/src/hu/splitting-generator.js +0 -175
  232. package/src/hu/store.js +0 -394
  233. package/src/infrastructure/mocks.js +0 -182
  234. package/src/mcp/handlers/run-handler.js +0 -318
  235. package/src/mcp/sovereignty-guard.js +0 -113
  236. package/src/mcp/tool-arg-normalizers.js +0 -16
  237. package/src/mutate/reviewer-signal.js +0 -76
  238. package/src/orchestrator/agent-fallback.js +0 -81
  239. package/src/orchestrator/brain-coordinator.js +0 -186
  240. package/src/orchestrator/ci-integration.js +0 -139
  241. package/src/orchestrator/config-init.js +0 -426
  242. package/src/orchestrator/direct-actions.js +0 -217
  243. package/src/orchestrator/drivers/error-recovery.js +0 -287
  244. package/src/orchestrator/drivers/init-context.js +0 -238
  245. package/src/orchestrator/drivers/iteration-loop.js +0 -382
  246. package/src/orchestrator/drivers/iteration-phases/coder-and-refactorer.js +0 -69
  247. package/src/orchestrator/drivers/iteration-phases/guards.js +0 -91
  248. package/src/orchestrator/drivers/iteration-phases/handle-approved.js +0 -29
  249. package/src/orchestrator/drivers/iteration-phases/quality-gates.js +0 -125
  250. package/src/orchestrator/drivers/iteration-phases/reviewer-gate.js +0 -62
  251. package/src/orchestrator/drivers/post-loop.js +0 -404
  252. package/src/orchestrator/drivers/pre-loop-phases/auto-hu-batch.js +0 -137
  253. package/src/orchestrator/drivers/pre-loop-phases/config-deprecations.js +0 -47
  254. package/src/orchestrator/drivers/pre-loop-phases/ensure-addyosmani-skills.js +0 -84
  255. package/src/orchestrator/drivers/pre-loop-phases/inject-loaded-plan.js +0 -393
  256. package/src/orchestrator/drivers/pre-loop.js +0 -524
  257. package/src/orchestrator/drivers/run-hu-batch.js +0 -468
  258. package/src/orchestrator/feedback-enrichment.js +0 -140
  259. package/src/orchestrator/feedback-queue.js +0 -151
  260. package/src/orchestrator/flow-control.js +0 -170
  261. package/src/orchestrator/flow-runner.js +0 -365
  262. package/src/orchestrator/fs-leak-detector.js +0 -228
  263. package/src/orchestrator/hu-scheduler.js +0 -114
  264. package/src/orchestrator/hu-sub-pipeline.js +0 -642
  265. package/src/orchestrator/iteration-gate.js +0 -73
  266. package/src/orchestrator/iteration-stages.js +0 -9
  267. package/src/orchestrator/parallel-limiter.js +0 -74
  268. package/src/orchestrator/pipeline-context.js +0 -72
  269. package/src/orchestrator/post-loop-stages.js +0 -468
  270. package/src/orchestrator/pre-loop-stages.js +0 -11
  271. package/src/orchestrator/preflight-checks.js +0 -487
  272. package/src/orchestrator/repair/repair-detector.js +0 -117
  273. package/src/orchestrator/repair/repair-runner.js +0 -142
  274. package/src/orchestrator/reviewer-fallback.js +0 -45
  275. package/src/orchestrator/role-output-compressor.js +0 -189
  276. package/src/orchestrator/session-journal.js +0 -308
  277. package/src/orchestrator/solomon-escalation.js +0 -331
  278. package/src/orchestrator/solomon-rules.js +0 -212
  279. package/src/orchestrator/stages/acceptance-coverage-stage.js +0 -47
  280. package/src/orchestrator/stages/architect-stage.js +0 -172
  281. package/src/orchestrator/stages/coder-stage.js +0 -506
  282. package/src/orchestrator/stages/domain-curator-stage.js +0 -82
  283. package/src/orchestrator/stages/format-stage.js +0 -61
  284. package/src/orchestrator/stages/hu-reviewer-phases/detect-and-apply-splits.js +0 -127
  285. package/src/orchestrator/stages/hu-reviewer-stage.js +0 -419
  286. package/src/orchestrator/stages/perf-stage.js +0 -140
  287. package/src/orchestrator/stages/planner-stage.js +0 -85
  288. package/src/orchestrator/stages/rag-context-stage.js +0 -80
  289. package/src/orchestrator/stages/rag-preload-decisor.js +0 -58
  290. package/src/orchestrator/stages/research-stage.js +0 -69
  291. package/src/orchestrator/stages/reviewer-stage.js +0 -431
  292. package/src/orchestrator/stages/sonar-stage.js +0 -439
  293. package/src/orchestrator/stages/stage-classes.js +0 -84
  294. package/src/orchestrator/stages/stage-executor.js +0 -155
  295. package/src/orchestrator/stages/suite-green-stage.js +0 -62
  296. package/src/orchestrator/stages/tdd-discipline-stage.js +0 -56
  297. package/src/orchestrator/stages/tool-judge-stage.js +0 -53
  298. package/src/orchestrator/stages/triage-stage.js +0 -172
  299. package/src/orchestrator/standby.js +0 -71
  300. package/src/orchestrator/verification-gate.js +0 -183
  301. package/src/orchestrator.js +0 -22
  302. package/src/plan/adr-generator.js +0 -170
  303. package/src/plan/adr-loader.js +0 -60
  304. package/src/plan/plan-executor.js +0 -100
  305. package/src/plan/plan-validation.js +0 -4
  306. package/src/prompts/acceptance-coverage.js +0 -32
  307. package/src/prompts/arbiter.js +0 -38
  308. package/src/prompts/architect.js +0 -103
  309. package/src/prompts/hu-reviewer.js +0 -244
  310. package/src/prompts/tool-correctness-judge.js +0 -31
  311. package/src/prompts/triage.js +0 -57
  312. package/src/rag/embedder.js +0 -2
  313. package/src/rag/embedders/_cloud-base.js +0 -2
  314. package/src/rag/embedders/cohere.js +0 -2
  315. package/src/rag/embedders/mistral.js +0 -2
  316. package/src/rag/embedders/onnx.js +0 -2
  317. package/src/rag/embedders/openai.js +0 -2
  318. package/src/rag/embedders/voyage.js +0 -2
  319. package/src/rag/rerank.js +0 -4
  320. package/src/rag/where-parser.js +0 -4
  321. package/src/repeat-detector.js +0 -88
  322. package/src/review/diff-generator.js +0 -112
  323. package/src/review/git-stash-helper.js +0 -104
  324. package/src/review/schema.js +0 -31
  325. package/src/review/scope-filter.js +0 -152
  326. package/src/review/snapshot-diff.js +0 -122
  327. package/src/review/tdd-discipline.js +0 -90
  328. package/src/review/tdd-policy.js +0 -69
  329. package/src/roles/acceptance-coverage-role.js +0 -78
  330. package/src/roles/architect-role.js +0 -77
  331. package/src/roles/coder-role.js +0 -113
  332. package/src/roles/commiter-role.js +0 -113
  333. package/src/roles/domain-curator-role.js +0 -134
  334. package/src/roles/hu-reviewer-role.js +0 -64
  335. package/src/roles/impeccable-role.js +0 -85
  336. package/src/roles/index.js +0 -18
  337. package/src/roles/karajan-brain-role.js +0 -134
  338. package/src/roles/perf-role.js +0 -122
  339. package/src/roles/planner-role.js +0 -151
  340. package/src/roles/refactorer-role.js +0 -30
  341. package/src/roles/repairer-role.js +0 -181
  342. package/src/roles/researcher-role.js +0 -70
  343. package/src/roles/reviewer-role.js +0 -115
  344. package/src/roles/security-role.js +0 -73
  345. package/src/roles/solomon-role.js +0 -271
  346. package/src/roles/sonar-role.js +0 -72
  347. package/src/roles/tester-role.js +0 -235
  348. package/src/roles/tool-correctness-judge-role.js +0 -78
  349. package/src/roles/triage-role.js +0 -99
  350. package/src/session/journal/decisions-writer.js +0 -200
  351. package/src/session/journal/iteration-logger.js +0 -194
  352. package/src/session/journal/summary-writer.js +0 -320
  353. package/src/session/journal/tree-writer.js +0 -164
  354. package/src/session/journal/write-all.js +0 -89
  355. package/src/session-cleanup.js +0 -116
  356. package/src/skills/semantic-detector.js +0 -167
  357. package/src/skills/skill-detector.js +0 -385
  358. package/src/sonar/cloud-scanner.js +0 -78
  359. package/src/tracker-bootstrap.js +0 -44
  360. package/src/types/index.js +0 -38
  361. package/src/types/policy.js +0 -43
  362. package/src/types/solomon.js +0 -87
  363. package/src/utils/async-lock.js +0 -31
  364. package/src/utils/budget.js +0 -229
  365. package/src/utils/cwd-confirm.js +0 -39
  366. package/src/utils/display/event-handlers.js +0 -403
  367. package/src/utils/display/formatters.js +0 -132
  368. package/src/utils/display/header.js +0 -47
  369. package/src/utils/display/session-summary.js +0 -118
  370. package/src/utils/display/solomon.js +0 -42
  371. package/src/utils/pricing.js +0 -29
  372. package/src/utils/quota-simulator.js +0 -56
  373. package/src/utils/role-assigner.js +0 -137
  374. package/src/utils/rtk-wrapper.js +0 -87
  375. package/src/utils/run-registry.js +0 -9
  376. package/src/utils/status-dashboard.js +0 -254
  377. package/src/utils/tool-call-extractor.js +0 -56
  378. package/src/webperf/devtools-detect.js +0 -112
  379. package/src/webperf/webperf-role-integration.js +0 -66
  380. package/templates/skills/kj-run.md +0 -73
@@ -1,62 +0,0 @@
1
- /**
2
- * KJC-BUG-0298 (#1993): with TDD, a red suite never reaches the reviewer. A
3
- * step whose test was added without its implementation was approved with one
4
- * failing file, because nothing in the iteration RAN the tests: the
5
- * verification gate counts changed lines, the TDD check asks that tests changed
6
- * alongside sources, and the red-then-green discipline is opt-in. This stage
7
- * runs the project's own test command (the one kj harden resolves: npm test, a
8
- * known framework, pytest, go test) and hands a red suite back to the coder.
9
- * Opt-out: `development.require_green_suite: false`.
10
- */
11
- import { addCheckpoint, saveSession } from "../../session/store.js";
12
- import { setReviewerFeedback } from "../../session/mutators.js";
13
- import { emitProgress, makeEvent } from "../../utils/events.js";
14
- import { runCommand } from "../../utils/process.js";
15
- import { resolveCmds } from "../../commands/harden.js";
16
-
17
- const TAIL_CHARS = 2000;
18
- const DEFAULT_TIMEOUT_MS = 10 * 60 * 1000;
19
-
20
- /** Whether the project asks for a green suite (opt-out, and off in the test harness). */
21
- export function suiteGreenRequired(config) {
22
- return config?.development?.require_green_suite !== false && config?.testHarness?.disableSuiteGreenStage !== true;
23
- }
24
-
25
- /** @returns {Promise<{action: "ok"|"continue", result: object}>} */
26
- export async function runSuiteGreenStage({ config, logger, emitter, eventBase, session, iteration, resolveCmdsImpl = resolveCmds, runTestsImpl = null }) {
27
- const projectDir = config?.projectDir || process.cwd();
28
- let command = null;
29
- try {
30
- command = (await resolveCmdsImpl(projectDir))?.test || null;
31
- } catch (err) {
32
- logger?.warn?.(`suite-green: could not resolve the test command (${err.message})`);
33
- }
34
- if (!command) {
35
- const message = "suite-green: no test command for this project (package.json scripts.test or a known framework): the suite was NOT run";
36
- logger?.warn?.(message);
37
- emitProgress(emitter, makeEvent("tests:result", { ...eventBase, stage: "tests" }, { status: "warn", message, detail: { ran: false } }));
38
- return { action: "ok", result: { ran: false } };
39
- }
40
- const timeout = Number(config?.development?.test_timeout_ms) > 0 ? Number(config.development.test_timeout_ms) : DEFAULT_TIMEOUT_MS;
41
- const run = runTestsImpl || (async () => {
42
- // KJC-BUG-0427: never a login shell, which re-reads the person's profile and may rewrite
43
- // PATH (nvm drops node when npm_config_prefix is set): the suite runs in kj's own environment.
44
- const res = await runCommand("bash", ["-c", command], { cwd: projectDir, timeout });
45
- return { exitCode: res.exitCode ?? 1, output: `${res.stdout || ""}\n${res.stderr || ""}` };
46
- });
47
- const res = await run(command);
48
- const ok = res.exitCode === 0;
49
- const verdict = ok ? "green" : `red (exit ${res.exitCode})`;
50
- emitProgress(emitter, makeEvent("tests:result", { ...eventBase, stage: "tests" }, {
51
- status: ok ? "ok" : "fail",
52
- message: `${command}: ${verdict}`,
53
- detail: { ran: true, ok, command, exitCode: res.exitCode, executorType: "local" },
54
- }));
55
- await addCheckpoint(session, { stage: "suite-green", iteration, ok, command });
56
- if (ok) return { action: "ok", result: { ran: true, ok: true, command } };
57
- const tail = String(res.output || "").trim().slice(-TAIL_CHARS);
58
- setReviewerFeedback(session, `The test suite is RED (${command}, exit ${res.exitCode}). Make it green before anything else:\n${tail}`);
59
- await saveSession(session);
60
- logger?.warn?.(`suite-green: ${command} exited ${res.exitCode}; back to the coder`);
61
- return { action: "continue", result: { ran: true, ok: false, command, exitCode: res.exitCode } };
62
- }
@@ -1,56 +0,0 @@
1
- // TDD discipline stage (KJC-TSK-0398 PR3).
2
- // Runs the red-then-green check when `development.require_red_then_green`
3
- // is true. Wraps `verifyTddDiscipline` with the surgical stash helper and
4
- // the project's detected test framework. Gate is opt-in; an unsupported
5
- // framework reports a warning and does not block the iteration.
6
-
7
- import { detectTestFramework } from "../../utils/project-detect.js";
8
- import { verifyTddDiscipline } from "../../review/tdd-discipline.js";
9
- import { stashFilesAside, restoreFiles } from "../../review/git-stash-helper.js";
10
- import { runCommand } from "../../utils/process.js";
11
- import { emitProgress, makeEvent } from "../../utils/events.js";
12
-
13
- const TDD_DISCIPLINE_COMMANDS = {
14
- vitest: ["npx", ["vitest", "run", "--reporter=verbose"]],
15
- jest: ["npx", ["jest", "--verbose"]],
16
- pytest: ["pytest", ["--tb=short"]],
17
- };
18
-
19
- export async function runTddDisciplineStage({
20
- config, logger, emitter, eventBase, sourceFiles = [], testFiles = [],
21
- detectFramework = detectTestFramework,
22
- runTestsImpl,
23
- stashImpl = stashFilesAside,
24
- restoreImpl = restoreFiles,
25
- } = {}) {
26
- const projectDir = config?.projectDir || process.cwd();
27
- const detection = await detectFramework(projectDir);
28
- const framework = detection?.framework || null;
29
-
30
- const runTests = runTestsImpl || (async () => {
31
- const cmd = TDD_DISCIPLINE_COMMANDS[framework];
32
- if (!cmd) return { exitCode: 0, output: "" };
33
- const res = await runCommand(cmd[0], cmd[1], { cwd: projectDir, reject: false });
34
- return { exitCode: res.exitCode ?? 0, output: `${res.stdout || ""}\n${res.stderr || ""}` };
35
- });
36
-
37
- const result = await verifyTddDiscipline({
38
- projectDir, sourceFiles, testFiles, framework,
39
- runTests,
40
- stashFiles: (files) => stashImpl(files, { projectDir }),
41
- restoreFiles: (token) => restoreImpl(token, { projectDir }),
42
- });
43
-
44
- emitProgress(emitter, makeEvent("tdd:discipline", { ...eventBase, stage: "tdd" }, {
45
- status: result.ok ? "ok" : "fail",
46
- message: result.message || `TDD discipline: ${result.reason}`,
47
- detail: { reason: result.reason, framework },
48
- }));
49
-
50
- if (result.warning) logger?.warn?.(result.warning);
51
- if (!result.ok) {
52
- logger?.warn?.(`TDD discipline violation: ${result.reason}`);
53
- return { action: "continue", result };
54
- }
55
- return { action: "ok", result };
56
- }
@@ -1,53 +0,0 @@
1
- // KJC-TSK-0375 PR3 — ToolJudgeStage.
2
- // Opt-in (`pipeline.tool_judge.enabled`). Scores the coder's tool calls
3
- // extracted from `session.last_coder_transcript`. Non-blocking: a low
4
- // score emits a warn event and surfaces in summary but never gates the
5
- // iteration loop. Wiring lives in `quality-gates.js`.
6
-
7
- import { ToolCorrectnessJudgeRole } from "../../roles/tool-correctness-judge-role.js";
8
- import { extractToolCalls } from "../../utils/tool-call-extractor.js";
9
- import { emitProgress, makeEvent } from "../../utils/events.js";
10
-
11
- export async function runToolJudgeStage({
12
- config, logger, emitter, eventBase, session, coderRole, trackBudget,
13
- iteration, task,
14
- extractFn = extractToolCalls,
15
- RoleClass = ToolCorrectnessJudgeRole,
16
- } = {}) {
17
- logger?.setContext?.({ iteration, stage: "tool-judge" });
18
- emitProgress(emitter, makeEvent("toolJudge:start", { ...eventBase, stage: "tool-judge" }, {
19
- message: "Tool-judge scoring coder tool calls",
20
- }));
21
-
22
- const transcript = session?.last_coder_transcript || "";
23
- const provider = coderRole?.provider || "claude";
24
- const toolCalls = extractFn({ transcript, provider });
25
-
26
- const role = new RoleClass({ config, logger, emitter });
27
- const roleResult = await role.execute({ task, toolCalls });
28
-
29
- try { trackBudget?.("tool-judge", roleResult.usage || { tokens_in: 0, tokens_out: 0, cost_usd: 0 }); } catch { /* best-effort */ }
30
-
31
- const r = roleResult.result;
32
- const status = r?.skipped ? "skip" : r?.lowQuality ? "warn" : roleResult.ok ? "ok" : "fail";
33
-
34
- emitProgress(emitter, makeEvent("toolJudge:end", { ...eventBase, stage: "tool-judge" }, {
35
- status,
36
- message: roleResult.summary || "tool-judge done",
37
- detail: { score: r?.score ?? null, threshold: r?.threshold ?? null, skipped: Boolean(r?.skipped), callCount: toolCalls.length },
38
- }));
39
-
40
- return {
41
- action: "ok",
42
- stageResult: {
43
- ok: roleResult.ok !== false,
44
- score: r?.score ?? null,
45
- lowQuality: Boolean(r?.lowQuality),
46
- skipped: Boolean(r?.skipped),
47
- threshold: r?.threshold ?? null,
48
- summary: roleResult.summary || "",
49
- breakdown: r?.breakdown || [],
50
- callCount: toolCalls.length,
51
- },
52
- };
53
- }
@@ -1,172 +0,0 @@
1
- /**
2
- * Triage stage logic.
3
- * Extracted from pre-loop-stages.js for maintainability.
4
- */
5
-
6
- import { TriageRole } from "../../roles/triage-role.js";
7
- import { addCheckpoint } from "../../session/store.js";
8
- import { emitProgress, makeEvent, emitAgentOutput } from "../../utils/events.js";
9
- import { selectModelsForRoles } from "../../utils/model-selector.js";
10
- import { createStallDetector } from "../../utils/stall-detector.js";
11
-
12
- const ROLE_NAMES = ["planner", "researcher", "architect", "refactorer", "reviewer", "tester", "security", "impeccable"];
13
-
14
- // What each role is for. Used to explain — deterministically — why triage would
15
- // or would not turn a role on. These describe the role's trigger, never a claim
16
- // about the current task, so the rationale is never invented per run.
17
- const ROLE_PURPOSE = {
18
- planner: "planificación multi-fichero",
19
- researcher: "investigación de contexto externo",
20
- architect: "decisiones de arquitectura",
21
- refactorer: "refactor de código existente",
22
- reviewer: "revisión de cambios",
23
- tester: "cobertura de tests dedicada",
24
- security: "auditoría de seguridad",
25
- impeccable: "auditoría de diseño"
26
- };
27
-
28
- function buildRoleOverrides(recommendedRoles, pipelineConfig) {
29
- const overrides = {};
30
- for (const role of ROLE_NAMES) {
31
- overrides[`${role}Enabled`] = recommendedRoles.has(role) || Boolean(pipelineConfig[role]?.enabled);
32
- }
33
- return overrides;
34
- }
35
-
36
- // Per-role explanation of the activate/skip decision, mirroring buildRoleOverrides.
37
- // When triage failed, recommendations are unavailable: roles resolve from config
38
- // alone and skipped ones get a neutral "sin datos de triage" reason.
39
- function buildRoleRationale(recommendedRoles, pipelineConfig, triageOk) {
40
- return ROLE_NAMES.map((role) => {
41
- const forced = Boolean(pipelineConfig[role]?.enabled);
42
- const recommended = triageOk && recommendedRoles.has(role);
43
- const purpose = ROLE_PURPOSE[role];
44
-
45
- if (recommended) {
46
- return { role, enabled: true, source: "triage", reason: `recomendado por triage — ${purpose}` };
47
- }
48
- if (forced) {
49
- return { role, enabled: true, source: "config", reason: `forzado por configuración — ${purpose}` };
50
- }
51
- const reason = triageOk
52
- ? `no recomendado — ${purpose} sin aplicar`
53
- : `sin datos de triage — ${purpose} sin evaluar`;
54
- return { role, enabled: false, source: "none", reason };
55
- });
56
- }
57
-
58
- function applyModelSelection(triageOutput, config, emitter, eventBase) {
59
- if (!triageOutput.ok || !config?.model_selection?.enabled) return null;
60
- const level = triageOutput.result?.level;
61
- if (!level) return null;
62
-
63
- const { modelOverrides, reasoning } = selectModelsForRoles({ level, config });
64
- for (const [role, model] of Object.entries(modelOverrides)) {
65
- if (config.roles?.[role] && !config.roles[role].model) {
66
- config.roles[role].model = model;
67
- }
68
- }
69
- const modelSelection = { modelOverrides, reasoning };
70
- emitProgress(
71
- emitter,
72
- makeEvent("model-selection:applied", { ...eventBase, stage: "triage" }, {
73
- message: "Smart model selection applied",
74
- detail: modelSelection
75
- })
76
- );
77
- return modelSelection;
78
- }
79
-
80
- export async function runTriageStage({ config, logger, emitter, eventBase, session, coderRole, trackBudget }) {
81
- logger.setContext({ iteration: 0, stage: "triage" });
82
-
83
- const triageProvider = config?.roles?.triage?.provider || coderRole.provider;
84
- emitProgress(
85
- emitter,
86
- makeEvent("triage:start", { ...eventBase, stage: "triage" }, {
87
- message: "Triage classifying task complexity",
88
- detail: { provider: triageProvider, executorType: "agent" }
89
- })
90
- );
91
-
92
- const triageOnOutput = (payload) => emitAgentOutput(emitter, eventBase, "triage", triageProvider, payload);
93
- const triageStall = createStallDetector({
94
- onOutput: triageOnOutput, emitter, eventBase, stage: "triage", provider: triageProvider
95
- });
96
-
97
- const triage = new TriageRole({ config, logger, emitter });
98
- await triage.init({ task: session.task, sessionId: session.id, iteration: 0 });
99
- const triageStart = Date.now();
100
- let triageOutput;
101
- try {
102
- triageOutput = await triage.run({ task: session.task, onOutput: triageStall.onOutput });
103
- } catch (err) {
104
- logger.warn(`Triage threw: ${err.message}`);
105
- triageOutput = { ok: false, summary: `Triage error: ${err.message}`, result: { error: err.message } };
106
- } finally {
107
- triageStall.stop();
108
- }
109
- trackBudget({
110
- role: "triage",
111
- provider: config?.roles?.triage?.provider || coderRole.provider,
112
- model: config?.roles?.triage?.model || coderRole.model,
113
- result: triageOutput,
114
- duration_ms: Date.now() - triageStart
115
- });
116
-
117
- await addCheckpoint(session, {
118
- stage: "triage",
119
- iteration: 0,
120
- ok: triageOutput.ok,
121
- provider: config?.roles?.triage?.provider || coderRole.provider,
122
- model: config?.roles?.triage?.model || coderRole.model || null
123
- });
124
-
125
- const recommendedRoles = new Set(triageOutput.result?.roles || []);
126
- const roleOverrides = triageOutput.ok
127
- ? buildRoleOverrides(recommendedRoles, config.pipeline || {})
128
- : {};
129
-
130
- const shouldDecompose = triageOutput.result?.shouldDecompose || false;
131
- const subtasks = triageOutput.result?.subtasks || [];
132
-
133
- const domainHints = triageOutput.result?.domainHints || [];
134
-
135
- const stageResult = {
136
- ok: triageOutput.ok,
137
- level: triageOutput.result?.level || null,
138
- roles: Array.from(recommendedRoles),
139
- reasoning: triageOutput.result?.reasoning || null,
140
- taskType: triageOutput.result?.taskType || "sw",
141
- shouldDecompose,
142
- subtasks,
143
- domainHints,
144
- roleRationale: buildRoleRationale(recommendedRoles, config.pipeline || {}, triageOutput.ok)
145
- };
146
-
147
- const modelSelection = applyModelSelection(triageOutput, config, emitter, eventBase);
148
- if (modelSelection) {
149
- stageResult.modelSelection = modelSelection;
150
- }
151
-
152
- if (shouldDecompose && subtasks.length > 0) {
153
- emitProgress(
154
- emitter,
155
- makeEvent("triage:decompose", { ...eventBase, stage: "triage" }, {
156
- message: `Task decomposition recommended: ${subtasks.length} subtask${subtasks.length === 1 ? "" : "s"}`,
157
- detail: { shouldDecompose, subtasks }
158
- })
159
- );
160
- }
161
-
162
- emitProgress(
163
- emitter,
164
- makeEvent("triage:end", { ...eventBase, stage: "triage" }, {
165
- status: triageOutput.ok ? "ok" : "fail",
166
- message: triageOutput.ok ? "Triage completed" : `Triage failed: ${triageOutput.summary}`,
167
- detail: { ...stageResult, provider: triageProvider, executorType: "agent" }
168
- })
169
- );
170
-
171
- return { roleOverrides, stageResult };
172
- }
@@ -1,71 +0,0 @@
1
- import { emitProgress, makeEvent } from "../utils/events.js";
2
- import { setStatus } from "../session/mutators.js";
3
-
4
- const DEFAULT_COOLDOWN_MS = 5 * 60 * 1000; // 5 minutes
5
- const MAX_COOLDOWN_MS = 30 * 60 * 1000; // 30 minutes
6
- const MAX_STANDBY_RETRIES = 5;
7
- const HEARTBEAT_INTERVAL_MS = 30 * 1000; // 30 seconds
8
-
9
- /**
10
- * Wait for a rate limit cooldown, emitting heartbeat events.
11
- * Returns when the cooldown expires.
12
- *
13
- * @param {object} options
14
- * @param {number|null} options.cooldownMs - Milliseconds to wait (null = use default)
15
- * @param {string|null} options.cooldownUntil - ISO timestamp when cooldown expires
16
- * @param {string} options.agent - Agent that was rate-limited
17
- * @param {number} options.retryCount - Current retry attempt (for backoff)
18
- * @param {object} options.emitter - Event emitter
19
- * @param {object} options.eventBase - Base event fields
20
- * @param {object} options.logger
21
- * @param {object} options.session
22
- */
23
- export async function waitForCooldown({ cooldownMs, cooldownUntil, agent, retryCount, emitter, eventBase, logger, session }) {
24
- // Calculate wait time with exponential backoff for retries without known cooldown
25
- let waitMs = cooldownMs || DEFAULT_COOLDOWN_MS;
26
- if (!cooldownMs && retryCount > 0) {
27
- waitMs = Math.min(DEFAULT_COOLDOWN_MS * Math.pow(2, retryCount), MAX_COOLDOWN_MS);
28
- }
29
-
30
- const resumeAt = cooldownUntil || new Date(Date.now() + waitMs).toISOString();
31
-
32
- logger.info(`Standby: waiting ${Math.round(waitMs / 1000)}s for ${agent} rate limit (retry ${retryCount + 1}/${MAX_STANDBY_RETRIES})`);
33
-
34
- // Emit standby start event
35
- emitProgress(emitter, makeEvent("coder:standby", { ...eventBase, stage: "standby" }, {
36
- message: `Rate limited — standby until ${resumeAt} (attempt ${retryCount + 1}/${MAX_STANDBY_RETRIES})`,
37
- detail: { agent, cooldownUntil: resumeAt, cooldownMs: waitMs, retryCount: retryCount + 1, maxRetries: MAX_STANDBY_RETRIES }
38
- }));
39
-
40
- // Update session status
41
- setStatus(session, "standby");
42
-
43
- // Wait with periodic heartbeats
44
- const startTime = Date.now();
45
- const endTime = startTime + waitMs;
46
-
47
- while (Date.now() < endTime) {
48
- const remaining = endTime - Date.now();
49
- const sleepTime = Math.min(HEARTBEAT_INTERVAL_MS, remaining);
50
-
51
- await new Promise(resolve => setTimeout(resolve, sleepTime));
52
-
53
- if (Date.now() < endTime) {
54
- const remainingSec = Math.round((endTime - Date.now()) / 1000);
55
- emitProgress(emitter, makeEvent("coder:standby_heartbeat", { ...eventBase, stage: "standby" }, {
56
- message: `Standby: ${remainingSec}s remaining`,
57
- detail: { agent, remainingMs: endTime - Date.now(), retryCount: retryCount + 1 }
58
- }));
59
- }
60
- }
61
-
62
- // Emit resume event
63
- emitProgress(emitter, makeEvent("coder:standby_resume", { ...eventBase, stage: "standby" }, {
64
- message: `Cooldown expired — resuming with ${agent}`,
65
- detail: { agent, retryCount: retryCount + 1 }
66
- }));
67
-
68
- setStatus(session, "running");
69
- }
70
-
71
- export { DEFAULT_COOLDOWN_MS, MAX_COOLDOWN_MS, MAX_STANDBY_RETRIES, HEARTBEAT_INTERVAL_MS };
@@ -1,183 +0,0 @@
1
- // Verification gate: checks whether the coder actually produced changes.
2
- // Prevents advancing the pipeline when coder iterations produce 0 file changes.
3
-
4
- import { execFileSync } from "node:child_process";
5
-
6
- /**
7
- * @typedef {Object} VerificationResult
8
- * @property {boolean} passed - true if coder produced real changes
9
- * @property {number} filesChanged - count of modified/added/deleted files
10
- * @property {number} linesChanged - total lines added/deleted
11
- * @property {string[]} files - list of changed file paths
12
- * @property {string} reason - explanation when not passed
13
- * @property {string} [retryStrategy] - suggested retry approach when not passed
14
- */
15
-
16
- /**
17
- * Count files and lines changed since a base reference.
18
- * Uses git diff --numstat to get both file and line counts.
19
- *
20
- * Audit follow-up: was using execSync with template-string interpolation
21
- * of `baseRef` and `projectDir`. Both come ultimately from session
22
- * state / config — not user shell input — but the shape was a known
23
- * shell-injection vector. Switched to execFileSync with arg arrays so
24
- * no interpolation reaches /bin/sh.
25
- */
26
- export function countChangesSince(baseRef, projectDir = null) {
27
- try {
28
- const args = ["diff", "--numstat", String(baseRef)];
29
- if (projectDir) args.push("--", String(projectDir));
30
- const output = execFileSync("git", args, {
31
- encoding: "utf8", stdio: ["pipe", "pipe", "pipe"],
32
- }).trim();
33
-
34
- if (!output) return { files: [], filesChanged: 0, linesAdded: 0, linesDeleted: 0 };
35
-
36
- const lines = output.split("\n");
37
- const files = [];
38
- let linesAdded = 0;
39
- let linesDeleted = 0;
40
-
41
- for (const line of lines) {
42
- const [added, deleted, file] = line.split("\t");
43
- if (!file) continue;
44
- files.push(file);
45
- linesAdded += Number(added) || 0;
46
- linesDeleted += Number(deleted) || 0;
47
- }
48
-
49
- return { files, filesChanged: files.length, linesAdded, linesDeleted };
50
- } catch (err) {
51
- // Git itself failed (baseRef invalid, repo corrupt, git binary
52
- // missing). Previously we returned `filesChanged: 0` silently —
53
- // indistinguishable from "the coder did nothing". Surface the
54
- // error so verifyCoderOutput stops blaming the agent for an
55
- // infrastructure failure.
56
- return {
57
- files: [], filesChanged: 0, linesAdded: 0, linesDeleted: 0,
58
- gitError: err?.stderr?.toString?.() || err?.message || String(err),
59
- };
60
- }
61
- }
62
-
63
- /**
64
- * Also count untracked files (new files not yet added to git).
65
- *
66
- * Audit follow-up: same execSync→execFileSync change as countChangesSince.
67
- */
68
- export function countUntrackedFiles(projectDir = null) {
69
- try {
70
- const args = ["ls-files", "--others", "--exclude-standard"];
71
- if (projectDir) args.push(String(projectDir));
72
- const output = execFileSync("git", args, {
73
- encoding: "utf8", stdio: ["pipe", "pipe", "pipe"],
74
- }).trim();
75
-
76
- if (!output) return { files: [] };
77
- return { files: output.split("\n").filter(Boolean) };
78
- } catch (err) {
79
- return {
80
- files: [],
81
- gitError: err?.stderr?.toString?.() || err?.message || String(err),
82
- };
83
- }
84
- }
85
-
86
- /**
87
- * Verify that the coder produced real changes.
88
- * Counts both tracked changes and untracked files.
89
- *
90
- * @param {Object} params
91
- * @param {string} params.baseRef - git reference to compare against
92
- * @param {string} [params.projectDir] - directory scope
93
- * @param {number} [params.minFiles=1] - minimum files that must change
94
- * @param {number} [params.minLines=1] - minimum lines that must change
95
- * @returns {VerificationResult}
96
- */
97
- export function verifyCoderOutput({ baseRef, projectDir = null, minFiles = 1, minLines = 1 }) {
98
- const tracked = countChangesSince(baseRef, projectDir);
99
- const untracked = countUntrackedFiles(projectDir);
100
-
101
- // Git infra failure (bad baseRef, corrupt repo, git missing) — not
102
- // the coder's fault. Bail out with `gitError` so the caller can log
103
- // it and skip the "retry with explicit file paths" feedback that
104
- // would otherwise blame the agent.
105
- const gitError = tracked.gitError || untracked.gitError;
106
- if (gitError) {
107
- return {
108
- passed: false,
109
- filesChanged: 0,
110
- linesChanged: 0,
111
- files: [],
112
- reason: `Git verification failed: ${gitError}`,
113
- retryStrategy: null,
114
- gitError,
115
- };
116
- }
117
-
118
- const untrackedFiles = untracked.files || [];
119
- const totalFiles = tracked.filesChanged + untrackedFiles.length;
120
- const totalLines = tracked.linesAdded + tracked.linesDeleted;
121
- const allFiles = [...tracked.files, ...untrackedFiles];
122
-
123
- const passed = totalFiles >= minFiles && (untrackedFiles.length > 0 || totalLines >= minLines);
124
-
125
- if (passed) {
126
- return {
127
- passed: true,
128
- filesChanged: totalFiles,
129
- linesChanged: totalLines,
130
- files: allFiles,
131
- reason: "",
132
- retryStrategy: null
133
- };
134
- }
135
-
136
- return {
137
- passed: false,
138
- filesChanged: totalFiles,
139
- linesChanged: totalLines,
140
- files: allFiles,
141
- reason: totalFiles === 0
142
- ? "Coder produced 0 file changes"
143
- : `Only ${totalFiles} file(s) and ${totalLines} line(s) changed (below minimum)`,
144
- retryStrategy: buildRetryStrategy(totalFiles, totalLines)
145
- };
146
- }
147
-
148
- /**
149
- * Build a retry strategy based on the verification failure.
150
- */
151
- function buildRetryStrategy(filesChanged, _linesChanged) {
152
- if (filesChanged === 0) {
153
- return "Rephrase the feedback with explicit file paths. List specific files to create/modify. Include example code snippets.";
154
- }
155
- return "Expand the prompt with more specific instructions. Break the task into smaller concrete steps.";
156
- }
157
-
158
- /**
159
- * Track consecutive verification failures to detect stuck loops.
160
- */
161
- export class VerificationTracker {
162
- constructor() {
163
- this.consecutiveFailures = 0;
164
- this.history = [];
165
- }
166
-
167
- record(result) {
168
- this.history.push({ ...result, timestamp: Date.now() });
169
- if (result.passed) {
170
- this.consecutiveFailures = 0;
171
- } else {
172
- this.consecutiveFailures += 1;
173
- }
174
- }
175
-
176
- isStuck(threshold = 2) {
177
- return this.consecutiveFailures >= threshold;
178
- }
179
-
180
- getLastFailure() {
181
- return [...this.history].reverse().find(h => !h.passed) || null;
182
- }
183
- }
@@ -1,22 +0,0 @@
1
- /**
2
- * Orchestrator public API — thin barrel over the implementation in
3
- * src/orchestrator/flow-runner.js.
4
- *
5
- * Why this file is tiny: the 2 000-line monolith that used to live here was
6
- * extracted in KJC-TSK-0315 so that adding a new stage or routing rule no
7
- * longer requires touching a god-module. Consumers keep importing from
8
- * `src/orchestrator.js` — only the internal layout changed.
9
- *
10
- * See also:
11
- * - src/orchestrator/flow-runner.js — runFlow + resumeFlow internals
12
- * - src/orchestrator/stages/stage-executor.js — the StageExecutor contract
13
- * that individual stages can implement to register themselves with
14
- * StageRegistry.
15
- */
16
-
17
- export { runFlow, resumeFlow } from "./orchestrator/flow-runner.js";
18
- export { loadProductContext } from "./orchestrator/config-init.js";
19
- export {
20
- shouldAutoContinueCheckpoint,
21
- parseCheckpointAnswer
22
- } from "./orchestrator/flow-control.js";