karajan-code 4.70.3 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (388) hide show
  1. package/README.md +2 -2
  2. package/package.json +6 -14
  3. package/packages/hu-board/package.json +1 -1
  4. package/packages/hu-board/public/app.js +4 -18
  5. package/packages/hu-board/public/index.html +5 -2
  6. package/packages/hu-board/public/styles.css +26 -0
  7. package/packages/hu-board/public/utils/api.js +0 -74
  8. package/packages/hu-board/public/utils/board-tour.js +62 -0
  9. package/packages/hu-board/public/utils/board-view.js +49 -144
  10. package/packages/hu-board/public/utils/command-launcher.js +8 -70
  11. package/packages/hu-board/public/utils/formatters.js +10 -0
  12. package/packages/hu-board/public/utils/governance-view.js +13 -1
  13. package/packages/hu-board/public/utils/hu-actions.js +17 -68
  14. package/packages/hu-board/public/utils/init-listeners.js +7 -8
  15. package/packages/hu-board/public/utils/log-panel.js +3 -16
  16. package/packages/hu-board/public/utils/maggle-mode.js +2 -12
  17. package/packages/hu-board/public/utils/modals.js +7 -0
  18. package/packages/hu-board/public/utils/project-picker-view.js +1 -1
  19. package/packages/hu-board/public/utils/server-push.js +3 -22
  20. package/packages/hu-board/public/utils/shared-board-notice.js +33 -0
  21. package/packages/hu-board/public/utils/story-detail-view.js +5 -19
  22. package/packages/hu-board/src/cleanup-zombies.js +0 -1
  23. package/packages/hu-board/src/command-runner.js +36 -25
  24. package/packages/hu-board/src/db-connection.js +282 -0
  25. package/packages/hu-board/src/db-paths.js +113 -0
  26. package/packages/hu-board/src/db-queries.js +188 -0
  27. package/packages/hu-board/src/db-tombstones.js +51 -0
  28. package/packages/hu-board/src/db.js +28 -619
  29. package/packages/hu-board/src/ephemeral-cleaner.js +2 -3
  30. package/packages/hu-board/src/hu-zombie-reaper.js +5 -1
  31. package/packages/hu-board/src/plan-mutations.js +3 -153
  32. package/packages/hu-board/src/plans-service.js +55 -0
  33. package/packages/hu-board/src/routes/api/commands.js +122 -0
  34. package/packages/hu-board/src/routes/api/plans.js +55 -0
  35. package/packages/hu-board/src/routes/api/projects.js +267 -0
  36. package/packages/hu-board/src/routes/api/prompts.js +135 -0
  37. package/packages/hu-board/src/routes/api/sessions.js +95 -0
  38. package/packages/hu-board/src/routes/api/stories.js +183 -0
  39. package/packages/hu-board/src/routes/api/system.js +241 -0
  40. package/packages/hu-board/src/routes/api/tombstones.js +38 -0
  41. package/packages/hu-board/src/routes/api.js +24 -1371
  42. package/packages/hu-board/src/routes/governance.js +23 -1
  43. package/packages/hu-board/src/routes/lanes.js +40 -0
  44. package/packages/hu-board/src/routes/rag.js +4 -3
  45. package/packages/hu-board/src/server.js +20 -34
  46. package/packages/hu-board/src/sync-files.js +318 -0
  47. package/packages/hu-board/src/sync-project.js +99 -0
  48. package/packages/hu-board/src/sync.js +22 -566
  49. package/packages/hu-board/src/zombie-reaper.js +1 -1
  50. package/scripts/dual-publish.mjs +19 -3
  51. package/scripts/postinstall.js +15 -2
  52. package/scripts/verify-pack-mcp.mjs +11 -7
  53. package/scripts/verify-pack.mjs +4 -4
  54. package/src/audit/audit-history.js +3 -2
  55. package/src/audit/dead-exports.js +68 -59
  56. package/src/audit/deterministic-summary.js +33 -13
  57. package/src/audit/npm-signatures.js +41 -0
  58. package/src/audit/sbom.js +35 -0
  59. package/src/checks/agent-token.js +112 -0
  60. package/src/checks/ai-surface.js +9 -7
  61. package/src/checks/config-files.js +8 -7
  62. package/src/checks/dir-setup.js +34 -1
  63. package/src/checks/native-build.js +21 -39
  64. package/src/checks/runner.js +128 -142
  65. package/src/cli/advanced-commands.js +6 -6
  66. package/src/cli/register-meta.js +42 -82
  67. package/src/cli/register-pipeline.js +8 -140
  68. package/src/cli/register-plan.js +9 -100
  69. package/src/cli/retired-commands.js +49 -0
  70. package/src/cli.js +18 -5
  71. package/src/commands/agent-run.js +40 -26
  72. package/src/commands/audit.js +127 -124
  73. package/src/commands/board.js +5 -9
  74. package/src/commands/check.js +29 -16
  75. package/src/commands/doctor.js +2 -0
  76. package/src/commands/env.js +176 -148
  77. package/src/commands/go.js +76 -55
  78. package/src/commands/harden.js +105 -86
  79. package/src/commands/hu-start.js +52 -0
  80. package/src/commands/hu.js +288 -221
  81. package/src/commands/identity.js +111 -78
  82. package/src/commands/init-atril.js +47 -0
  83. package/src/commands/init.js +11 -40
  84. package/src/commands/install-tools.js +70 -85
  85. package/src/commands/main-guard.js +78 -0
  86. package/src/commands/policy.js +226 -184
  87. package/src/commands/qmd.js +27 -21
  88. package/src/commands/rag.js +75 -48
  89. package/src/commands/review-gate.js +422 -339
  90. package/src/commands/start.js +4 -5
  91. package/src/commands/steward.js +96 -47
  92. package/src/commands/tournament.js +46 -37
  93. package/src/commands/worktree.js +94 -25
  94. package/src/config/loader.js +34 -17
  95. package/src/config/overrides.js +2 -1
  96. package/src/config/secrets.js +36 -0
  97. package/src/config.js +1 -0
  98. package/src/environment/adr.js +16 -2
  99. package/src/environment/board-access.js +11 -9
  100. package/src/git/karajan-label.js +20 -8
  101. package/src/guards/main-guard.js +54 -0
  102. package/src/harden/branch-protection.js +36 -3
  103. package/src/harden/hook-templates.js +16 -1
  104. package/src/harden/sentinel/posttooluse.mjs +18 -6
  105. package/src/harden/sentinel/pretooluse-sentinel.mjs +81 -35
  106. package/src/harden/sentinel/sentinel-lib.mjs +149 -23
  107. package/src/harden/sentinel/sentinel-shell.mjs +64 -0
  108. package/src/harden/sentinel/sessionstart.mjs +3 -2
  109. package/src/harden/sentinel/stop.mjs +5 -4
  110. package/src/harden/workflow-engine.js +12 -1
  111. package/src/harden/workflow-templates.js +1 -1
  112. package/src/hu/board-lookup.js +29 -0
  113. package/src/hu/gh-identity.js +23 -0
  114. package/src/hu/github-board.js +4 -2
  115. package/src/hu/lane-prune.js +15 -7
  116. package/src/hu/lane-setup.js +65 -0
  117. package/src/hu/lanes.js +66 -0
  118. package/src/hu/team-board-mirror.js +3 -2
  119. package/src/infrastructure/command-runner.js +1 -1
  120. package/src/infrastructure/file-system-service.js +1 -1
  121. package/src/mcp/handlers/direct-handlers.js +2 -292
  122. package/src/mcp/handlers/hu-handlers.js +44 -55
  123. package/src/mcp/handlers/management-handlers.js +2 -42
  124. package/src/mcp/server-handlers.js +16 -22
  125. package/src/mcp/tools.js +5 -200
  126. package/src/plan/lane-plans.js +54 -0
  127. package/src/plan/plan-store.js +7 -4
  128. package/src/policy/add.js +26 -12
  129. package/src/policy/adr-number-check.js +31 -0
  130. package/src/prompts/audit.js +299 -339
  131. package/src/prompts/card-context.js +10 -5
  132. package/src/prompts/reviewer.js +5 -2
  133. package/src/rag/auto-update.js +56 -43
  134. package/src/rag/bootstrap-index.js +28 -54
  135. package/src/rag/migrate.js +1 -1
  136. package/src/rag/onnx-fallback.js +2 -2
  137. package/src/rag/pid-lease.js +70 -0
  138. package/src/rag/project-store.js +2 -12
  139. package/src/review/card-first.js +57 -46
  140. package/src/review/dual-review.js +5 -4
  141. package/src/review/gate-gitignore.js +23 -4
  142. package/src/review/gate-hook.js +47 -0
  143. package/src/review/one-shot-review.js +51 -37
  144. package/src/review/publish-pr.js +18 -3
  145. package/src/review/repo-docs.js +73 -0
  146. package/src/review/repo-stack.js +59 -0
  147. package/src/review/reviewer-fallback.js +34 -3
  148. package/src/review/seal-commit.js +29 -0
  149. package/src/review/sonar-pregate.js +59 -44
  150. package/src/review/third-party-review.js +90 -16
  151. package/src/review/third-party-size.js +43 -0
  152. package/src/review/third-party-skills.js +54 -0
  153. package/src/review/verify-pr.js +2 -26
  154. package/src/roles/audit-role.js +106 -125
  155. package/src/skills/atril-skills.js +5 -4
  156. package/src/sonar/scanner.js +116 -101
  157. package/src/steward/invariants.js +5 -4
  158. package/src/steward/phantom-sweep.js +66 -0
  159. package/src/tournament/judge.js +60 -53
  160. package/src/utils/agent-home.js +33 -0
  161. package/src/utils/gh-account.js +37 -0
  162. package/src/utils/git.js +0 -13
  163. package/src/utils/home-migration.js +7 -1
  164. package/src/utils/main-checkout.js +53 -0
  165. package/src/utils/qmd-collection.js +3 -1
  166. package/src/utils/welcome.js +3 -3
  167. package/templates/{skills → atril/commands}/kj-architect.md +5 -0
  168. package/templates/{skills → atril/commands}/kj-audit.md +5 -0
  169. package/templates/{skills → atril/commands}/kj-board.md +5 -0
  170. package/templates/{skills → atril/commands}/kj-code.md +5 -0
  171. package/templates/{skills → atril/commands}/kj-csv-transform.md +5 -0
  172. package/templates/{skills → atril/commands}/kj-data-report.md +5 -0
  173. package/templates/{skills → atril/commands}/kj-discover.md +5 -0
  174. package/templates/{skills → atril/commands}/kj-rag-query.md +5 -0
  175. package/templates/{skills → atril/commands}/kj-review.md +5 -0
  176. package/templates/{skills → atril/commands}/kj-security.md +5 -0
  177. package/templates/{skills → atril/commands}/kj-sonar.md +5 -0
  178. package/templates/{skills → atril/commands}/kj-sql-analysis.md +5 -0
  179. package/templates/{skills → atril/commands}/kj-test.md +5 -0
  180. package/packages/hu-board/public/utils/run-launcher.js +0 -169
  181. package/packages/hu-board/src/run-tracker.js +0 -121
  182. package/src/activity-log.js +0 -59
  183. package/src/agents/host-agent.js +0 -38
  184. package/src/agents/model-registry.js +0 -142
  185. package/src/audit/plan-adherence.js +0 -224
  186. package/src/autonomy/arbiter-role.js +0 -71
  187. package/src/autonomy/arbiter.js +0 -22
  188. package/src/autonomy/decider.js +0 -18
  189. package/src/autonomy/decision-resolver.js +0 -58
  190. package/src/autonomy/outcome-report.js +0 -55
  191. package/src/autonomy/stage-ask.js +0 -30
  192. package/src/brain/decision-tracker.js +0 -125
  193. package/src/brain/decisor.js +0 -243
  194. package/src/brain/solomon-consult.js +0 -171
  195. package/src/brain/standby-scheduler.js +0 -8
  196. package/src/budget/comparison.js +0 -96
  197. package/src/canvas/parse-md.js +0 -238
  198. package/src/canvas/schema.js +0 -101
  199. package/src/canvas/to-flat.js +0 -85
  200. package/src/canvas/validate.js +0 -163
  201. package/src/ci/dispatch.js +0 -99
  202. package/src/ci/index.js +0 -3
  203. package/src/ci/pr-diff.js +0 -26
  204. package/src/cli/register-standby.js +0 -26
  205. package/src/commands/architect.js +0 -111
  206. package/src/commands/autorun.js +0 -49
  207. package/src/commands/researcher.js +0 -54
  208. package/src/commands/resume.js +0 -72
  209. package/src/commands/review.js +0 -89
  210. package/src/commands/run.js +0 -185
  211. package/src/commands/standby.js +0 -117
  212. package/src/commands/status.js +0 -36
  213. package/src/commands/triage.js +0 -78
  214. package/src/commands/undo.js +0 -62
  215. package/src/domains/domain-loader.js +0 -245
  216. package/src/domains/domain-registry.js +0 -140
  217. package/src/domains/domain-synthesizer.js +0 -129
  218. package/src/git/automation.js +0 -433
  219. package/src/git/coder-commit-guard.js +0 -40
  220. package/src/git/hu-automation.js +0 -243
  221. package/src/git/hu-snapshot.js +0 -10
  222. package/src/git/symlink-targets.js +0 -57
  223. package/src/golden/asserter.js +0 -92
  224. package/src/golden/loader.js +0 -52
  225. package/src/golden/runner.js +0 -92
  226. package/src/golden/schema.js +0 -41
  227. package/src/guards/duplicate-members.js +0 -86
  228. package/src/guards/intent-guard.js +0 -161
  229. package/src/guards/perf-guard.js +0 -126
  230. package/src/guards/policy-guard.js +0 -90
  231. package/src/guards/policy-resolver.js +0 -85
  232. package/src/guards/secret-redactor.js +0 -71
  233. package/src/hu/acceptance-runner.js +0 -138
  234. package/src/hu/lazy-planner.js +0 -109
  235. package/src/hu/parallel-executor.js +0 -94
  236. package/src/hu/routing-metrics.js +0 -17
  237. package/src/hu/split-validator.js +0 -143
  238. package/src/hu/splitting-detector.js +0 -158
  239. package/src/hu/splitting-generator.js +0 -175
  240. package/src/hu/store.js +0 -394
  241. package/src/infrastructure/mocks.js +0 -182
  242. package/src/mcp/handlers/run-handler.js +0 -318
  243. package/src/mcp/sovereignty-guard.js +0 -113
  244. package/src/mcp/tool-arg-normalizers.js +0 -16
  245. package/src/mutate/reviewer-signal.js +0 -76
  246. package/src/orchestrator/agent-fallback.js +0 -81
  247. package/src/orchestrator/brain-coordinator.js +0 -186
  248. package/src/orchestrator/ci-integration.js +0 -139
  249. package/src/orchestrator/config-init.js +0 -426
  250. package/src/orchestrator/direct-actions.js +0 -217
  251. package/src/orchestrator/drivers/error-recovery.js +0 -287
  252. package/src/orchestrator/drivers/init-context.js +0 -238
  253. package/src/orchestrator/drivers/iteration-loop.js +0 -382
  254. package/src/orchestrator/drivers/iteration-phases/coder-and-refactorer.js +0 -69
  255. package/src/orchestrator/drivers/iteration-phases/guards.js +0 -91
  256. package/src/orchestrator/drivers/iteration-phases/handle-approved.js +0 -29
  257. package/src/orchestrator/drivers/iteration-phases/quality-gates.js +0 -125
  258. package/src/orchestrator/drivers/iteration-phases/reviewer-gate.js +0 -62
  259. package/src/orchestrator/drivers/post-loop.js +0 -404
  260. package/src/orchestrator/drivers/pre-loop-phases/auto-hu-batch.js +0 -137
  261. package/src/orchestrator/drivers/pre-loop-phases/config-deprecations.js +0 -47
  262. package/src/orchestrator/drivers/pre-loop-phases/ensure-addyosmani-skills.js +0 -84
  263. package/src/orchestrator/drivers/pre-loop-phases/inject-loaded-plan.js +0 -393
  264. package/src/orchestrator/drivers/pre-loop.js +0 -524
  265. package/src/orchestrator/drivers/run-hu-batch.js +0 -468
  266. package/src/orchestrator/feedback-enrichment.js +0 -140
  267. package/src/orchestrator/feedback-queue.js +0 -151
  268. package/src/orchestrator/flow-control.js +0 -170
  269. package/src/orchestrator/flow-runner.js +0 -365
  270. package/src/orchestrator/fs-leak-detector.js +0 -228
  271. package/src/orchestrator/hu-scheduler.js +0 -114
  272. package/src/orchestrator/hu-sub-pipeline.js +0 -642
  273. package/src/orchestrator/iteration-gate.js +0 -73
  274. package/src/orchestrator/iteration-stages.js +0 -9
  275. package/src/orchestrator/parallel-limiter.js +0 -74
  276. package/src/orchestrator/pipeline-context.js +0 -72
  277. package/src/orchestrator/post-loop-stages.js +0 -468
  278. package/src/orchestrator/pre-loop-stages.js +0 -11
  279. package/src/orchestrator/preflight-checks.js +0 -487
  280. package/src/orchestrator/repair/repair-detector.js +0 -117
  281. package/src/orchestrator/repair/repair-runner.js +0 -142
  282. package/src/orchestrator/reviewer-fallback.js +0 -45
  283. package/src/orchestrator/role-output-compressor.js +0 -189
  284. package/src/orchestrator/session-journal.js +0 -308
  285. package/src/orchestrator/solomon-escalation.js +0 -331
  286. package/src/orchestrator/solomon-rules.js +0 -212
  287. package/src/orchestrator/stages/acceptance-coverage-stage.js +0 -47
  288. package/src/orchestrator/stages/architect-stage.js +0 -172
  289. package/src/orchestrator/stages/coder-stage.js +0 -506
  290. package/src/orchestrator/stages/domain-curator-stage.js +0 -82
  291. package/src/orchestrator/stages/format-stage.js +0 -61
  292. package/src/orchestrator/stages/hu-reviewer-phases/detect-and-apply-splits.js +0 -127
  293. package/src/orchestrator/stages/hu-reviewer-stage.js +0 -419
  294. package/src/orchestrator/stages/perf-stage.js +0 -140
  295. package/src/orchestrator/stages/planner-stage.js +0 -85
  296. package/src/orchestrator/stages/rag-context-stage.js +0 -80
  297. package/src/orchestrator/stages/rag-preload-decisor.js +0 -58
  298. package/src/orchestrator/stages/research-stage.js +0 -69
  299. package/src/orchestrator/stages/reviewer-stage.js +0 -431
  300. package/src/orchestrator/stages/sonar-stage.js +0 -439
  301. package/src/orchestrator/stages/stage-classes.js +0 -84
  302. package/src/orchestrator/stages/stage-executor.js +0 -155
  303. package/src/orchestrator/stages/suite-green-stage.js +0 -62
  304. package/src/orchestrator/stages/tdd-discipline-stage.js +0 -56
  305. package/src/orchestrator/stages/tool-judge-stage.js +0 -53
  306. package/src/orchestrator/stages/triage-stage.js +0 -172
  307. package/src/orchestrator/standby.js +0 -71
  308. package/src/orchestrator/verification-gate.js +0 -183
  309. package/src/orchestrator.js +0 -22
  310. package/src/plan/adr-generator.js +0 -170
  311. package/src/plan/adr-loader.js +0 -60
  312. package/src/plan/plan-executor.js +0 -100
  313. package/src/plan/plan-validation.js +0 -4
  314. package/src/prompts/acceptance-coverage.js +0 -32
  315. package/src/prompts/arbiter.js +0 -38
  316. package/src/prompts/architect.js +0 -103
  317. package/src/prompts/hu-reviewer.js +0 -244
  318. package/src/prompts/tool-correctness-judge.js +0 -31
  319. package/src/prompts/triage.js +0 -57
  320. package/src/rag/embedder.js +0 -2
  321. package/src/rag/embedders/_cloud-base.js +0 -2
  322. package/src/rag/embedders/cohere.js +0 -2
  323. package/src/rag/embedders/mistral.js +0 -2
  324. package/src/rag/embedders/onnx.js +0 -2
  325. package/src/rag/embedders/openai.js +0 -2
  326. package/src/rag/embedders/voyage.js +0 -2
  327. package/src/rag/rerank.js +0 -4
  328. package/src/rag/where-parser.js +0 -4
  329. package/src/repeat-detector.js +0 -88
  330. package/src/review/diff-generator.js +0 -112
  331. package/src/review/git-stash-helper.js +0 -104
  332. package/src/review/schema.js +0 -31
  333. package/src/review/scope-filter.js +0 -152
  334. package/src/review/snapshot-diff.js +0 -122
  335. package/src/review/tdd-discipline.js +0 -90
  336. package/src/review/tdd-policy.js +0 -69
  337. package/src/roles/acceptance-coverage-role.js +0 -78
  338. package/src/roles/architect-role.js +0 -77
  339. package/src/roles/coder-role.js +0 -113
  340. package/src/roles/commiter-role.js +0 -113
  341. package/src/roles/domain-curator-role.js +0 -134
  342. package/src/roles/hu-reviewer-role.js +0 -64
  343. package/src/roles/impeccable-role.js +0 -85
  344. package/src/roles/index.js +0 -18
  345. package/src/roles/karajan-brain-role.js +0 -134
  346. package/src/roles/perf-role.js +0 -122
  347. package/src/roles/planner-role.js +0 -151
  348. package/src/roles/refactorer-role.js +0 -30
  349. package/src/roles/repairer-role.js +0 -181
  350. package/src/roles/researcher-role.js +0 -70
  351. package/src/roles/reviewer-role.js +0 -115
  352. package/src/roles/security-role.js +0 -73
  353. package/src/roles/solomon-role.js +0 -271
  354. package/src/roles/sonar-role.js +0 -72
  355. package/src/roles/tester-role.js +0 -235
  356. package/src/roles/tool-correctness-judge-role.js +0 -78
  357. package/src/roles/triage-role.js +0 -99
  358. package/src/session/journal/decisions-writer.js +0 -200
  359. package/src/session/journal/iteration-logger.js +0 -194
  360. package/src/session/journal/summary-writer.js +0 -320
  361. package/src/session/journal/tree-writer.js +0 -164
  362. package/src/session/journal/write-all.js +0 -89
  363. package/src/session-cleanup.js +0 -116
  364. package/src/skills/semantic-detector.js +0 -167
  365. package/src/skills/skill-detector.js +0 -385
  366. package/src/sonar/cloud-scanner.js +0 -78
  367. package/src/tracker-bootstrap.js +0 -44
  368. package/src/types/index.js +0 -38
  369. package/src/types/policy.js +0 -43
  370. package/src/types/solomon.js +0 -87
  371. package/src/utils/async-lock.js +0 -31
  372. package/src/utils/budget.js +0 -229
  373. package/src/utils/cwd-confirm.js +0 -39
  374. package/src/utils/display/event-handlers.js +0 -403
  375. package/src/utils/display/formatters.js +0 -132
  376. package/src/utils/display/header.js +0 -47
  377. package/src/utils/display/session-summary.js +0 -118
  378. package/src/utils/display/solomon.js +0 -42
  379. package/src/utils/pricing.js +0 -29
  380. package/src/utils/quota-simulator.js +0 -56
  381. package/src/utils/role-assigner.js +0 -137
  382. package/src/utils/rtk-wrapper.js +0 -87
  383. package/src/utils/run-registry.js +0 -9
  384. package/src/utils/status-dashboard.js +0 -254
  385. package/src/utils/tool-call-extractor.js +0 -56
  386. package/src/webperf/devtools-detect.js +0 -112
  387. package/src/webperf/webperf-role-integration.js +0 -66
  388. package/templates/skills/kj-run.md +0 -73
@@ -1,86 +1,75 @@
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
 
6
6
  import { handleSuggestion } from "../suggest-handler.js";
7
+ import { runKjCommand } from "../run-kj.js";
7
8
  import {
8
9
  resolveProjectDir,
9
10
  failPayload,
10
11
  } from "../shared-helpers.js";
11
12
 
13
+ export const HU_STATUSES = ["pending", "running", "done", "failed", "skipped"];
14
+
15
+ /**
16
+ * KJC-BUG-0452 (#2815): kj_hu used the old kj run store, so an agent saw an empty
17
+ * board while `kj hu list` showed every card. It runs the CLI's own `kj hu` in a
18
+ * subprocess: the same board (local, shared or a lane's), and stdout, which is
19
+ * this server's protocol channel, stays clean.
20
+ */
21
+ async function kjHu(projectDir, args) {
22
+ const res = await runKjCommand({ command: "hu", commandArgs: [...args, "--json"], options: { projectDir } });
23
+ if (!res.ok) return { error: `kj hu ${args[0]} failed: ${res.errorSummary || res.stderr || "no output"}` };
24
+ const line = String(res.stdout || "").trim().split("\n").reverse().find((l) => /^[[{]/.test(l.trim()));
25
+ try { return { data: JSON.parse(line) }; } catch { return { error: `kj hu ${args[0]} answered no JSON: ${String(res.stdout || "").slice(0, 200)}` }; }
26
+ }
27
+
28
+ const notOnBoard = (id) => `HU ${id} is not on the board — kj_hu list shows its cards`;
29
+
30
+ async function createHu(projectDir, a) {
31
+ if (!a.title) return failPayload("Missing required field: title (required for create)");
32
+ const args = ["add", a.title, ...(a.acceptanceCriteria ? ["--ac", a.acceptanceCriteria] : []), ...(a.ref ? ["--ref", a.ref] : [])];
33
+ const added = await kjHu(projectDir, args);
34
+ if (added.error) return failPayload(added.error);
35
+ if (!a.status || a.status === "pending") return { ok: true, hu: added.data };
36
+ return moveHu(projectDir, added.data.short_id || added.data.id, a.status);
37
+ }
38
+
39
+ async function moveHu(projectDir, huId, status) {
40
+ if (!HU_STATUSES.includes(status)) return failPayload(`Unknown status "${status}": use ${HU_STATUSES.join(", ")}`);
41
+ const moved = await kjHu(projectDir, ["move", huId, status]);
42
+ return moved.error ? failPayload(moved.error) : { ok: true, hu: moved.data };
43
+ }
44
+
12
45
  export async function handleHu(a, server) {
13
46
  const action = a.action;
14
47
  if (!action) return failPayload("Missing required field: action");
15
-
16
48
  const projectDir = await resolveProjectDir(server, a.projectDir);
17
- const { createManualHu, listHus, getHu, updateHuStatus } = await import("../../hu/store.js");
18
49
 
19
50
  switch (action) {
20
- case "create": {
21
- if (!a.title) return failPayload("Missing required field: title (required for create)");
22
- const hu = await createManualHu(projectDir, {
23
- title: a.title,
24
- description: a.description,
25
- status: a.status,
26
- acceptanceCriteria: a.acceptanceCriteria
27
- });
28
- return { ok: true, hu };
29
- }
51
+ case "create":
52
+ return createHu(projectDir, a);
30
53
  case "list": {
31
- const hus = await listHus(projectDir);
32
- return { ok: true, hus };
54
+ const listed = await kjHu(projectDir, ["list"]);
55
+ return listed.error ? failPayload(listed.error) : { ok: true, hus: listed.data };
33
56
  }
34
57
  case "get": {
35
58
  if (!a.huId) return failPayload("Missing required field: huId (required for get)");
36
- const hu = await getHu(projectDir, a.huId);
37
- return { ok: true, hu };
59
+ const listed = await kjHu(projectDir, ["list"]);
60
+ if (listed.error) return failPayload(listed.error);
61
+ const hu = listed.data.find((h) => h.id === a.huId || h.short_id === a.huId);
62
+ return hu ? { ok: true, hu } : failPayload(notOnBoard(a.huId));
38
63
  }
39
- case "update": {
64
+ case "update":
40
65
  if (!a.huId) return failPayload("Missing required field: huId (required for update)");
41
66
  if (!a.status) return failPayload("Missing required field: status (required for update)");
42
- const hu = await updateHuStatus(projectDir, a.huId, a.status);
43
- return { ok: true, hu };
44
- }
67
+ return moveHu(projectDir, a.huId, a.status);
45
68
  default:
46
69
  return failPayload(`Unknown hu action: ${action}`);
47
70
  }
48
71
  }
49
72
 
50
- export async function handleSkills(a) {
51
- const action = a.action;
52
- if (!action) return failPayload("Missing required field: action");
53
-
54
- const { isOpenSkillsAvailable, installSkill, removeSkill, listSkills, readSkill } =
55
- await import("../../skills/openskills-client.js");
56
-
57
- const opts = { projectDir: a.projectDir || null };
58
-
59
- switch (action) {
60
- case "install": {
61
- if (!a.source) return failPayload("Missing required field: source (required for install)");
62
- const available = await isOpenSkillsAvailable();
63
- if (!available) {
64
- return failPayload("OpenSkills CLI is not available. Install it with: npm install -g openskills");
65
- }
66
- return installSkill(a.source, { ...opts, global: a.global || false });
67
- }
68
- case "remove": {
69
- if (!a.name) return failPayload("Missing required field: name (required for remove)");
70
- return removeSkill(a.name, opts);
71
- }
72
- case "list": {
73
- return listSkills(opts);
74
- }
75
- case "read": {
76
- if (!a.name) return failPayload("Missing required field: name (required for read)");
77
- return readSkill(a.name, opts);
78
- }
79
- default:
80
- return failPayload(`Unknown skills action: ${action}`);
81
- }
82
- }
83
-
84
73
  export async function handleSuggest(a) {
85
74
  if (!a.suggestion) {
86
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
@@ -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),
package/src/mcp/tools.js CHANGED
@@ -48,91 +48,6 @@ export const tools = [
48
48
  }
49
49
  }
50
50
  },
51
- {
52
- name: "kj_run",
53
- description:
54
- "Run the full Karajan pipeline. IMPORTANT: Pass the user's task description exactly as they wrote it. Do NOT group, split, reorder, or modify tasks yourself. Karajan handles decomposition, role activation, iteration, and quality gates internally. Do NOT override pipeline parameters (enableHuReviewer, mode, methodology) unless the user explicitly requested it. If you have observations about the task, use kj_suggest instead.",
55
- inputSchema: {
56
- type: "object",
57
- properties: {
58
- task: { type: "string", description: "Task description for the coder (can include a Planning Game card ID like KJC-TSK-0042). Either `task` or `taskFile` is required." },
59
- taskFile: { type: "string", description: "Alternative to `task`: path to a .md (or any text file) whose contents become the task description. Relative paths resolve against projectDir." },
60
- plan: { type: "string", description: "Plan ID from kj_plan. Loads persisted plan context and skips researcher/architect/planner stages." },
61
- projectDir: { type: "string", description: "Absolute path to the project directory. Required when KJ MCP server runs from a different directory than the target project." },
62
- pgTask: { type: "string", description: "Planning Game card ID (e.g., KJC-TSK-0042). If provided, fetches full card details as task context and updates card status on completion." },
63
- pgProject: { type: "string", description: "Planning Game project ID (e.g., 'Karajan Code'). Required when pgTask is used." },
64
- planner: { type: "string" },
65
- coder: { type: "string" },
66
- reviewer: { type: "string" },
67
- refactorer: { type: "string" },
68
- plannerModel: { type: "string" },
69
- coderModel: { type: "string" },
70
- reviewerModel: { type: "string" },
71
- refactorerModel: { type: "string" },
72
- enablePlanner: { type: "boolean" },
73
- enableReviewer: { type: "boolean" },
74
- enableRefactorer: { type: "boolean" },
75
- enableResearcher: { type: "boolean" },
76
- enableTester: { type: "boolean" },
77
- enableSecurity: { type: "boolean" },
78
- enableImpeccable: { type: "boolean" },
79
- enablePerf: { type: "boolean" },
80
- enableTriage: { type: "boolean" },
81
- enableDiscover: { type: "boolean" },
82
- enableArchitect: { type: "boolean" },
83
- enableHuReviewer: { type: "boolean" },
84
- architectModel: { type: "string" },
85
- huFile: { type: "string", description: "Path to YAML file with HU stories to certify before coding" },
86
- enableSerena: { type: "boolean" },
87
- enableCi: { type: "boolean", description: "Enable Karajan CI (early PR + dispatch comments/reviews)" },
88
- reviewerFallback: { type: "string" },
89
- reviewerRetries: { type: "number" },
90
- mode: { type: "string" },
91
- maxIterations: { type: "number" },
92
- maxIterationMinutes: { type: "number" },
93
- maxTotalMinutes: { type: "number" },
94
- baseBranch: { type: "string" },
95
- baseRef: { type: "string" },
96
- methodology: { type: "string", enum: ["tdd", "standard"] },
97
- autoCommit: { type: "boolean" },
98
- autoPush: { type: "boolean" },
99
- autoPr: { type: "boolean" },
100
- autoRebase: { type: "boolean" },
101
- branchPrefix: { type: "string" },
102
- autoSimplify: { type: "boolean", description: "Auto-simplify pipeline for simple tasks (level trivial/simple). Disable with false to force full pipeline." },
103
- smartModels: { type: "boolean", description: "Enable/disable smart model selection based on triage complexity" },
104
- checkpointInterval: { type: "number", description: "Minutes between interactive checkpoints (default: 5). Set 0 to disable." },
105
- taskType: { type: "string", enum: ["sw", "infra", "doc", "add-tests", "refactor"], description: "Explicit task type for policy resolution. Overrides triage classification." },
106
- quiet: { type: "boolean", description: "Suppress raw agent output lines, show only stage status (default: true). Set false for verbose output." },
107
- noSonar: { type: "boolean" },
108
- design: { type: "boolean", description: "Activate design refactoring mode. Impeccable role applies design changes instead of just auditing." },
109
- enableSonarcloud: { type: "boolean", description: "Enable SonarCloud scan (complementary to SonarQube)" },
110
- kjHome: { type: "string" },
111
- sonarToken: { type: "string" },
112
- timeoutMs: { type: "number" },
113
- domain: { type: "string", description: "Domain knowledge: inline text describing the project domain, or absolute path to a .md file. Auto-saved to .karajan/domains/ for the curator." },
114
- brain: { type: "string", enum: ["on", "off"], description: "Brain decisor: on|off. Controls whether intent-driven routing overrides pipeline flags." },
115
- forceRole: { type: "array", items: { type: "string" }, description: "Force roles ON regardless of triage (e.g. [\"security\"])" },
116
- skipRole: { type: "array", items: { type: "string" }, description: "Force roles OFF regardless of triage (e.g. [\"tester\"])" },
117
- specReviewMode: { type: "string", enum: ["auto", "skip"], description: "Pre-pipeline spec-reviewer behaviour (KJC-PCS-0048). `auto` (default): the role runs, findings stream to the client via progress events; the pipeline continues regardless. `skip`: bypass the reviewer entirely (mirrors the --skip-spec-review CLI flag)." }
118
- }
119
- }
120
- },
121
- {
122
- name: "kj_resume",
123
- description:
124
- "Resume a paused, stopped, or failed session by ID. For paused sessions, provide an answer. For stopped/failed sessions, re-runs the flow from scratch. Sends real-time progress notifications via MCP logging.",
125
- inputSchema: {
126
- type: "object",
127
- required: ["sessionId"],
128
- properties: {
129
- sessionId: { type: "string", description: "Session ID to resume" },
130
- answer: { type: "string", description: "Answer to the question that caused the pause" },
131
- projectDir: { type: "string", description: "Absolute path to the project directory" },
132
- kjHome: { type: "string" }
133
- }
134
- }
135
- },
136
51
  {
137
52
  name: "kj_report",
138
53
  description: "Read latest or list session reports. Use trace=true for chronological stage-by-stage breakdown with timing and token usage.",
@@ -176,7 +91,7 @@ export const tools = [
176
91
  },
177
92
  {
178
93
  name: "kj_preflight",
179
- description: "Confirm or adjust agent configuration before first kj_run/kj_code. REQUIRED before running any task via MCP. Show the config to the human, get their confirmation or adjustments, then call this tool with their response.",
94
+ description: "Confirm or adjust agent configuration before first kj_code. REQUIRED before running any task via MCP. Show the config to the human, get their confirmation or adjustments, then call this tool with their response.",
180
95
  inputSchema: {
181
96
  type: "object",
182
97
  required: ["humanResponse"],
@@ -207,50 +122,6 @@ export const tools = [
207
122
  }
208
123
  }
209
124
  },
210
- {
211
- name: "kj_review",
212
- description: "Run reviewer-only mode against current diff. Do NOT filter or pre-process the diff before passing it.",
213
- inputSchema: {
214
- type: "object",
215
- properties: {
216
- task: { type: "string", description: "Task description. Either `task` or `taskFile` is required." },
217
- taskFile: { type: "string", description: "Alternative to `task`: path to a .md/text file." },
218
- reviewer: { type: "string" },
219
- reviewerModel: { type: "string" },
220
- baseRef: { type: "string" },
221
- projectDir: { type: "string", description: "Absolute path to the project directory" },
222
- kjHome: { type: "string" }
223
- }
224
- }
225
- },
226
- {
227
- name: "kj_status",
228
- description: "Show real-time status and log of the current or last Karajan run. Returns a parsed status (current stage, agent, iteration, errors) plus recent log lines. Use this to monitor progress while kj_run/kj_plan/kj_code is executing.",
229
- inputSchema: {
230
- type: "object",
231
- properties: {
232
- lines: { type: "number", description: "Number of log lines to show (default 50)" }
233
- }
234
- }
235
- },
236
- {
237
- name: "kj_plan",
238
- description: "Generate implementation plan for a task. Pass the task as the user described it. Karajan's planner decides the approach.",
239
- inputSchema: {
240
- type: "object",
241
- properties: {
242
- task: { type: "string", description: "Task description. Either `task` or `taskFile` is required." },
243
- taskFile: { type: "string", description: "Alternative to `task`: path to a .md/text file." },
244
- planner: { type: "string" },
245
- plannerModel: { type: "string" },
246
- coder: { type: "string", description: "Legacy alias for planner" },
247
- coderModel: { type: "string", description: "Legacy alias for plannerModel" },
248
- projectDir: { type: "string", description: "Absolute path to the project directory" },
249
- kjHome: { type: "string" },
250
- specReviewMode: { type: "string", enum: ["auto", "skip"], description: "Pre-planner spec-reviewer behaviour (KJC-PCS-0048). `auto` (default): runs the reviewer, findings stream as progress, planner continues. `skip`: bypass entirely." }
251
- }
252
- }
253
- },
254
125
  {
255
126
  name: "kj_discover",
256
127
  description: "Analyze a task for gaps, ambiguities, and missing information before execution. Returns a verdict (ready/needs_validation) with structured gap list. Can read task details from Planning Game if pgTask is provided.",
@@ -268,46 +139,6 @@ export const tools = [
268
139
  }
269
140
  }
270
141
  },
271
- {
272
- name: "kj_triage",
273
- description: "Classify task complexity and recommend which pipeline roles to activate. Returns level (trivial/simple/medium/complex), taskType, recommended roles, and optional decomposition.",
274
- inputSchema: {
275
- type: "object",
276
- properties: {
277
- task: { type: "string", description: "Task description to classify. Either `task` or `taskFile` is required." },
278
- taskFile: { type: "string", description: "Alternative to `task`: path to a .md/text file." },
279
- projectDir: { type: "string", description: "Absolute path to the project directory" },
280
- kjHome: { type: "string" }
281
- }
282
- }
283
- },
284
- {
285
- name: "kj_researcher",
286
- description: "Research the codebase for a task. Identifies affected files, patterns, constraints, prior decisions, risks, and test coverage.",
287
- inputSchema: {
288
- type: "object",
289
- properties: {
290
- task: { type: "string", description: "Task description to research. Either `task` or `taskFile` is required." },
291
- taskFile: { type: "string", description: "Alternative to `task`: path to a .md/text file." },
292
- projectDir: { type: "string", description: "Absolute path to the project directory" },
293
- kjHome: { type: "string" }
294
- }
295
- }
296
- },
297
- {
298
- name: "kj_architect",
299
- description: "Design solution architecture for a task. Returns layers, patterns, data model, API contracts, tradeoffs, and a verdict (ready/needs_clarification).",
300
- inputSchema: {
301
- type: "object",
302
- properties: {
303
- task: { type: "string", description: "Task description to architect. Either `task` or `taskFile` is required." },
304
- taskFile: { type: "string", description: "Alternative to `task`: path to a .md/text file." },
305
- context: { type: "string", description: "Additional context (e.g., researcher output)" },
306
- projectDir: { type: "string", description: "Absolute path to the project directory" },
307
- kjHome: { type: "string" }
308
- }
309
- }
310
- },
311
142
  {
312
143
  name: "kj_audit",
313
144
  description: "Analyze codebase health without modifying files. Returns findings across security, code quality, performance, architecture, and testing dimensions.",
@@ -335,17 +166,17 @@ export const tools = [
335
166
  },
336
167
  {
337
168
  name: "kj_hu",
338
- description: "Manage user stories (HUs) in the local board",
169
+ description: "Manage user stories (HUs) in the HU Board, the same board `kj hu` uses (local or shared)",
339
170
  inputSchema: {
340
171
  type: "object",
341
172
  required: ["action"],
342
173
  properties: {
343
174
  action: { type: "string", enum: ["create", "update", "list", "get"], description: "Action to perform" },
344
175
  title: { type: "string", description: "HU title (required for create)" },
345
- description: { type: "string", description: "HU description" },
346
- acceptanceCriteria: { type: "string", description: "Acceptance criteria" },
176
+ acceptanceCriteria: { type: "string", description: "Acceptance criteria, one per line" },
177
+ ref: { type: "string", description: "Id of this card's replica in the external tracker (Planning Game, Jira, Linear...)" },
347
178
  huId: { type: "string", description: "HU ID (required for update/get)" },
348
- status: { type: "string", description: "HU status (for create/update)", enum: ["pending", "coding", "reviewing", "done", "failed", "blocked"] },
179
+ status: { type: "string", description: "HU status (for create/update)", enum: ["pending", "running", "done", "failed", "skipped"] },
349
180
  projectDir: { type: "string", description: "Project directory (defaults to cwd)" }
350
181
  }
351
182
  }
@@ -363,32 +194,6 @@ export const tools = [
363
194
  }
364
195
  }
365
196
  },
366
- {
367
- name: "kj_skills",
368
- description: "Manage OpenSkills for domain-specific agent knowledge. Install skills from the marketplace or GitHub repos to give coders domain expertise.",
369
- inputSchema: {
370
- type: "object",
371
- properties: {
372
- action: { type: "string", enum: ["install", "remove", "list", "read"], description: "Action to perform" },
373
- source: { type: "string", description: "Skill source: marketplace name, GitHub URL, or local path (for install)" },
374
- name: { type: "string", description: "Skill name (for remove/read)" },
375
- global: { type: "boolean", description: "Install globally (~/.agent/skills/) instead of project-local" },
376
- projectDir: { type: "string", description: "Project directory" }
377
- },
378
- required: ["action"]
379
- }
380
- },
381
- {
382
- name: "kj_undo",
383
- description: "Revert the last pipeline run by resetting to the pre-pipeline commit. Default: soft reset (keeps changes staged). Use hard=true to discard all changes.",
384
- inputSchema: {
385
- type: "object",
386
- properties: {
387
- hard: { type: "boolean", description: "If true, discard all changes (git reset --hard). Default: false (soft reset, keeps changes staged)." },
388
- projectDir: { type: "string", description: "Absolute path to the project directory" }
389
- }
390
- }
391
- },
392
197
  {
393
198
  name: "kj_clean",
394
199
  description: "Garbage-collect stale Karajan state: orphan plans (project dir no longer exists), finalised plans/sessions past their retention window, and HU story batches. Dry-run by default; pass yes=true to actually delete. Use nuke=true to wipe everything (retention=0 on every bucket + drop the HU board SQLite DB).",
@@ -0,0 +1,54 @@
1
+ /**
2
+ * #2566: a lane (<main>/.kj/worktrees/<x>, <main>/.claude/worktrees/<x>) kept plans under its own
3
+ * slug; `kj hu list` moves them to the main checkout's. A taken name is kept and reported.
4
+ */
5
+ import fs from "node:fs/promises";
6
+ import path from "node:path";
7
+ import { plansDir } from "./plan-store.js";
8
+ import { mainCheckout } from "../utils/main-checkout.js";
9
+ import { MIRROR_PLAN_ID } from "../hu/team-board-mirror.js";
10
+
11
+ const LANE_DIRS = [".kj_worktrees_", ".claude_worktrees_"];
12
+
13
+ // Never overwrites: "wx" and errorOnExist fail with EEXIST if another session wrote dest first.
14
+ async function moveEntry(from, dest, main) {
15
+ const plan = from.endsWith(".json") ? await fs.readFile(from, "utf8").then(JSON.parse, () => null) : null;
16
+ if (plan) {
17
+ // TSK-0341: the stamp must outlive the lane, or the GC sees the plan as orphan.
18
+ await fs.writeFile(dest, JSON.stringify({ ...plan, projectDir: main }, null, 2), { flag: "wx" });
19
+ return fs.unlink(from);
20
+ }
21
+ await fs.cp(from, dest, { recursive: true, force: false, errorOnExist: true });
22
+ return fs.rm(from, { recursive: true });
23
+ }
24
+
25
+ export async function migrateLanePlans(projectDir) {
26
+ const [target, main] = [plansDir(projectDir), mainCheckout(projectDir)];
27
+ const root = path.dirname(target);
28
+ const prefixes = LANE_DIRS.map((d) => `${path.basename(target)}_${d}`); // the main checkout's slug
29
+ const moved = [];
30
+ const kept = [];
31
+ let entries;
32
+ try { entries = await fs.readdir(root, { withFileTypes: true }); } catch (err) {
33
+ if (err.code === "ENOENT") return { moved, kept };
34
+ throw err;
35
+ }
36
+ const isLaneFolder = (e) => e.isDirectory() && prefixes.some((p) => e.name.startsWith(p));
37
+ for (const lane of entries.filter(isLaneFolder)) {
38
+ const from = path.join(root, lane.name);
39
+ await fs.mkdir(target, { recursive: true });
40
+ for (const file of await fs.readdir(from)) {
41
+ // The team board mirror is no plan: `kj hu list` rewrites it from GitHub, a lane's copy is stale.
42
+ if (file === `${MIRROR_PLAN_ID}.json`) { await fs.unlink(path.join(from, file)); continue; }
43
+ try {
44
+ await moveEntry(path.join(from, file), path.join(target, file), main);
45
+ moved.push(file);
46
+ } catch (err) {
47
+ if (err.code !== "EEXIST" && err.code !== "ERR_FS_CP_EEXIST") throw err;
48
+ kept.push(path.join(from, file));
49
+ }
50
+ }
51
+ await fs.rmdir(from).catch((err) => { if (err.code !== "ENOTEMPTY") throw err; }); // a collision stays
52
+ }
53
+ return { moved, kept };
54
+ }
@@ -10,6 +10,7 @@ import { writeJsonAtomic } from "../utils/atomic-write.js";
10
10
  import { resolveHome } from "../utils/paths.js";
11
11
  import { getSharedPlansDir } from "../utils/shared-paths.js";
12
12
  import { generatePlanId, normaliseAlias } from "./plan-id.js";
13
+ import { mainCheckout } from "../utils/main-checkout.js";
13
14
 
14
15
  /**
15
16
  * A plan JSON file failed to parse — typically an interrupted write
@@ -51,7 +52,7 @@ export function getKjHome() {
51
52
  /**
52
53
  * Deterministic slug for a project path — stable across plan-store writes,
53
54
  * HU-board syncs and board URL routing. Keep in lockstep with
54
- * `packages/hu-board/src/sync.js::deriveProjectIdFromDir`.
55
+ * `packages/hu-board/src/sync.js::deriveProjectIdFromDir` (kj slugs the main checkout, #2566).
55
56
  * @param {string} projectDir - absolute project path
56
57
  * @returns {string}
57
58
  */
@@ -64,12 +65,13 @@ export function projectSlug(projectDir) {
64
65
  }
65
66
 
66
67
  // KJC-TSK-1166: the board honours KJ_PLANS_DIR as its plans root; what kj writes must land
67
- // in the same root, or the board shows none of it.
68
+ // in the same root, or the board shows none of it. #2566: one folder per main checkout, lanes included.
68
69
  export function plansDir(projectDir) {
69
70
  const root = process.env.KJ_PLANS_DIR || path.join(getKjHome(), "plans");
70
- return path.join(root, projectSlug(projectDir));
71
+ return path.join(root, projectSlug(mainCheckout(projectDir)));
71
72
  }
72
73
 
74
+
73
75
  /**
74
76
  * Save a plan to disk. Accepts both v1 and v2 schemas.
75
77
  * @param {string} projectDir
@@ -88,7 +90,8 @@ export async function savePlan(projectDir, planResult) {
88
90
  // plan so the GC can check `fs.exists(projectDir)` reliably. Reverse-
89
91
  // engineering it from the slug is lossy (underscores in the original
90
92
  // name collide with underscores introduced by slash-substitution).
91
- if (!planResult.projectDir && projectDir) planResult.projectDir = projectDir;
93
+ // #2566: the main checkout, never a lane that is deleted after merge.
94
+ if (!planResult.projectDir && projectDir) planResult.projectDir = mainCheckout(projectDir);
92
95
  // Humanización IDs: si el plan no tiene alias todavía, derívalo de
93
96
  // plan.name (lo que el planner pidió al usuario). Resuelve
94
97
  // colisiones con sufijo -2, -3… leyendo el dir antes.