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