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
@@ -0,0 +1,66 @@
1
+ /**
2
+ * KJC-TSK-1313: which card each worktree lane works on. Read from git every time, never stored on
3
+ * the card, so a lane removed by hand never lingers on the board.
4
+ */
5
+ import path from "node:path";
6
+
7
+ /**
8
+ * The worktrees with a branch in `git worktree list --porcelain`. The first entry is the main
9
+ * checkout and is left out, as are detached worktrees. With `root`, only the lanes under it.
10
+ * @returns {{slug: string, branch: string, path: string}[]}
11
+ */
12
+ export function parseLanes(porcelain, { root = null } = {}) {
13
+ const lanes = [];
14
+ let current = null;
15
+ let seen = 0;
16
+ for (const line of porcelain.split("\n")) {
17
+ if (line.startsWith("worktree ")) {
18
+ current = seen++ === 0 ? null : { path: line.slice(9).trim() };
19
+ } else if (line.startsWith("branch ") && current) {
20
+ lanes.push({ slug: path.basename(current.path), branch: line.slice(7).trim().replace(/^refs\/heads\//, ""), path: current.path });
21
+ }
22
+ }
23
+ return root ? lanes.filter((l) => l.path.startsWith(root + path.sep)) : lanes;
24
+ }
25
+
26
+ const escapeRe = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, String.raw`\$&`);
27
+
28
+ /**
29
+ * The lanes of each card: those whose branch carries the card id as a whole token (so HU-2 never
30
+ * claims HU-27). Cards without a lane have no entry.
31
+ * @returns {Map<string, {slug: string, branch: string, path: string}[]>}
32
+ */
33
+ export function lanesByCard(lanes, cardIds) {
34
+ const byCard = new Map();
35
+ for (const id of new Set(cardIds)) {
36
+ const token = new RegExp(`(^|[^a-z0-9])${escapeRe(id)}($|[^a-z0-9])`, "i");
37
+ const hits = lanes.filter((l) => token.test(l.branch));
38
+ if (hits.length > 0) byCard.set(id, hits);
39
+ }
40
+ return byCard;
41
+ }
42
+
43
+ /**
44
+ * The cards a lane works on: those whose id or any of whose references (a tracker card, an
45
+ * issue) its branch names. `cards` are `{id, refs}`.
46
+ * @returns {string[]}
47
+ */
48
+ /**
49
+ * KJC-TSK-1316: one PR per branch from `gh pr list --json number,url,state,headRefName`: an open
50
+ * one wins, else the newest (a merged lane is what KJC-TSK-1314 warns about).
51
+ * @returns {Map<string, {number: number, url: string, state: string}>}
52
+ */
53
+ export function prsByBranch(prs) {
54
+ const byBranch = new Map();
55
+ const open = (p) => (p.state === "OPEN" ? 1 : 0);
56
+ for (const p of prs) {
57
+ const cur = byBranch.get(p.headRefName);
58
+ if (!cur || open(p) > open(cur) || (open(p) === open(cur) && p.number > cur.number)) {
59
+ byBranch.set(p.headRefName, { number: p.number, url: p.url, state: p.state });
60
+ }
61
+ }
62
+ return byBranch;
63
+ }
64
+
65
+ export const cardsOfLane = (lane, cards) =>
66
+ cards.filter((c) => lanesByCard([lane], [c.id, ...c.refs]).size > 0).map((c) => c.id);
@@ -19,10 +19,11 @@ export async function writeTeamMirror(projectDir, rows, { repo }) {
19
19
  const plan = {
20
20
  version: 2, planId: MIRROR_PLAN_ID, name: "github", alias: "github", projectDir,
21
21
  task: `Shared HU Board: GitHub Issues of ${repo}`,
22
- status: "ready", readonly: "github", createdAt: now,
22
+ status: "ready", readonly: "github", repo, createdAt: now,
23
23
  hus: rows.map((r) => ({
24
24
  id: r.short_id, short_id: r.short_id, title: r.title, status: r.status,
25
- claimed_by: r.claimed_by ?? null, created_by: "github", external_ref: `${repo}#${r.number}`,
25
+ // KJC-BUG-0443: the tracker card it replicates too, so the gates find it by that reference.
26
+ claimed_by: r.claimed_by ?? null, created_by: "github", external_ref: [`${repo}#${r.number}`, r.ref].filter(Boolean).join(" · "),
26
27
  acceptance_criteria: [], acceptance_tests: [], createdAt: now, updatedAt: now,
27
28
  })),
28
29
  };
@@ -8,7 +8,7 @@
8
8
  *
9
9
  * This adapter preserves the runCommand API exactly, so current consumers
10
10
  * can opt-in to DI without behavioural changes. A matching MockCommandRunner
11
- * lives in src/infrastructure/mocks.js and lets tests script outputs per
11
+ * lives in tests/support/infrastructure-mocks.js and lets tests script outputs per
12
12
  * invocation.
13
13
  *
14
14
  * @typedef {Object} CommandRunResult
@@ -8,7 +8,7 @@
8
8
  * This adapter preserves the exact native API shapes for the handful of
9
9
  * operations actually used in the codebase, so consumers can opt-in to DI
10
10
  * without rewriting call sites. A matching MockFileSystem lives in
11
- * src/infrastructure/mocks.js.
11
+ * tests/support/infrastructure-mocks.js.
12
12
  *
13
13
  * Scope for TSK-0316: intentionally minimal. Only the operations already used
14
14
  * by orchestrator + agents. Additional methods added on demand.
@@ -1,6 +1,6 @@
1
1
  /**
2
- * Direct role handler logic (code, review, plan, audit, discover, triage, researcher, architect, impeccable).
3
- * Extracted from server-handlers.js for maintainability.
2
+ * Direct role handler logic (code, audit, discover). KJC-TSK-1318: review,
3
+ * plan, triage, researcher and architect left with the kj run pipeline.
4
4
  */
5
5
 
6
6
  import fs from "node:fs/promises";
@@ -8,12 +8,7 @@ import { resolveRole } from "../../config.js";
8
8
  import { createLogger } from "../../utils/logger.js";
9
9
  import { assertAgentsAvailable } from "../../agents/availability.js";
10
10
  import { createAgent } from "../../agents/index.js";
11
- import { buildPlannerPrompt } from "../../prompts/planner.js";
12
11
  import { buildCoderPrompt } from "../../prompts/coder.js";
13
- import { buildReviewerPrompt } from "../../prompts/reviewer.js";
14
- import { parseMaybeJsonString, agentAnswerText } from "../../review/parser.js";
15
- import { computeBaseRef, generateDiff } from "../../review/diff-generator.js";
16
- import { resolveReviewProfile } from "../../review/profiles.js";
17
12
  import { createRunLog } from "../../utils/run-log.js";
18
13
  import { createStallDetector } from "../../utils/stall-detector.js";
19
14
  import { sendTrackerLog } from "../progress.js";
@@ -66,165 +61,6 @@ function applySessionOverrides(a, roleKeys) {
66
61
  }
67
62
  }
68
63
 
69
- export async function handlePlanDirect(a, server, extra) {
70
- // KJC-PCS-0048 PR 3b: same `specReviewMode: skip` → skipSpecReview
71
- // mapping as kj_run. Default "auto" keeps the reviewer enabled.
72
- if (a.specReviewMode === "skip") a.skipSpecReview = true;
73
- const { normalizePlanArgs } = await import("../tool-arg-normalizers.js");
74
- const options = normalizePlanArgs(a);
75
- const config = await buildConfig(options, "plan");
76
- const logger = createLogger(config.output.log_level, "mcp");
77
-
78
- const plannerRole = resolveRole(config, "planner");
79
- await assertAgentsAvailable([plannerRole.provider]);
80
-
81
- const projectDir = await resolveProjectDir(server, a.projectDir);
82
- await ensureTaskFromFile(a, projectDir);
83
- const runLog = createRunLog(projectDir);
84
- const silenceTimeoutMs = Number(config?.session?.max_agent_silence_minutes) > 0
85
- ? Math.round(Number(config.session.max_agent_silence_minutes) * 60 * 1000)
86
- : undefined;
87
- const plannerTimeoutMs = Number(config?.session?.max_planner_minutes) > 0
88
- ? Math.round(Number(config.session.max_planner_minutes) * 60 * 1000)
89
- : undefined;
90
- const silenceLabel = silenceTimeoutMs ? `${Math.round(silenceTimeoutMs / 1000)}s` : "disabled";
91
- const runtimeLabel = plannerTimeoutMs ? `${Math.round(plannerTimeoutMs / 1000)}s` : "disabled";
92
- runLog.logText(
93
- `[kj_plan] started — provider=${plannerRole.provider}, max_silence=${silenceLabel}, max_runtime=${runtimeLabel}`
94
- );
95
- const emitter = buildDirectEmitter(server, runLog, extra);
96
- const eventBase = { sessionId: null, iteration: 0, startedAt: Date.now() };
97
-
98
- // --- Phase 1: Researcher (codebase context) ---
99
- let researchContext = null;
100
- try {
101
- const { ResearcherRole } = await import("../../roles/researcher-role.js");
102
- const researcherRole = resolveRole(config, "researcher");
103
- const researcherOnOutput = ({ stream, line }) => {
104
- emitter.emit("progress", { type: "agent:output", stage: "researcher", message: line, detail: { stream, agent: researcherRole.provider } });
105
- };
106
- const researcherStall = createStallDetector({
107
- onOutput: researcherOnOutput, emitter, eventBase, stage: "researcher", provider: researcherRole.provider
108
- });
109
-
110
- sendTrackerLog(server, "researcher", "running", researcherRole.provider);
111
- runLog.logText(`[researcher] agent launched for plan context...`);
112
- const researcher = new ResearcherRole({ config, logger, emitter });
113
- await researcher.init({ task: a.task });
114
- let researchOutput;
115
- try {
116
- researchOutput = await researcher.run({ task: a.task, onOutput: researcherStall.onOutput });
117
- } finally {
118
- researcherStall.stop();
119
- }
120
- if (researchOutput.ok) {
121
- researchContext = researchOutput.result;
122
- sendTrackerLog(server, "researcher", "done");
123
- runLog.logText(`[researcher] completed — context available`);
124
- } else {
125
- sendTrackerLog(server, "researcher", "failed");
126
- runLog.logText(`[researcher] failed: ${researchOutput.summary || "unknown"}`);
127
- }
128
- } catch (err) {
129
- logger.warn(`Researcher phase skipped: ${err.message}`);
130
- }
131
-
132
- // --- Phase 2: Architect (solution design) ---
133
- let architectContext = null;
134
- try {
135
- const { ArchitectRole } = await import("../../roles/architect-role.js");
136
- const architectRole = resolveRole(config, "architect");
137
- const architectOnOutput = ({ stream, line }) => {
138
- emitter.emit("progress", { type: "agent:output", stage: "architect", message: line, detail: { stream, agent: architectRole.provider } });
139
- };
140
- const architectStall = createStallDetector({
141
- onOutput: architectOnOutput, emitter, eventBase, stage: "architect", provider: architectRole.provider
142
- });
143
-
144
- sendTrackerLog(server, "architect", "running", architectRole.provider);
145
- runLog.logText(`[architect] agent launched for plan context...`);
146
- const architect = new ArchitectRole({ config, logger, emitter });
147
- await architect.init({ task: a.task });
148
- let architectOutput;
149
- try {
150
- architectOutput = await architect.run({ task: a.task, researchContext, onOutput: architectStall.onOutput });
151
- } finally {
152
- architectStall.stop();
153
- }
154
- if (architectOutput.ok) {
155
- architectContext = architectOutput.result;
156
- sendTrackerLog(server, "architect", "done");
157
- runLog.logText(`[architect] completed — context available`);
158
- } else {
159
- sendTrackerLog(server, "architect", "failed");
160
- runLog.logText(`[architect] failed: ${architectOutput.summary || "unknown"}`);
161
- }
162
- } catch (err) {
163
- logger.warn(`Architect phase skipped: ${err.message}`);
164
- }
165
-
166
- // --- Phase 3: Planner (with research + architecture context) ---
167
- const onOutput = ({ stream, line }) => {
168
- emitter.emit("progress", { type: "agent:output", stage: "planner", message: line, detail: { stream, agent: plannerRole.provider } });
169
- };
170
- const stallDetector = createStallDetector({
171
- onOutput, emitter, eventBase, stage: "planner", provider: plannerRole.provider
172
- });
173
-
174
- const planner = createAgent(plannerRole.provider, config, logger);
175
- const prompt = buildPlannerPrompt({ task: a.task, context: a.context, architectContext });
176
- sendTrackerLog(server, "planner", "running", plannerRole.provider);
177
- runLog.logText(`[planner] agent launched, waiting for response...`);
178
- let result;
179
- let plannerStats;
180
- try {
181
- result = await planner.runTask({
182
- prompt,
183
- role: "planner",
184
- onOutput: stallDetector.onOutput,
185
- silenceTimeoutMs,
186
- timeoutMs: plannerTimeoutMs
187
- });
188
- } finally {
189
- stallDetector.stop();
190
- plannerStats = stallDetector.stats();
191
- runLog.logText(
192
- `[planner] finished — lines=${plannerStats.lineCount}, bytes=${plannerStats.bytesReceived}, elapsed=${Math.round(plannerStats.elapsedMs / 1000)}s`
193
- );
194
- runLog.close();
195
- }
196
-
197
- if (!result.ok) {
198
- sendTrackerLog(server, "planner", "failed");
199
- const baseError = result.error || result.output || "Planner failed";
200
- const statsSuffix = plannerStats
201
- ? ` [lines=${plannerStats.lineCount}, bytes=${plannerStats.bytesReceived}, elapsed=${Math.round(plannerStats.elapsedMs / 1000)}s]`
202
- : "";
203
- throw new Error(`${baseError}${statsSuffix}`);
204
- }
205
-
206
- sendTrackerLog(server, "planner", "done");
207
- const parsed = parseMaybeJsonString(result.output);
208
-
209
- // --- Persist plan ---
210
- let planId = null;
211
- try {
212
- const { savePlan } = await import("../../plan/plan-store.js");
213
- planId = await savePlan(projectDir, {
214
- task: a.task,
215
- researchContext,
216
- architectContext,
217
- plan: parsed || result.output,
218
- raw: result.output
219
- });
220
- runLog.logText(`[kj_plan] plan persisted — planId=${planId}`);
221
- } catch (err) {
222
- logger.warn(`Plan persistence failed (non-blocking): ${err.message}`);
223
- }
224
-
225
- return { ok: true, plan: parsed || result.output, raw: result.output, planId, researchContext, architectContext };
226
- }
227
-
228
64
  export async function handleCodeDirect(a, server, extra) {
229
65
  const config = await buildConfig(a, "code");
230
66
  await assertNotOnBaseBranch(config);
@@ -277,55 +113,6 @@ export async function handleCodeDirect(a, server, extra) {
277
113
  return { ok: true, output: result.output, exitCode: result.exitCode };
278
114
  }
279
115
 
280
- export async function handleReviewDirect(a, server, extra) {
281
- const config = await buildConfig(a, "review");
282
- await assertNotOnBaseBranch(config);
283
- const logger = createLogger(config.output.log_level, "mcp");
284
-
285
- const reviewerRole = resolveRole(config, "reviewer");
286
- await assertAgentsAvailable([reviewerRole.provider]);
287
-
288
- const projectDir = await resolveProjectDir(server, a.projectDir);
289
- await ensureTaskFromFile(a, projectDir);
290
- const runLog = createRunLog(projectDir);
291
- runLog.logText(`[kj_review] started — provider=${reviewerRole.provider}`);
292
- const emitter = buildDirectEmitter(server, runLog, extra);
293
- const eventBase = { sessionId: null, iteration: 0, startedAt: Date.now() };
294
- const onOutput = ({ stream, line }) => {
295
- emitter.emit("progress", { type: "agent:output", stage: "reviewer", message: line, detail: { stream, agent: reviewerRole.provider } });
296
- };
297
- const stallDetector = createStallDetector({
298
- onOutput, emitter, eventBase, stage: "reviewer", provider: reviewerRole.provider
299
- });
300
-
301
- const reviewer = createAgent(reviewerRole.provider, config, logger);
302
- const resolvedBase = await computeBaseRef({ baseBranch: config.base_branch, baseRef: a.baseRef });
303
- const diff = await generateDiff({ baseRef: resolvedBase });
304
- const { rules } = await resolveReviewProfile({ mode: config.review_mode, projectDir: process.cwd() });
305
-
306
- const prompt = await buildReviewerPrompt({ task: a.task, diff, reviewRules: rules, mode: config.review_mode });
307
- sendTrackerLog(server, "reviewer", "running", reviewerRole.provider);
308
- runLog.logText(`[reviewer] agent launched, waiting for response...`);
309
- let result;
310
- try {
311
- result = await reviewer.reviewTask({ prompt, role: "reviewer", onOutput: stallDetector.onOutput });
312
- } finally {
313
- stallDetector.stop();
314
- const stats = stallDetector.stats();
315
- runLog.logText(`[reviewer] finished — lines=${stats.lineCount}, bytes=${stats.bytesReceived}, elapsed=${Math.round(stats.elapsedMs / 1000)}s`);
316
- runLog.close();
317
- }
318
-
319
- if (!result.ok) {
320
- sendTrackerLog(server, "reviewer", "failed");
321
- throw new Error(result.error || result.output || `Reviewer failed (exit ${result.exitCode})`);
322
- }
323
-
324
- sendTrackerLog(server, "reviewer", "done");
325
- const parsed = parseMaybeJsonString(agentAnswerText(result.output));
326
- return { ok: true, review: parsed || result.output, raw: result.output };
327
- }
328
-
329
116
  export async function handleDiscoverDirect(a, server, extra) {
330
117
  // Build context from pgTask if provided
331
118
  let context = a.context || null;
@@ -350,34 +137,6 @@ export async function handleDiscoverDirect(a, server, extra) {
350
137
  });
351
138
  }
352
139
 
353
- export async function handleTriageDirect(a, server, extra) {
354
- return runDirectRole({
355
- roleName: "triage",
356
- importRole: async () => {
357
- const { TriageRole } = await import("../../roles/triage-role.js");
358
- return { RoleClass: TriageRole };
359
- },
360
- initContext: { task: a.task },
361
- runInput: { task: a.task },
362
- args: a, server, extra,
363
- resolveProjectDir, buildConfig, buildDirectEmitter
364
- });
365
- }
366
-
367
- export async function handleResearcherDirect(a, server, extra) {
368
- return runDirectRole({
369
- roleName: "researcher",
370
- importRole: async () => {
371
- const { ResearcherRole } = await import("../../roles/researcher-role.js");
372
- return { RoleClass: ResearcherRole };
373
- },
374
- initContext: { task: a.task },
375
- runInput: { task: a.task },
376
- args: a, server, extra,
377
- resolveProjectDir, buildConfig, buildDirectEmitter
378
- });
379
- }
380
-
381
140
  export async function handleAuditDirect(a, server, extra) {
382
141
  const task = a.task || "Analyze the full codebase";
383
142
  return runDirectRole({
@@ -394,20 +153,6 @@ export async function handleAuditDirect(a, server, extra) {
394
153
  });
395
154
  }
396
155
 
397
- export async function handleArchitectDirect(a, server, extra) {
398
- return runDirectRole({
399
- roleName: "architect",
400
- importRole: async () => {
401
- const { ArchitectRole } = await import("../../roles/architect-role.js");
402
- return { RoleClass: ArchitectRole };
403
- },
404
- initContext: { task: a.task },
405
- runInput: { task: a.task, researchContext: a.context || null },
406
- args: a, server, extra,
407
- resolveProjectDir, buildConfig, buildDirectEmitter
408
- });
409
- }
410
-
411
156
  export async function handleCode(a, server, extra) {
412
157
  const missingTask = await requireTask(a, server);
413
158
  if (missingTask) return missingTask;
@@ -422,20 +167,6 @@ export async function handleCode(a, server, extra) {
422
167
  return handleCodeDirect(a, server, extra);
423
168
  }
424
169
 
425
- export async function handleReview(a, server, extra) {
426
- const missingTask = await requireTask(a, server);
427
- if (missingTask) return missingTask;
428
- await runBootstrapGate(server, a);
429
- return handleReviewDirect(a, server, extra);
430
- }
431
-
432
- export async function handlePlan(a, server, extra) {
433
- const missingTask = await requireTask(a, server);
434
- if (missingTask) return missingTask;
435
- await runBootstrapGate(server, a);
436
- return handlePlanDirect(a, server, extra);
437
- }
438
-
439
170
  export async function handleDiscover(a, server, extra) {
440
171
  const missingTask = await requireTask(a, server);
441
172
  if (missingTask) return missingTask;
@@ -447,27 +178,6 @@ export async function handleDiscover(a, server, extra) {
447
178
  return handleDiscoverDirect(a, server, extra);
448
179
  }
449
180
 
450
- export async function handleTriage(a, server, extra) {
451
- const missingTask = await requireTask(a, server);
452
- if (missingTask) return missingTask;
453
- await runBootstrapGate(server, a);
454
- return handleTriageDirect(a, server, extra);
455
- }
456
-
457
- export async function handleResearcher(a, server, extra) {
458
- const missingTask = await requireTask(a, server);
459
- if (missingTask) return missingTask;
460
- await runBootstrapGate(server, a);
461
- return handleResearcherDirect(a, server, extra);
462
- }
463
-
464
- export async function handleArchitect(a, server, extra) {
465
- const missingTask = await requireTask(a, server);
466
- if (missingTask) return missingTask;
467
- await runBootstrapGate(server, a);
468
- return handleArchitectDirect(a, server, extra);
469
- }
470
-
471
181
  export async function handleAudit(a, server, extra) {
472
182
  await runBootstrapGate(server, a);
473
183
  const result = await handleAuditDirect(a, server, extra);
@@ -1,5 +1,5 @@
1
1
  /**
2
- * HU, Skills, and Suggest handler logic.
2
+ * HU and Suggest handler logic (skills moved to `atril mcp`, ADR 0021).
3
3
  * Extracted from server-handlers.js for maintainability.
4
4
  */
5
5
 
@@ -70,40 +70,6 @@ export async function handleHu(a, server) {
70
70
  }
71
71
  }
72
72
 
73
- export async function handleSkills(a) {
74
- const action = a.action;
75
- if (!action) return failPayload("Missing required field: action");
76
-
77
- const { isOpenSkillsAvailable, installSkill, removeSkill, listSkills, readSkill } =
78
- await import("../../skills/openskills-client.js");
79
-
80
- const opts = { projectDir: a.projectDir || null };
81
-
82
- switch (action) {
83
- case "install": {
84
- if (!a.source) return failPayload("Missing required field: source (required for install)");
85
- const available = await isOpenSkillsAvailable();
86
- if (!available) {
87
- return failPayload("OpenSkills CLI is not available. Install it with: npm install -g openskills");
88
- }
89
- return installSkill(a.source, { ...opts, global: a.global || false });
90
- }
91
- case "remove": {
92
- if (!a.name) return failPayload("Missing required field: name (required for remove)");
93
- return removeSkill(a.name, opts);
94
- }
95
- case "list": {
96
- return listSkills(opts);
97
- }
98
- case "read": {
99
- if (!a.name) return failPayload("Missing required field: name (required for read)");
100
- return readSkill(a.name, opts);
101
- }
102
- default:
103
- return failPayload(`Unknown skills action: ${action}`);
104
- }
105
- }
106
-
107
73
  export async function handleSuggest(a) {
108
74
  if (!a.suggestion) {
109
75
  return failPayload("Missing required field: suggestion");
@@ -1,11 +1,10 @@
1
1
  /**
2
- * Management handler logic (init, doctor, config, scan, report, roles, agents, preflight, status, board).
3
- * Extracted from server-handlers.js for maintainability.
2
+ * Management handler logic (init, doctor, config, scan, report, roles, agents, preflight, board, clean).
3
+ * KJC-TSK-1318: status and undo left with the kj run pipeline.
4
4
  */
5
5
 
6
6
  import { runKjCommand } from "../run-kj.js";
7
7
  import { loadConfig } from "../../config.js";
8
- import { readRunLog } from "../../utils/run-log.js";
9
8
  import { ackPreflight, getSessionOverrides } from "../preflight.js";
10
9
  import { ensureBootstrap } from "../../bootstrap.js";
11
10
  import {
@@ -14,8 +13,6 @@ import {
14
13
  responseText,
15
14
  buildConfig,
16
15
  } from "../shared-helpers.js";
17
- import { buildDashboardJson } from "../../utils/status-dashboard.js";
18
- import { loadMostRecentSession } from "../../session/store.js";
19
16
  import { escapeRegExp } from "../../utils/escape-regexp.js";
20
17
 
21
18
  const AGENT_ROLES = new Set(["coder", "reviewer", "tester", "security", "solomon"]);
@@ -29,31 +26,6 @@ async function runBootstrapGate(server, a) {
29
26
  await ensureBootstrap(projectDir, config);
30
27
  }
31
28
 
32
- export async function handleStatus(a, server) {
33
- const maxLines = a.lines || 50;
34
- const projectDir = await resolveProjectDir(server, a.projectDir);
35
- const logResult = readRunLog(projectDir, maxLines);
36
-
37
- // Enrich with dashboard data when possible
38
- try {
39
- const session = await loadMostRecentSession();
40
- const stories = [];
41
- if (session) {
42
- try {
43
- const { loadHuBatch } = await import("../../hu/store.js");
44
- const batch = await loadHuBatch(session.id);
45
- if (batch?.stories) stories.push(...batch.stories);
46
- } catch { /* no HU batch for this session */ }
47
- }
48
-
49
- const dashboard = buildDashboardJson(session, logResult.lines || [], { stories });
50
- return { ...logResult, dashboard };
51
- } catch {
52
- // Fallback: return raw log without dashboard
53
- return logResult;
54
- }
55
- }
56
-
57
29
  export async function handleAgents(a) {
58
30
  const action = a.action || "list";
59
31
  if (action === "set") {
@@ -190,18 +162,6 @@ export async function handleBoard(a) {
190
162
  }
191
163
  }
192
164
 
193
- export async function handleUndo(a, server) {
194
- const projectDir = await resolveProjectDir(server, a.projectDir);
195
- const origCwd = process.cwd();
196
- try {
197
- process.chdir(projectDir);
198
- const { undoCommand } = await import("../../commands/undo.js");
199
- return undoCommand({ hard: !!a.hard });
200
- } finally {
201
- process.chdir(origCwd);
202
- }
203
- }
204
-
205
165
  /**
206
166
  * Garbage-collect stale Karajan state. Routed here (not through the
207
167
  * generic `runKjCommand`) because the user needs a structured result
@@ -10,6 +10,7 @@ import { indexProject } from "../../rag/indexer.js";
10
10
  import { ragExclude } from "../../rag/indexable.js";
11
11
  import { query } from "../../rag/retriever.js";
12
12
  import { pathNamedHits, withPathNamedHits } from "../../rag/path-hits.js";
13
+ import { claimLease, indexLeasePath, releaseLease } from "../../rag/pid-lease.js";
13
14
  import { getKarajanHome } from "../../utils/paths.js";
14
15
  import { resolveProjectDir, buildConfig, responseText, failPayload } from "../shared-helpers.js";
15
16
 
@@ -56,7 +57,11 @@ export async function handleRagIndex(args, server) {
56
57
  const projectDir = await resolveProjectDir(server, args?.projectDir);
57
58
  const config = await buildConfig({ ...args, projectDir }, "rag-index");
58
59
  const db = openProjectStore({ projectDir, dim: config?.rag?.embedder?.dim || 768 });
60
+ // HU-2907: the long-lived host holds the machine lease for the walk and releases it in the finally.
61
+ const lease = indexLeasePath();
62
+ let claim;
59
63
  try {
64
+ claim = claimLease(lease, { projectDir, slug: projectSlug(projectDir) });
60
65
  const totals = await indexProject(projectDir, {
61
66
  db, embedder: makeGovernedEmbedder(config),
62
67
  karajanHome: getKarajanHome(), logger: silentLogger,
@@ -64,7 +69,10 @@ export async function handleRagIndex(args, server) {
64
69
  exclude: ragExclude(config), // KJC-TSK-0891
65
70
  });
66
71
  return responseText(totals);
67
- } finally { db.close(); }
72
+ } finally {
73
+ if (claim?.claimed) releaseLease(lease);
74
+ db.close();
75
+ }
68
76
  } catch (err) {
69
77
  return failPayload(`kj_rag_index failed: ${err.message}`);
70
78
  }
@@ -20,32 +20,35 @@ export {
20
20
  } from "./shared-helpers.js";
21
21
 
22
22
  // ── Sub-module re-exports ────────────────────────────────────────────
23
- export { handleRunDirect, handleResumeDirect, validateResumeAnswer, handleRun, handleResume } from "./handlers/run-handler.js";
24
- export { handlePlanDirect, handleCodeDirect, handleReviewDirect, handleDiscoverDirect, handleTriageDirect, handleResearcherDirect, handleAuditDirect, handleArchitectDirect, handleCode, handleReview, handlePlan, handleDiscover, handleTriage, handleResearcher, handleArchitect, handleAudit } from "./handlers/direct-handlers.js";
25
- export { handleStatus, handleAgents, handlePreflight, handleRoles, handleReport, handleInit, handleDoctor, handleConfig, handleScan, handleBoard, handleUndo, handleClean, buildPreflightRequiredResponse } from "./handlers/management-handlers.js";
26
- export { handleHu, handleSkills, handleSuggest } from "./handlers/hu-handlers.js";
23
+ export { handleCodeDirect, handleDiscoverDirect, handleAuditDirect, handleCode, handleDiscover, handleAudit } from "./handlers/direct-handlers.js";
24
+ export { handleAgents, handlePreflight, handleRoles, handleReport, handleInit, handleDoctor, handleConfig, handleScan, handleBoard, handleClean, buildPreflightRequiredResponse } from "./handlers/management-handlers.js";
25
+ export { handleHu, handleSuggest } from "./handlers/hu-handlers.js";
27
26
 
28
27
  // ── Handler dispatch ─────────────────────────────────────────────────
29
28
 
30
29
  import { asObject, failPayload } from "./shared-helpers.js";
31
- import { handleRun, handleResume } from "./handlers/run-handler.js";
30
+ import { handleCode, handleDiscover, handleAudit } from "./handlers/direct-handlers.js";
32
31
  import {
33
- handleCode, handleReview, handlePlan, handleDiscover,
34
- handleTriage, handleResearcher, handleArchitect, handleAudit
35
- } from "./handlers/direct-handlers.js";
36
- import {
37
- handleStatus, handleAgents, handlePreflight, handleRoles,
32
+ handleAgents, handlePreflight, handleRoles,
38
33
  handleReport, handleInit, handleDoctor, handleConfig,
39
- handleScan, handleBoard, handleUndo, handleClean
34
+ handleScan, handleBoard, handleClean
40
35
  } from "./handlers/management-handlers.js";
41
- import { handleHu, handleSkills, handleSuggest } from "./handlers/hu-handlers.js";
36
+ import { retiredMessage } from "../cli/retired-commands.js";
37
+
38
+ // KJC-TSK-1318: the tools of the kj run pipeline, retired in 5.0 with their
39
+ // commands; a call answers with the same notice and starts nothing.
40
+ const RETIRED_TOOLS = {
41
+ kj_run: "run", kj_resume: "resume", kj_plan: "plan generate", kj_status: "status", kj_undo: "undo",
42
+ kj_triage: "triage", kj_researcher: "researcher", kj_architect: "architect", kj_review: "review",
43
+ };
44
+ import { handleHu, handleSuggest } from "./handlers/hu-handlers.js";
42
45
  import { handleRagQuery, handleRagIndex } from "./handlers/rag-handler.js";
43
46
  import { withKarajanHome } from "../utils/paths.js";
44
47
 
45
48
  export async function handleToolCall(name, args, server, extra) {
49
+ if (Object.hasOwn(RETIRED_TOOLS, name)) return failPayload(retiredMessage(RETIRED_TOOLS[name]));
46
50
  const a = asObject(args);
47
51
  const handler = {
48
- kj_status: (a, server) => handleStatus(a, server),
49
52
  kj_init: (a) => handleInit(a),
50
53
  kj_doctor: (a) => handleDoctor(a),
51
54
  kj_agents: (a) => handleAgents(a),
@@ -54,21 +57,12 @@ export async function handleToolCall(name, args, server, extra) {
54
57
  kj_scan: (a, server) => handleScan(a, server),
55
58
  kj_roles: (a) => handleRoles(a),
56
59
  kj_report: (a) => handleReport(a),
57
- kj_resume: (a, server, extra) => handleResume(a, server, extra),
58
- kj_run: (a, server, extra) => handleRun(a, server, extra),
59
60
  kj_code: (a, server, extra) => handleCode(a, server, extra),
60
- kj_review: (a, server, extra) => handleReview(a, server, extra),
61
- kj_plan: (a, server, extra) => handlePlan(a, server, extra),
62
61
  kj_discover: (a, server, extra) => handleDiscover(a, server, extra),
63
- kj_triage: (a, server, extra) => handleTriage(a, server, extra),
64
- kj_researcher: (a, server, extra) => handleResearcher(a, server, extra),
65
- kj_architect: (a, server, extra) => handleArchitect(a, server, extra),
66
62
  kj_audit: (a, server, extra) => handleAudit(a, server, extra),
67
63
  kj_board: (a) => handleBoard(a),
68
64
  kj_hu: (a, server) => handleHu(a, server),
69
65
  kj_suggest: (a) => handleSuggest(a),
70
- kj_skills: (a) => handleSkills(a),
71
- kj_undo: (a, server) => handleUndo(a, server),
72
66
  kj_clean: (a) => handleClean(a),
73
67
  kj_rag_query: (a, server) => handleRagQuery(a, server),
74
68
  kj_rag_index: (a, server) => handleRagIndex(a, server),