karajan-code 4.70.4 → 5.0.1

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