karajan-code 4.70.4 → 5.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (390) hide show
  1. package/README.md +2 -2
  2. package/package.json +6 -14
  3. package/packages/hu-board/package.json +1 -1
  4. package/packages/hu-board/public/app.js +4 -18
  5. package/packages/hu-board/public/index.html +5 -2
  6. package/packages/hu-board/public/styles.css +26 -0
  7. package/packages/hu-board/public/utils/api.js +0 -74
  8. package/packages/hu-board/public/utils/board-tour.js +62 -0
  9. package/packages/hu-board/public/utils/board-view.js +49 -144
  10. package/packages/hu-board/public/utils/command-launcher.js +8 -70
  11. package/packages/hu-board/public/utils/formatters.js +10 -0
  12. package/packages/hu-board/public/utils/governance-view.js +13 -1
  13. package/packages/hu-board/public/utils/hu-actions.js +17 -68
  14. package/packages/hu-board/public/utils/init-listeners.js +7 -8
  15. package/packages/hu-board/public/utils/log-panel.js +3 -16
  16. package/packages/hu-board/public/utils/maggle-mode.js +2 -12
  17. package/packages/hu-board/public/utils/modals.js +7 -0
  18. package/packages/hu-board/public/utils/project-picker-view.js +1 -1
  19. package/packages/hu-board/public/utils/server-push.js +3 -22
  20. package/packages/hu-board/public/utils/shared-board-notice.js +33 -0
  21. package/packages/hu-board/public/utils/story-detail-view.js +5 -19
  22. package/packages/hu-board/src/cleanup-zombies.js +0 -1
  23. package/packages/hu-board/src/command-runner.js +36 -25
  24. package/packages/hu-board/src/db-connection.js +282 -0
  25. package/packages/hu-board/src/db-paths.js +113 -0
  26. package/packages/hu-board/src/db-queries.js +188 -0
  27. package/packages/hu-board/src/db-tombstones.js +51 -0
  28. package/packages/hu-board/src/db.js +28 -619
  29. package/packages/hu-board/src/ephemeral-cleaner.js +2 -3
  30. package/packages/hu-board/src/hu-zombie-reaper.js +5 -1
  31. package/packages/hu-board/src/plan-mutations.js +3 -153
  32. package/packages/hu-board/src/plans-service.js +55 -0
  33. package/packages/hu-board/src/routes/api/commands.js +122 -0
  34. package/packages/hu-board/src/routes/api/plans.js +55 -0
  35. package/packages/hu-board/src/routes/api/projects.js +267 -0
  36. package/packages/hu-board/src/routes/api/prompts.js +135 -0
  37. package/packages/hu-board/src/routes/api/sessions.js +95 -0
  38. package/packages/hu-board/src/routes/api/stories.js +183 -0
  39. package/packages/hu-board/src/routes/api/system.js +241 -0
  40. package/packages/hu-board/src/routes/api/tombstones.js +38 -0
  41. package/packages/hu-board/src/routes/api.js +24 -1371
  42. package/packages/hu-board/src/routes/governance.js +23 -1
  43. package/packages/hu-board/src/routes/lanes.js +40 -0
  44. package/packages/hu-board/src/routes/rag.js +4 -3
  45. package/packages/hu-board/src/server.js +20 -34
  46. package/packages/hu-board/src/sync-files.js +318 -0
  47. package/packages/hu-board/src/sync-project.js +99 -0
  48. package/packages/hu-board/src/sync.js +22 -566
  49. package/packages/hu-board/src/zombie-reaper.js +1 -1
  50. package/scripts/dual-publish.mjs +19 -3
  51. package/scripts/postinstall.js +15 -2
  52. package/scripts/verify-pack-mcp.mjs +11 -7
  53. package/scripts/verify-pack.mjs +4 -4
  54. package/src/audit/audit-history.js +3 -2
  55. package/src/audit/dead-exports.js +68 -59
  56. package/src/audit/deterministic-summary.js +33 -13
  57. package/src/audit/npm-signatures.js +41 -0
  58. package/src/audit/sbom.js +35 -0
  59. package/src/checks/agent-token.js +112 -0
  60. package/src/checks/dir-setup.js +34 -1
  61. package/src/checks/native-build.js +21 -39
  62. package/src/checks/runner.js +128 -142
  63. package/src/cli/advanced-commands.js +6 -6
  64. package/src/cli/register-meta.js +42 -82
  65. package/src/cli/register-pipeline.js +8 -143
  66. package/src/cli/register-plan.js +9 -100
  67. package/src/cli/register-roles-skills.js +1 -1
  68. package/src/cli/retired-commands.js +49 -0
  69. package/src/cli.js +18 -5
  70. package/src/commands/agent-run.js +40 -26
  71. package/src/commands/audit.js +127 -124
  72. package/src/commands/board.js +5 -9
  73. package/src/commands/check.js +29 -16
  74. package/src/commands/doctor.js +2 -0
  75. package/src/commands/env.js +176 -150
  76. package/src/commands/go.js +71 -53
  77. package/src/commands/harden.js +90 -81
  78. package/src/commands/hu-start.js +52 -0
  79. package/src/commands/hu.js +288 -221
  80. package/src/commands/identity.js +111 -78
  81. package/src/commands/init-atril.js +47 -0
  82. package/src/commands/init.js +11 -40
  83. package/src/commands/install-tools.js +70 -85
  84. package/src/commands/main-guard.js +78 -0
  85. package/src/commands/policy.js +226 -184
  86. package/src/commands/qmd.js +27 -21
  87. package/src/commands/rag.js +121 -55
  88. package/src/commands/review-gate.js +421 -341
  89. package/src/commands/skills.js +4 -1
  90. package/src/commands/start.js +4 -5
  91. package/src/commands/steward.js +96 -47
  92. package/src/commands/tournament.js +46 -37
  93. package/src/commands/worktree.js +107 -26
  94. package/src/config/defaults.js +1 -0
  95. package/src/config/loader.js +34 -17
  96. package/src/config/role-resolver.js +1 -0
  97. package/src/config/schema.js +1 -0
  98. package/src/config/secrets.js +36 -0
  99. package/src/config.js +1 -0
  100. package/src/environment/adr.js +16 -2
  101. package/src/git/karajan-label.js +20 -8
  102. package/src/guards/main-guard.js +54 -0
  103. package/src/harden/hook-templates.js +16 -1
  104. package/src/harden/sentinel/posttooluse.mjs +18 -6
  105. package/src/harden/sentinel/pretooluse-sentinel.mjs +64 -36
  106. package/src/harden/sentinel/sentinel-lib.mjs +129 -26
  107. package/src/harden/sentinel/sentinel-shell.mjs +5 -16
  108. package/src/harden/sentinel/sessionstart.mjs +3 -2
  109. package/src/harden/sentinel/stop.mjs +5 -4
  110. package/src/harden/workflow-templates.js +1 -1
  111. package/src/hu/board-lookup.js +29 -0
  112. package/src/hu/gh-identity.js +23 -0
  113. package/src/hu/github-board.js +4 -2
  114. package/src/hu/lane-prune.js +83 -13
  115. package/src/hu/lane-setup.js +65 -0
  116. package/src/hu/lanes.js +66 -0
  117. package/src/hu/team-board-mirror.js +3 -2
  118. package/src/infrastructure/command-runner.js +1 -1
  119. package/src/infrastructure/file-system-service.js +1 -1
  120. package/src/mcp/handlers/direct-handlers.js +2 -292
  121. package/src/mcp/handlers/hu-handlers.js +1 -35
  122. package/src/mcp/handlers/management-handlers.js +2 -42
  123. package/src/mcp/handlers/rag-handler.js +9 -1
  124. package/src/mcp/server-handlers.js +16 -22
  125. package/src/mcp/tools.js +1 -196
  126. package/src/plan/lane-plans.js +54 -0
  127. package/src/plan/plan-store.js +7 -4
  128. package/src/policy/add.js +26 -12
  129. package/src/policy/adr-number-check.js +31 -0
  130. package/src/prompts/audit.js +299 -339
  131. package/src/prompts/card-context.js +10 -5
  132. package/src/prompts/reviewer.js +5 -2
  133. package/src/rag/auto-update.js +71 -44
  134. package/src/rag/bootstrap-index.js +46 -54
  135. package/src/rag/indexer.js +9 -4
  136. package/src/rag/migrate.js +1 -1
  137. package/src/rag/onnx-fallback.js +2 -2
  138. package/src/rag/pid-lease.js +181 -0
  139. package/src/rag/project-store.js +2 -12
  140. package/src/review/card-first.js +57 -46
  141. package/src/review/gate-gitignore.js +23 -4
  142. package/src/review/gate-hook.js +12 -4
  143. package/src/review/one-shot-review.js +45 -35
  144. package/src/review/publish-pr.js +14 -2
  145. package/src/review/repo-docs.js +73 -0
  146. package/src/review/repo-stack.js +59 -0
  147. package/src/review/reviewer-fallback.js +19 -4
  148. package/src/review/seal-commit.js +29 -0
  149. package/src/review/sonar-pregate.js +59 -44
  150. package/src/review/third-party-review.js +90 -16
  151. package/src/review/third-party-size.js +43 -0
  152. package/src/review/third-party-skills.js +54 -0
  153. package/src/review/verify-pr.js +1 -24
  154. package/src/roles/audit-role.js +106 -125
  155. package/src/skills/atril-cli.js +19 -1
  156. package/src/skills/atril-skills.js +5 -4
  157. package/src/skills/skills-search.js +72 -0
  158. package/src/skills/translate.js +62 -0
  159. package/src/sonar/scanner.js +116 -101
  160. package/src/steward/invariants.js +5 -4
  161. package/src/steward/phantom-sweep.js +66 -0
  162. package/src/tournament/judge.js +60 -53
  163. package/src/utils/gh-account.js +37 -0
  164. package/src/utils/git.js +0 -13
  165. package/src/utils/home-migration.js +7 -1
  166. package/src/utils/main-checkout.js +53 -0
  167. package/src/utils/qmd-collection.js +3 -1
  168. package/src/utils/welcome.js +3 -3
  169. package/templates/{skills → atril/commands}/kj-architect.md +5 -0
  170. package/templates/{skills → atril/commands}/kj-audit.md +5 -0
  171. package/templates/{skills → atril/commands}/kj-board.md +5 -0
  172. package/templates/{skills → atril/commands}/kj-code.md +5 -0
  173. package/templates/{skills → atril/commands}/kj-csv-transform.md +5 -0
  174. package/templates/{skills → atril/commands}/kj-data-report.md +5 -0
  175. package/templates/{skills → atril/commands}/kj-discover.md +5 -0
  176. package/templates/{skills → atril/commands}/kj-rag-query.md +5 -0
  177. package/templates/{skills → atril/commands}/kj-review.md +5 -0
  178. package/templates/{skills → atril/commands}/kj-security.md +5 -0
  179. package/templates/{skills → atril/commands}/kj-sonar.md +5 -0
  180. package/templates/{skills → atril/commands}/kj-sql-analysis.md +5 -0
  181. package/templates/{skills → atril/commands}/kj-test.md +5 -0
  182. package/packages/hu-board/public/utils/run-launcher.js +0 -169
  183. package/packages/hu-board/src/run-tracker.js +0 -121
  184. package/src/activity-log.js +0 -59
  185. package/src/agents/host-agent.js +0 -38
  186. package/src/agents/model-registry.js +0 -142
  187. package/src/audit/plan-adherence.js +0 -224
  188. package/src/autonomy/arbiter-role.js +0 -71
  189. package/src/autonomy/arbiter.js +0 -22
  190. package/src/autonomy/decider.js +0 -18
  191. package/src/autonomy/decision-resolver.js +0 -58
  192. package/src/autonomy/outcome-report.js +0 -55
  193. package/src/autonomy/stage-ask.js +0 -30
  194. package/src/brain/decision-tracker.js +0 -125
  195. package/src/brain/decisor.js +0 -243
  196. package/src/brain/solomon-consult.js +0 -171
  197. package/src/brain/standby-scheduler.js +0 -8
  198. package/src/budget/comparison.js +0 -96
  199. package/src/canvas/parse-md.js +0 -238
  200. package/src/canvas/schema.js +0 -101
  201. package/src/canvas/to-flat.js +0 -85
  202. package/src/canvas/validate.js +0 -163
  203. package/src/ci/dispatch.js +0 -99
  204. package/src/ci/index.js +0 -3
  205. package/src/ci/pr-diff.js +0 -26
  206. package/src/cli/register-standby.js +0 -26
  207. package/src/commands/architect.js +0 -111
  208. package/src/commands/autorun.js +0 -49
  209. package/src/commands/researcher.js +0 -54
  210. package/src/commands/resume.js +0 -72
  211. package/src/commands/review.js +0 -89
  212. package/src/commands/run.js +0 -185
  213. package/src/commands/standby.js +0 -117
  214. package/src/commands/status.js +0 -36
  215. package/src/commands/triage.js +0 -78
  216. package/src/commands/undo.js +0 -62
  217. package/src/domains/domain-loader.js +0 -245
  218. package/src/domains/domain-registry.js +0 -140
  219. package/src/domains/domain-synthesizer.js +0 -129
  220. package/src/git/automation.js +0 -433
  221. package/src/git/coder-commit-guard.js +0 -40
  222. package/src/git/hu-automation.js +0 -243
  223. package/src/git/hu-snapshot.js +0 -10
  224. package/src/git/symlink-targets.js +0 -57
  225. package/src/golden/asserter.js +0 -92
  226. package/src/golden/loader.js +0 -52
  227. package/src/golden/runner.js +0 -92
  228. package/src/golden/schema.js +0 -41
  229. package/src/guards/duplicate-members.js +0 -86
  230. package/src/guards/intent-guard.js +0 -161
  231. package/src/guards/perf-guard.js +0 -126
  232. package/src/guards/policy-guard.js +0 -90
  233. package/src/guards/policy-resolver.js +0 -85
  234. package/src/guards/secret-redactor.js +0 -71
  235. package/src/hu/acceptance-runner.js +0 -138
  236. package/src/hu/lazy-planner.js +0 -109
  237. package/src/hu/parallel-executor.js +0 -94
  238. package/src/hu/routing-metrics.js +0 -17
  239. package/src/hu/split-validator.js +0 -143
  240. package/src/hu/splitting-detector.js +0 -158
  241. package/src/hu/splitting-generator.js +0 -175
  242. package/src/hu/store.js +0 -394
  243. package/src/infrastructure/mocks.js +0 -182
  244. package/src/mcp/handlers/run-handler.js +0 -318
  245. package/src/mcp/sovereignty-guard.js +0 -113
  246. package/src/mcp/tool-arg-normalizers.js +0 -16
  247. package/src/mutate/reviewer-signal.js +0 -76
  248. package/src/orchestrator/agent-fallback.js +0 -81
  249. package/src/orchestrator/brain-coordinator.js +0 -186
  250. package/src/orchestrator/ci-integration.js +0 -139
  251. package/src/orchestrator/config-init.js +0 -426
  252. package/src/orchestrator/direct-actions.js +0 -217
  253. package/src/orchestrator/drivers/error-recovery.js +0 -287
  254. package/src/orchestrator/drivers/init-context.js +0 -238
  255. package/src/orchestrator/drivers/iteration-loop.js +0 -382
  256. package/src/orchestrator/drivers/iteration-phases/coder-and-refactorer.js +0 -69
  257. package/src/orchestrator/drivers/iteration-phases/guards.js +0 -91
  258. package/src/orchestrator/drivers/iteration-phases/handle-approved.js +0 -29
  259. package/src/orchestrator/drivers/iteration-phases/quality-gates.js +0 -125
  260. package/src/orchestrator/drivers/iteration-phases/reviewer-gate.js +0 -62
  261. package/src/orchestrator/drivers/post-loop.js +0 -404
  262. package/src/orchestrator/drivers/pre-loop-phases/auto-hu-batch.js +0 -137
  263. package/src/orchestrator/drivers/pre-loop-phases/config-deprecations.js +0 -47
  264. package/src/orchestrator/drivers/pre-loop-phases/ensure-addyosmani-skills.js +0 -84
  265. package/src/orchestrator/drivers/pre-loop-phases/inject-loaded-plan.js +0 -393
  266. package/src/orchestrator/drivers/pre-loop.js +0 -524
  267. package/src/orchestrator/drivers/run-hu-batch.js +0 -468
  268. package/src/orchestrator/feedback-enrichment.js +0 -140
  269. package/src/orchestrator/feedback-queue.js +0 -151
  270. package/src/orchestrator/flow-control.js +0 -170
  271. package/src/orchestrator/flow-runner.js +0 -365
  272. package/src/orchestrator/fs-leak-detector.js +0 -228
  273. package/src/orchestrator/hu-scheduler.js +0 -114
  274. package/src/orchestrator/hu-sub-pipeline.js +0 -642
  275. package/src/orchestrator/iteration-gate.js +0 -73
  276. package/src/orchestrator/iteration-stages.js +0 -9
  277. package/src/orchestrator/parallel-limiter.js +0 -74
  278. package/src/orchestrator/pipeline-context.js +0 -72
  279. package/src/orchestrator/post-loop-stages.js +0 -468
  280. package/src/orchestrator/pre-loop-stages.js +0 -11
  281. package/src/orchestrator/preflight-checks.js +0 -487
  282. package/src/orchestrator/repair/repair-detector.js +0 -117
  283. package/src/orchestrator/repair/repair-runner.js +0 -142
  284. package/src/orchestrator/reviewer-fallback.js +0 -45
  285. package/src/orchestrator/role-output-compressor.js +0 -189
  286. package/src/orchestrator/session-journal.js +0 -308
  287. package/src/orchestrator/solomon-escalation.js +0 -331
  288. package/src/orchestrator/solomon-rules.js +0 -212
  289. package/src/orchestrator/stages/acceptance-coverage-stage.js +0 -47
  290. package/src/orchestrator/stages/architect-stage.js +0 -172
  291. package/src/orchestrator/stages/coder-stage.js +0 -506
  292. package/src/orchestrator/stages/domain-curator-stage.js +0 -82
  293. package/src/orchestrator/stages/format-stage.js +0 -61
  294. package/src/orchestrator/stages/hu-reviewer-phases/detect-and-apply-splits.js +0 -127
  295. package/src/orchestrator/stages/hu-reviewer-stage.js +0 -419
  296. package/src/orchestrator/stages/perf-stage.js +0 -140
  297. package/src/orchestrator/stages/planner-stage.js +0 -85
  298. package/src/orchestrator/stages/rag-context-stage.js +0 -80
  299. package/src/orchestrator/stages/rag-preload-decisor.js +0 -58
  300. package/src/orchestrator/stages/research-stage.js +0 -69
  301. package/src/orchestrator/stages/reviewer-stage.js +0 -431
  302. package/src/orchestrator/stages/sonar-stage.js +0 -439
  303. package/src/orchestrator/stages/stage-classes.js +0 -84
  304. package/src/orchestrator/stages/stage-executor.js +0 -155
  305. package/src/orchestrator/stages/suite-green-stage.js +0 -62
  306. package/src/orchestrator/stages/tdd-discipline-stage.js +0 -56
  307. package/src/orchestrator/stages/tool-judge-stage.js +0 -53
  308. package/src/orchestrator/stages/triage-stage.js +0 -172
  309. package/src/orchestrator/standby.js +0 -71
  310. package/src/orchestrator/verification-gate.js +0 -183
  311. package/src/orchestrator.js +0 -22
  312. package/src/plan/adr-generator.js +0 -170
  313. package/src/plan/adr-loader.js +0 -60
  314. package/src/plan/plan-executor.js +0 -100
  315. package/src/plan/plan-validation.js +0 -4
  316. package/src/prompts/acceptance-coverage.js +0 -32
  317. package/src/prompts/arbiter.js +0 -38
  318. package/src/prompts/architect.js +0 -103
  319. package/src/prompts/hu-reviewer.js +0 -244
  320. package/src/prompts/tool-correctness-judge.js +0 -31
  321. package/src/prompts/triage.js +0 -57
  322. package/src/rag/embedder.js +0 -2
  323. package/src/rag/embedders/_cloud-base.js +0 -2
  324. package/src/rag/embedders/cohere.js +0 -2
  325. package/src/rag/embedders/mistral.js +0 -2
  326. package/src/rag/embedders/onnx.js +0 -2
  327. package/src/rag/embedders/openai.js +0 -2
  328. package/src/rag/embedders/voyage.js +0 -2
  329. package/src/rag/rerank.js +0 -4
  330. package/src/rag/where-parser.js +0 -4
  331. package/src/repeat-detector.js +0 -88
  332. package/src/review/diff-generator.js +0 -112
  333. package/src/review/git-stash-helper.js +0 -104
  334. package/src/review/schema.js +0 -31
  335. package/src/review/scope-filter.js +0 -152
  336. package/src/review/snapshot-diff.js +0 -122
  337. package/src/review/tdd-discipline.js +0 -90
  338. package/src/review/tdd-policy.js +0 -69
  339. package/src/roles/acceptance-coverage-role.js +0 -78
  340. package/src/roles/architect-role.js +0 -77
  341. package/src/roles/coder-role.js +0 -113
  342. package/src/roles/commiter-role.js +0 -113
  343. package/src/roles/domain-curator-role.js +0 -134
  344. package/src/roles/hu-reviewer-role.js +0 -64
  345. package/src/roles/impeccable-role.js +0 -85
  346. package/src/roles/index.js +0 -18
  347. package/src/roles/karajan-brain-role.js +0 -134
  348. package/src/roles/perf-role.js +0 -122
  349. package/src/roles/planner-role.js +0 -151
  350. package/src/roles/refactorer-role.js +0 -30
  351. package/src/roles/repairer-role.js +0 -181
  352. package/src/roles/researcher-role.js +0 -70
  353. package/src/roles/reviewer-role.js +0 -115
  354. package/src/roles/security-role.js +0 -73
  355. package/src/roles/solomon-role.js +0 -271
  356. package/src/roles/sonar-role.js +0 -72
  357. package/src/roles/tester-role.js +0 -235
  358. package/src/roles/tool-correctness-judge-role.js +0 -78
  359. package/src/roles/triage-role.js +0 -99
  360. package/src/session/journal/decisions-writer.js +0 -200
  361. package/src/session/journal/iteration-logger.js +0 -194
  362. package/src/session/journal/summary-writer.js +0 -320
  363. package/src/session/journal/tree-writer.js +0 -164
  364. package/src/session/journal/write-all.js +0 -89
  365. package/src/session-cleanup.js +0 -116
  366. package/src/skills/semantic-detector.js +0 -167
  367. package/src/skills/skill-detector.js +0 -385
  368. package/src/sonar/cloud-scanner.js +0 -78
  369. package/src/tracker-bootstrap.js +0 -44
  370. package/src/types/index.js +0 -38
  371. package/src/types/policy.js +0 -43
  372. package/src/types/solomon.js +0 -87
  373. package/src/utils/async-lock.js +0 -31
  374. package/src/utils/budget.js +0 -229
  375. package/src/utils/cwd-confirm.js +0 -39
  376. package/src/utils/display/event-handlers.js +0 -403
  377. package/src/utils/display/formatters.js +0 -132
  378. package/src/utils/display/header.js +0 -47
  379. package/src/utils/display/session-summary.js +0 -118
  380. package/src/utils/display/solomon.js +0 -42
  381. package/src/utils/pricing.js +0 -29
  382. package/src/utils/quota-simulator.js +0 -56
  383. package/src/utils/role-assigner.js +0 -137
  384. package/src/utils/rtk-wrapper.js +0 -87
  385. package/src/utils/run-registry.js +0 -9
  386. package/src/utils/status-dashboard.js +0 -254
  387. package/src/utils/tool-call-extractor.js +0 -56
  388. package/src/webperf/devtools-detect.js +0 -112
  389. package/src/webperf/webperf-role-integration.js +0 -66
  390. package/templates/skills/kj-run.md +0 -73
@@ -1,12 +1,11 @@
1
1
  /**
2
- * Native build availability check (KJC-BUG-0092).
2
+ * Native module check (KJC-BUG-0092, KJC-TSK-1353).
3
3
  *
4
- * better-sqlite3 ships a native addon compiled in a postinstall step. pnpm
5
- * blocks dependency build scripts by default (ERR_PNPM_IGNORED_BUILDS), so a
6
- * `pnpm add -g karajan-code` leaves the addon uncompiled: `kj --version` still
7
- * works (it never opens a DB) but any DB-backed command (board, rag, cost
8
- * tracking) crashes with "Cannot find module 'better-sqlite3'". This surfaces a
9
- * WARN in `kj doctor` with the exact remedy instead of a cryptic runtime crash.
4
+ * node-pty is kj's only native module since better-sqlite3 left (KJC-TSK-1353:
5
+ * every SQLite store runs on node:sqlite, built into Node). It is optional: it
6
+ * powers the HU Board's terminal. Where it needs its install script, pnpm
7
+ * (ERR_PNPM_IGNORED_BUILDS) and npm 12 (allowScripts) block it by default, so
8
+ * `kj doctor` warns with the exact remedy instead of a broken terminal.
10
9
  */
11
10
 
12
11
  import { execFileSync } from "node:child_process";
@@ -32,19 +31,7 @@ function defaultNpmMajor() {
32
31
  * allowScripts covers it; reinstalling blocks it again. Approve, then rebuild, in kj's dir.
33
32
  */
34
33
  export const npmAllowScriptsRemedy = (pkgDir = OWN_PKG_DIR) =>
35
- `cd "${pkgDir}" && npm install-scripts approve better-sqlite3 && npm install-scripts approve node-pty && npm rebuild better-sqlite3 node-pty`;
36
-
37
- // The addon is installed but its native build is missing (a missing package needs a reinstall, not this).
38
- const UNBUILT_ADDON = /bindings file|better_sqlite3\.node/;
39
-
40
- /** A missing better-sqlite3 addon becomes an error that says how to build it; any other error passes as it is. */
41
- export function explainNativeLoadError(err, { npmMajor = defaultNpmMajor, pkgDir = OWN_PKG_DIR } = {}) {
42
- if (!UNBUILT_ADDON.test(String(err?.message ?? err))) return err;
43
- const remedy = (npmMajor() ?? 0) >= 12
44
- ? `npm 12 skipped its install script (allowScripts); build it with: ${npmAllowScriptsRemedy(pkgDir)}`
45
- : "run kj doctor for the exact fix on this install";
46
- return new Error(`better-sqlite3 native addon is not built, so the RAG cannot open its index — ${remedy}`, { cause: err });
47
- }
34
+ `cd "${pkgDir}" && npm install-scripts approve node-pty && npm rebuild node-pty`;
48
35
 
49
36
  /** pnpm lays packages out under a `.pnpm` virtual store and symlinks them in. */
50
37
  function isPnpmInstall() {
@@ -54,50 +41,45 @@ function isPnpmInstall() {
54
41
  );
55
42
  }
56
43
 
57
- /** Force the native binding to load by opening an in-memory database. */
58
- async function defaultLoadDb() {
59
- const Database = (await import("better-sqlite3")).default;
60
- new Database(":memory:").close();
44
+ /** Load node-pty's native binding. */
45
+ async function defaultLoadPty() {
46
+ await import("node-pty");
61
47
  }
62
48
 
63
- export function createNativeBuildCheck({ loadDb = defaultLoadDb, isPnpm = isPnpmInstall, npmMajor = defaultNpmMajor, pkgDir = OWN_PKG_DIR } = {}) {
49
+ const NO_TERMINAL = "the HU Board terminal is unavailable (everything else works)";
50
+
51
+ export function createNativeBuildCheck({ loadPty = defaultLoadPty, isPnpm = isPnpmInstall, npmMajor = defaultNpmMajor, pkgDir = OWN_PKG_DIR } = {}) {
64
52
  return {
65
53
  name: "native-build",
66
- label: "native modules (better-sqlite3)",
54
+ label: "native modules (node-pty)",
67
55
  strategy: STRATEGY.MANUAL,
68
56
  async detect() {
69
57
  try {
70
- await loadDb();
71
- return {
72
- ok: true,
73
- severity: "info",
74
- detail: "better-sqlite3 native addon loads — DB-backed commands available",
75
- };
58
+ await loadPty();
59
+ return { ok: true, severity: "info", detail: "node-pty loads — the HU Board terminal is available" };
76
60
  } catch (err) {
77
61
  const firstLine = String(err?.message || err).split("\n")[0];
78
62
  if (isPnpm()) {
79
63
  return {
80
64
  ok: false,
81
65
  severity: "warn",
82
- detail: "better-sqlite3 native build was skipped — pnpm blocks dependency build scripts by default",
83
- fix: "Approve the build then reinstall: `pnpm approve-builds better-sqlite3` — or install with npm: `npm i -g @karajan-family/code`",
66
+ detail: `node-pty native build was skipped — pnpm blocks dependency build scripts by default; ${NO_TERMINAL}`,
67
+ fix: "Approve the build then reinstall: `pnpm approve-builds node-pty` — or install with npm: `npm i -g @karajan-family/code`",
84
68
  };
85
69
  }
86
70
  if ((npmMajor() ?? 0) >= 12) {
87
71
  return {
88
72
  ok: false,
89
73
  severity: "warn",
90
- detail: `better-sqlite3 failed to load: ${firstLine} — npm 12 skips dependency install scripts that allowScripts does not cover, so the native build never ran`,
74
+ detail: `node-pty failed to load: ${firstLine} — npm 12 skips dependency install scripts that allowScripts does not cover; ${NO_TERMINAL}`,
91
75
  fix: npmAllowScriptsRemedy(pkgDir),
92
76
  };
93
77
  }
94
78
  return {
95
79
  ok: false,
96
80
  severity: "warn",
97
- // KJC-BUG-0118: the standalone (curl) binary ships without native
98
- // modules by design — name the consequence (RAG/board/MCP need the
99
- // npm install) instead of implying the install is broken.
100
- detail: `better-sqlite3 failed to load: ${firstLine} — DB-backed features (RAG, board, MCP) unavailable; the standalone binary does not bundle native modules`,
81
+ // KJC-BUG-0118: the standalone (curl) binary ships without native modules by design.
82
+ detail: `node-pty failed to load: ${firstLine} — ${NO_TERMINAL}; the standalone binary does not bundle native modules`,
101
83
  fix: "Reinstall to rebuild native modules: `npm i -g @karajan-family/code`",
102
84
  };
103
85
  }
@@ -51,162 +51,25 @@ export async function runChecks(checks, ctx, options = {}) {
51
51
 
52
52
  const { config } = ctx;
53
53
  const startTotal = Date.now();
54
- const entries = [];
54
+ const entries = checks.map((check) => entryFor(check, config));
55
55
  const overrides = {};
56
56
 
57
- // Build applicable entries (skipped checks noted up front).
58
- // A check.applies(config) may return:
59
- // - true / false — boolean form (back-compat).
60
- // - an object { applies: boolean, reason?: string } — when false, `reason`
61
- // is shown verbatim so users see WHY (e.g. "sonarqube.enabled is false
62
- // in kj.config.yml") instead of the opaque "Not applicable" message
63
- // that confused users debugging their config.
64
- for (const check of checks) {
65
- if (typeof check.applies !== "function") {
66
- entries.push({ check, status: null, detail: null, runMs: 0, detectResult: null, remediated: false });
67
- continue;
68
- }
69
- const verdict = check.applies(config);
70
- const isObj = verdict && typeof verdict === "object" && "applies" in verdict;
71
- const applies = isObj ? Boolean(verdict.applies) : Boolean(verdict);
72
- if (applies) {
73
- entries.push({ check, status: null, detail: null, runMs: 0, detectResult: null, remediated: false });
74
- continue;
75
- }
76
- const reason = (isObj && typeof verdict.reason === "string" && verdict.reason.trim())
77
- ? verdict.reason.trim()
78
- : "Not applicable for current configuration";
79
- entries.push({
80
- check,
81
- status: STATUS.SKIPPED,
82
- detail: reason,
83
- runMs: 0,
84
- detectResult: null,
85
- remediated: false,
86
- });
87
- }
88
-
89
57
  // Phase 1: detect in parallel with timeout.
90
58
  const detectBase = Date.now();
91
- await Promise.all(
92
- entries.map(async (entry) => {
93
- if (entry.status === STATUS.SKIPPED) return;
94
- const start = Date.now();
95
- // Per-check override: checks that spawn slow tools (e.g. `npx <pkg>` cold
96
- // start) declare detectTimeoutMs so the blanket pipeline timeout doesn't
97
- // kill them. Falls back to the pipeline-wide timeoutMs.
98
- const detectTimeoutMs = Number.isFinite(entry.check.detectTimeoutMs)
99
- ? entry.check.detectTimeoutMs
100
- : timeoutMs;
101
- try {
102
- const result = await withTimeout(entry.check.detect({ config, signal }), detectTimeoutMs, entry.check.name);
103
- entry.detectResult = result;
104
- entry.runMs = Date.now() - start;
105
- entry.status = resolveStatusFromDetect(entry.check, result);
106
- entry.detail = result.detail;
107
- // KJC-BUG-0049: si el check es degradable y falló (status FAIL/WARN tras
108
- // resolveStatusFromDetect), aplicar disables al overrides y degradar a WARN.
109
- // Así el preflight no aborta — la feature opcional se desactiva con aviso.
110
- if (!result.ok && entry.check.degradable && (entry.status === STATUS.FAIL || entry.status === STATUS.WARN)) {
111
- for (const dotPath of entry.check.degradable.disables || []) {
112
- setDotPath(overrides, dotPath, false);
113
- }
114
- entry.status = STATUS.WARN;
115
- entry.detail = `${result.detail} → ${entry.check.degradable.warn}`;
116
- entry.degraded = true;
117
- }
118
- } catch (err) {
119
- entry.runMs = Date.now() - start;
120
- if (err instanceof TimeoutError) {
121
- entry.detectResult = { ok: false, severity: "warn", detail: `Timeout after ${detectTimeoutMs}ms` };
122
- // A timeout on a degradable (optional) check must not block the
123
- // pipeline: degrade to WARN and disable its feature flags, same as
124
- // a regular failure (KJC-BUG-0049 semantics).
125
- if (entry.check.degradable) {
126
- for (const dotPath of entry.check.degradable.disables || []) {
127
- setDotPath(overrides, dotPath, false);
128
- }
129
- entry.status = STATUS.WARN;
130
- entry.detail = `${entry.detectResult.detail} → ${entry.check.degradable.warn}`;
131
- entry.degraded = true;
132
- } else {
133
- entry.status = STATUS.TIMEOUT;
134
- entry.detail = entry.detectResult.detail;
135
- }
136
- } else {
137
- entry.detectResult = { ok: false, severity: "fail", detail: `Detection error: ${err.message}` };
138
- entry.status = STATUS.FAIL;
139
- entry.detail = entry.detectResult.detail;
140
- }
141
- }
142
- })
143
- );
59
+ await Promise.all(entries.map((entry) => detectEntry(entry, { config, signal, timeoutMs, overrides })));
144
60
  logger.info?.(`Detect phase done in ${Date.now() - detectBase}ms`);
145
61
 
146
- // Phase 2: remediate sequentially (only in "fix" mode, only failing checks).
147
62
  if (mode !== "check-only") {
63
+ // Phase 2: remediate sequentially (only in "fix" mode, only failing checks).
148
64
  for (const entry of entries) {
149
- if (!shouldAttemptRemediation(entry)) continue;
150
- const { check, detectResult } = entry;
151
- if (check.strategy === STRATEGY.PROMPT && !yes) {
152
- const approved = await onConfirm(check.describe || `Fix: ${check.name}`);
153
- if (!approved) {
154
- logger.info?.(`User declined remediation for ${check.name}`);
155
- continue;
156
- }
157
- }
158
- const start = Date.now();
159
- try {
160
- const rem = await withTimeout(
161
- check.remediate({ config, extra: detectResult.extra, signal, logger }),
162
- remediateTimeoutMs,
163
- `${check.name}:remediate`
164
- );
165
- entry.remediated = rem.fixed === true;
166
- entry.runMs += Date.now() - start;
167
- if (rem.fixed) {
168
- if (rem.changes) mergeOverrides(overrides, rem.changes);
169
- entry.detail = rem.detail;
170
- entry.status = STATUS.FIXED;
171
- } else {
172
- entry.detail = rem.detail || entry.detail;
173
- entry.status = STATUS.FAIL;
174
- }
175
- } catch (err) {
176
- entry.runMs += Date.now() - start;
177
- const msg = err instanceof TimeoutError ? `Remediation timeout after ${remediateTimeoutMs}ms` : `Remediation error: ${err.message}`;
178
- entry.detail = msg;
179
- entry.status = STATUS.FAIL;
180
- logger.warn?.(`Remediation failed for ${check.name}: ${msg}`);
181
- }
65
+ if (shouldAttemptRemediation(entry)) await remediateEntry(entry, { config, signal, logger, yes, onConfirm, remediateTimeoutMs, overrides });
182
66
  }
183
-
184
67
  // Phase 3: re-verify fixed checks using the config merged with any
185
68
  // runtime overrides applied by remediations. Without this merge, a check
186
69
  // that rebinds to a new port (override) would re-verify against the old
187
70
  // config and wrongly report failure.
188
71
  const verifyConfig = mergeConfigAndOverrides(config, overrides);
189
- await Promise.all(
190
- entries.filter((e) => e.remediated).map(async (entry) => {
191
- const start = Date.now();
192
- try {
193
- const result = await withTimeout(
194
- entry.check.detect({ config: verifyConfig, signal }),
195
- Number.isFinite(entry.check.detectTimeoutMs) ? entry.check.detectTimeoutMs : timeoutMs,
196
- `${entry.check.name}:reverify`
197
- );
198
- entry.runMs += Date.now() - start;
199
- if (!result.ok) {
200
- entry.status = STATUS.FAIL;
201
- entry.detail = `${entry.detail} (but re-verify failed: ${result.detail})`;
202
- }
203
- } catch (err) {
204
- entry.runMs += Date.now() - start;
205
- entry.status = STATUS.FAIL;
206
- entry.detail = `${entry.detail} (re-verify error: ${err.message})`;
207
- }
208
- })
209
- );
72
+ await Promise.all(entries.filter((e) => e.remediated).map((entry) => reverifyEntry(entry, { verifyConfig, signal, timeoutMs })));
210
73
  }
211
74
 
212
75
  // Flatten into reports.
@@ -234,6 +97,129 @@ export async function runChecks(checks, ctx, options = {}) {
234
97
  };
235
98
  }
236
99
 
100
+ // Build an applicable entry (skipped checks noted up front).
101
+ // A check.applies(config) may return:
102
+ // - true / false — boolean form (back-compat).
103
+ // - an object { applies: boolean, reason?: string } — when false, `reason`
104
+ // is shown verbatim so users see WHY (e.g. "sonarqube.enabled is false
105
+ // in kj.config.yml") instead of the opaque "Not applicable" message
106
+ // that confused users debugging their config.
107
+ function entryFor(check, config) {
108
+ const entry = { check, status: null, detail: null, runMs: 0, detectResult: null, remediated: false };
109
+ if (typeof check.applies !== "function") return entry;
110
+ const verdict = check.applies(config);
111
+ const isObj = verdict && typeof verdict === "object" && "applies" in verdict;
112
+ const applies = isObj ? Boolean(verdict.applies) : Boolean(verdict);
113
+ if (applies) return entry;
114
+ const reason = (isObj && typeof verdict.reason === "string" && verdict.reason.trim())
115
+ ? verdict.reason.trim()
116
+ : "Not applicable for current configuration";
117
+ return { ...entry, status: STATUS.SKIPPED, detail: reason };
118
+ }
119
+
120
+ // Per-check override: checks that spawn slow tools (e.g. `npx <pkg>` cold
121
+ // start) declare detectTimeoutMs so the blanket pipeline timeout doesn't
122
+ // kill them. Falls back to the pipeline-wide timeoutMs.
123
+ const detectTimeoutOf = (check, timeoutMs) => (Number.isFinite(check.detectTimeoutMs) ? check.detectTimeoutMs : timeoutMs);
124
+
125
+ // KJC-BUG-0049: an optional (degradable) check that fails or times out does not
126
+ // block the pipeline: its feature flags are disabled and it degrades to WARN.
127
+ function degrade(entry, overrides, detail) {
128
+ for (const dotPath of entry.check.degradable.disables || []) {
129
+ setDotPath(overrides, dotPath, false);
130
+ }
131
+ entry.status = STATUS.WARN;
132
+ entry.detail = `${detail} → ${entry.check.degradable.warn}`;
133
+ entry.degraded = true;
134
+ }
135
+
136
+ async function detectEntry(entry, { config, signal, timeoutMs, overrides }) {
137
+ if (entry.status === STATUS.SKIPPED) return;
138
+ const start = Date.now();
139
+ const detectTimeoutMs = detectTimeoutOf(entry.check, timeoutMs);
140
+ try {
141
+ const result = await withTimeout(entry.check.detect({ config, signal }), detectTimeoutMs, entry.check.name);
142
+ entry.detectResult = result;
143
+ entry.runMs = Date.now() - start;
144
+ entry.status = resolveStatusFromDetect(entry.check, result);
145
+ entry.detail = result.detail;
146
+ // Así el preflight no aborta — la feature opcional se desactiva con aviso.
147
+ if (!result.ok && entry.check.degradable && (entry.status === STATUS.FAIL || entry.status === STATUS.WARN)) {
148
+ degrade(entry, overrides, result.detail);
149
+ }
150
+ } catch (err) {
151
+ entry.runMs = Date.now() - start;
152
+ if (!(err instanceof TimeoutError)) {
153
+ entry.detectResult = { ok: false, severity: "fail", detail: `Detection error: ${err.message}` };
154
+ entry.status = STATUS.FAIL;
155
+ entry.detail = entry.detectResult.detail;
156
+ return;
157
+ }
158
+ entry.detectResult = { ok: false, severity: "warn", detail: `Timeout after ${detectTimeoutMs}ms` };
159
+ if (entry.check.degradable) {
160
+ degrade(entry, overrides, entry.detectResult.detail);
161
+ } else {
162
+ entry.status = STATUS.TIMEOUT;
163
+ entry.detail = entry.detectResult.detail;
164
+ }
165
+ }
166
+ }
167
+
168
+ async function remediateEntry(entry, { config, signal, logger, yes, onConfirm, remediateTimeoutMs, overrides }) {
169
+ const { check, detectResult } = entry;
170
+ if (check.strategy === STRATEGY.PROMPT && !yes) {
171
+ const approved = await onConfirm(check.describe || `Fix: ${check.name}`);
172
+ if (!approved) {
173
+ logger.info?.(`User declined remediation for ${check.name}`);
174
+ return;
175
+ }
176
+ }
177
+ const start = Date.now();
178
+ try {
179
+ const rem = await withTimeout(
180
+ check.remediate({ config, extra: detectResult.extra, signal, logger }),
181
+ remediateTimeoutMs,
182
+ `${check.name}:remediate`
183
+ );
184
+ entry.remediated = rem.fixed === true;
185
+ entry.runMs += Date.now() - start;
186
+ if (rem.fixed) {
187
+ if (rem.changes) mergeOverrides(overrides, rem.changes);
188
+ entry.detail = rem.detail;
189
+ entry.status = STATUS.FIXED;
190
+ } else {
191
+ entry.detail = rem.detail || entry.detail;
192
+ entry.status = STATUS.FAIL;
193
+ }
194
+ } catch (err) {
195
+ entry.runMs += Date.now() - start;
196
+ const msg = err instanceof TimeoutError ? `Remediation timeout after ${remediateTimeoutMs}ms` : `Remediation error: ${err.message}`;
197
+ entry.detail = msg;
198
+ entry.status = STATUS.FAIL;
199
+ logger.warn?.(`Remediation failed for ${check.name}: ${msg}`);
200
+ }
201
+ }
202
+
203
+ async function reverifyEntry(entry, { verifyConfig, signal, timeoutMs }) {
204
+ const start = Date.now();
205
+ try {
206
+ const result = await withTimeout(
207
+ entry.check.detect({ config: verifyConfig, signal }),
208
+ detectTimeoutOf(entry.check, timeoutMs),
209
+ `${entry.check.name}:reverify`
210
+ );
211
+ entry.runMs += Date.now() - start;
212
+ if (!result.ok) {
213
+ entry.status = STATUS.FAIL;
214
+ entry.detail = `${entry.detail} (but re-verify failed: ${result.detail})`;
215
+ }
216
+ } catch (err) {
217
+ entry.runMs += Date.now() - start;
218
+ entry.status = STATUS.FAIL;
219
+ entry.detail = `${entry.detail} (re-verify error: ${err.message})`;
220
+ }
221
+ }
222
+
237
223
  function shouldAttemptRemediation(entry) {
238
224
  if (entry.status === STATUS.SKIPPED) return false;
239
225
  if (entry.status === STATUS.OK) return false;
@@ -13,9 +13,9 @@ export const CORE_COMMANDS = [
13
13
  // gets — it is the first command a new project ever runs.
14
14
  "bootstrap",
15
15
  "init",
16
- "run",
16
+ "hu",
17
+ "review",
17
18
  "plan",
18
- "status",
19
19
  "doctor",
20
20
  "harden",
21
21
  "config",
@@ -31,11 +31,11 @@ export const META_COMMANDS = ["advanced", "help"];
31
31
  * so a newly-registered command can never silently vanish from `kj advanced`.
32
32
  */
33
33
  export const ADVANCED_GROUPS = [
34
- { title: "Pipeline (piezas sueltas)", commands: ["autorun", "code", "review", "solomon", "agent", "scan", "tournament"] },
35
- { title: "Análisis pre-run", commands: ["discover", "spec", "triage", "researcher", "architect", "onboard", "brief"] },
34
+ { title: "Agentes y revisión", commands: ["code", "solomon", "agent", "scan", "tournament"] },
35
+ { title: "Análisis previo", commands: ["discover", "spec", "onboard", "brief"] },
36
36
  { title: "Búsqueda / RAG", commands: ["rag", "qmd", "watch", "doc"] },
37
- { title: "Calidad / auditoría", commands: ["audit", "check", "mutate", "webperf", "sonar", "privacy", "release", "policy", "rules", "rulesync", "claims", "steward", "pr-size"] },
38
- { title: "Sesión / board", commands: ["resume", "report", "board", "hu", "adr", "worktree", "undo", "standby", "sentinel", "identity", "security", "handoff"] },
37
+ { title: "Calidad / auditoría", commands: ["audit", "check", "mutate", "webperf", "sonar", "privacy", "release", "policy", "rules", "rulesync", "claims", "steward", "pr-size", "main-guard"] },
38
+ { title: "Sesión / board", commands: ["report", "board", "adr", "worktree", "sentinel", "identity", "security", "handoff"] },
39
39
  { title: "Infra / setup", commands: ["install-tools", "ollama", "skills", "roles", "agents", "env"] },
40
40
  { title: "Mantenimiento", commands: ["clean", "sync", "telemetry", "report-issue"] },
41
41
  ];
@@ -1,8 +1,6 @@
1
1
  import { discoverCommand } from "../commands/discover.js";
2
2
  import { specRefineCommand } from "../commands/spec-refine.js";
3
- import { triageCommand } from "../commands/triage.js";
4
- import { researcherCommand } from "../commands/researcher.js";
5
- import { architectCommand } from "../commands/architect.js";
3
+ import { writeSbom } from "../audit/sbom.js";
6
4
  import { onboardCommand } from "../commands/onboard.js";
7
5
  import { startCommand } from "../commands/start.js";
8
6
  import { goCommand } from "../commands/go.js";
@@ -19,10 +17,8 @@ import { qmdQueryCommand } from "../commands/qmd.js";
19
17
  import { ragMcpCommand } from "../commands/rag-mcp.js";
20
18
  import { watchStartCommand, watchStopCommand, watchStatusCommand } from "../commands/watch.js";
21
19
  import { auditCommand } from "../commands/audit.js";
22
- import { resumeCommand } from "../commands/resume.js";
23
20
  import { boardCommand } from "../commands/board.js";
24
21
  import { webperfCommand } from "../commands/webperf.js";
25
- import { undoCommand } from "../commands/undo.js";
26
22
  import { syncCommand } from "../commands/sync.js";
27
23
  import { cleanCommand } from "../commands/clean.js";
28
24
  import { checkCommand } from "../commands/check.js";
@@ -106,54 +102,6 @@ export function registerMeta(program, { pkgVersion }) {
106
102
  });
107
103
  });
108
104
 
109
- program
110
- .command("triage")
111
- .description("Classify task complexity and recommend pipeline roles")
112
- .argument("[task]", "Task description (REQUIRED — provide as argument or via --task-file)")
113
- .option("--task-file <path>", "Read the task from a file (e.g. .md)")
114
- .option("--triage <name>", "Override triage agent")
115
- .option("--triage-model <name>", "Override triage model")
116
- .option("--json", "Output raw JSON")
117
- .action(async (task, flags) => {
118
- await withConfig(pkgVersion, "triage", flags, async ({ config, logger }) => {
119
- const { resolveTaskInput } = await import("../utils/task-file.js");
120
- const resolvedTask = await resolveTaskInput({ task, taskFile: flags.taskFile, projectDir: config.projectDir, logger, indexFirstBytes: config.docs?.indexFirstBytes });
121
- await triageCommand({ task: resolvedTask, config, logger, json: flags.json });
122
- });
123
- });
124
-
125
- program
126
- .command("researcher")
127
- .description("Research codebase for a task (files, patterns, constraints)")
128
- .argument("[task]", "Task description (REQUIRED — provide as argument or via --task-file)")
129
- .option("--task-file <path>", "Read the task from a file (e.g. .md)")
130
- .option("--researcher <name>", "Override researcher agent")
131
- .option("--researcher-model <name>", "Override researcher model")
132
- .action(async (task, flags) => {
133
- await withConfig(pkgVersion, "researcher", flags, async ({ config, logger }) => {
134
- const { resolveTaskInput } = await import("../utils/task-file.js");
135
- const resolvedTask = await resolveTaskInput({ task, taskFile: flags.taskFile, projectDir: config.projectDir, logger, indexFirstBytes: config.docs?.indexFirstBytes });
136
- await researcherCommand({ task: resolvedTask, config, logger });
137
- });
138
- });
139
-
140
- program
141
- .command("architect")
142
- .description("Design solution architecture (layers, patterns, contracts)")
143
- .argument("[task]", "Task description (REQUIRED — provide as argument or via --task-file)")
144
- .option("--task-file <path>", "Read the task from a file (e.g. .md)")
145
- .option("--architect <name>", "Override architect agent")
146
- .option("--architect-model <name>", "Override architect model")
147
- .option("--context <text>", "Additional context (e.g. researcher output)")
148
- .option("--json", "Output raw JSON")
149
- .action(async (task, flags) => {
150
- await withConfig(pkgVersion, "architect", flags, async ({ config, logger }) => {
151
- const { resolveTaskInput } = await import("../utils/task-file.js");
152
- const resolvedTask = await resolveTaskInput({ task, taskFile: flags.taskFile, projectDir: config.projectDir, logger, indexFirstBytes: config.docs?.indexFirstBytes });
153
- await architectCommand({ task: resolvedTask, config, logger, context: flags.context, json: flags.json });
154
- });
155
- });
156
-
157
105
  program
158
106
  .command("onboard")
159
107
  .description("Analyze an existing codebase (brownfield) and produce an Architecture Brief")
@@ -317,7 +265,7 @@ export function registerMeta(program, { pkgVersion }) {
317
265
  // beats ordering a practice an agent can narrate without doing.
318
266
  const wt = program.command("worktree").description("Isolated task lanes (git worktrees) for the host agent");
319
267
  wt.command("start <slug>")
320
- .description("Create a lane: worktree + feat/<slug> branch + dependency bootstrap")
268
+ .description("Create a lane: worktree + feat/<slug> branch from origin/<base> + dependency bootstrap")
321
269
  .action(async (slug, flags) => {
322
270
  await withConfig(pkgVersion, "worktree", flags, async ({ config }) => {
323
271
  await worktreeCommand({ config, action: "start", args: [slug], flags });
@@ -325,14 +273,16 @@ export function registerMeta(program, { pkgVersion }) {
325
273
  });
326
274
  wt.command("list")
327
275
  .description("List the active lanes")
276
+ .option("--json", "Each lane with its commits ahead of the base and the cards its branch names")
277
+ .option("--prs", "With --json, each lane's PR (one gh call)")
328
278
  .action(async (flags) => {
329
279
  await withConfig(pkgVersion, "worktree", flags, async ({ config }) => {
330
280
  await worktreeCommand({ config, action: "list", flags });
331
281
  });
332
282
  });
333
283
  wt.command("done <slug>")
334
- .option("--force", "Remove the lane even with uncommitted changes")
335
- .description("Remove a merged lane (refuses uncommitted changes without --force)")
284
+ .option("--force", "Remove the lane even with uncommitted changes, and delete its branch even if not merged")
285
+ .description("Remove a lane and delete its branch when merged into the base (refuses uncommitted changes without --force)")
336
286
  .action(async (slug, flags) => {
337
287
  await withConfig(pkgVersion, "worktree", flags, async ({ config }) => {
338
288
  await worktreeCommand({ config, action: "done", args: [slug], flags });
@@ -372,6 +322,16 @@ export function registerMeta(program, { pkgVersion }) {
372
322
  await huCommand({ config, action: "move", args: [id, status], flags });
373
323
  });
374
324
  });
325
+ // KJC-TSK-1372 (#2853): one step to start a task: card, lane, running.
326
+ hu.command("start <id> [slug]")
327
+ .description("Start a card: open its lane feat/<id>-<slug> from origin/<base> and move it to running (slug from the title if omitted)")
328
+ .option("--code", "Then have the panel coder write the card in the lane (kj code --card)")
329
+ .option("--json", "Machine-readable output")
330
+ .action(async (id, slug, flags) => {
331
+ await withConfig(pkgVersion, "hu", flags, async ({ config }) => {
332
+ await huCommand({ config, action: "start", args: [id, slug].filter(Boolean), flags });
333
+ });
334
+ });
375
335
  hu.command("list")
376
336
  .option("--json", "Machine-readable output")
377
337
  .action(async (flags) => {
@@ -801,6 +761,19 @@ export function registerMeta(program, { pkgVersion }) {
801
761
  });
802
762
  });
803
763
 
764
+ // KJC-TSK-1369 (ADR 0037): the audit job on every push to the protected branch.
765
+ program.command("main-guard")
766
+ .description("Audit a push to the protected branch: merges without their required checks, and the protection (exit 1 with a markdown report)")
767
+ .requiredOption("--repo <owner/repo>", "GitHub repository")
768
+ .requiredOption("--before <sha>", "The branch tip before the push")
769
+ .requiredOption("--after <sha>", "The branch tip after the push")
770
+ .requiredOption("--require <checks...>", "Required checks that every merge must have passed")
771
+ .option("--branch <name>", "Protected branch", "main")
772
+ .action(async (flags) => {
773
+ const { mainGuardCommand } = await import("../commands/main-guard.js");
774
+ await mainGuardCommand({ flags });
775
+ });
776
+
804
777
  const rag = program.command("rag").description("Retrieval-augmented search over Karajan plans, onboarding briefs and project code");
805
778
  rag.command("index")
806
779
  .description("Index plans + onboarding (and optionally project sources) into the local vector store")
@@ -947,8 +920,21 @@ export function registerMeta(program, { pkgVersion }) {
947
920
  .option("--deterministic-only", "Skip the LLM analysis entirely. Print/persist only the deterministic findings (basalCost, sonar, stack, growth-delta, webperf). Zero tokens spent. Compatible with --report-file and --json.")
948
921
  .option("--security", "Focused deterministic security pass: prompt-injection scan over the agent-context surface (CLAUDE.md/AGENTS.md/templates/.rulesync/.karajan) + OSV + Semgrep + Sonar. Skips basal-cost, webperf, madge, knip, ai-slop, harness and the LLM — zero tokens. Designed for agents to self-invoke when a task touches sensitive surface (KJC-TSK-0695).")
949
922
  .option("-y, --yes", "Auto-confirm the 'Continue with LLM analysis?' prompt. Useful in scripts that want the full audit non-interactively. CI/non-TTY paths already auto-confirm without this flag.")
923
+ .option("--sbom <file>", "Only write the CycloneDX SBOM of the npm project's production dependencies to <file> (from package-lock.json) and stop. KJC-TSK-1255.")
950
924
  .action(async (task, flags) => {
951
925
  await withConfig(pkgVersion, "audit", flags, async ({ config, logger }) => {
926
+ if (flags.sbom) {
927
+ try {
928
+ const res = await writeSbom({ projectDir: config.projectDir || process.cwd(), file: flags.sbom });
929
+ if (flags.json) console.log(JSON.stringify(res));
930
+ else console.log(`SBOM (CycloneDX, ${res.components} components): ${res.file}`);
931
+ } catch (err) {
932
+ if (flags.json) console.log(JSON.stringify({ error: err.message }));
933
+ else logger.error(err.message);
934
+ process.exitCode = 1;
935
+ }
936
+ return;
937
+ }
952
938
  let resolvedTask = task;
953
939
  if (flags.taskFile) {
954
940
  const { readTaskFile } = await import("../utils/task-file.js");
@@ -997,21 +983,6 @@ export function registerMeta(program, { pkgVersion }) {
997
983
  });
998
984
  });
999
985
 
1000
- program
1001
- .command("resume")
1002
- .description("Resume a paused session")
1003
- .argument("<sessionId>")
1004
- .option("--answer <text>", "Answer to the question that caused the pause")
1005
- .option("--non-interactive", "Agents/CI: auto-answer prompts with their safe defaults; stop when there is none. Also enabled by KJ_NON_INTERACTIVE=1.")
1006
- .option("--json", "Output JSON only")
1007
- .action(async (sessionId, flags) => {
1008
- await withConfig(pkgVersion, "resume", flags, async ({ config, logger }) => {
1009
- const res = await resumeCommand({ sessionId, answer: flags.answer, config, logger, flags });
1010
- // KJC-TSK-0674 (issue #1289): same contract as kj run — an aborted
1011
- // resume must be observable by CI.
1012
- if (res?.aborted) process.exitCode = 1;
1013
- });
1014
- });
1015
986
 
1016
987
  program
1017
988
  .command("update")
@@ -1061,17 +1032,6 @@ export function registerMeta(program, { pkgVersion }) {
1061
1032
  });
1062
1033
  });
1063
1034
 
1064
- program
1065
- .command("undo")
1066
- .description("Revert last pipeline run")
1067
- .option("--hard", "Discard all changes (default: soft reset, keeps changes staged)")
1068
- .action(async (flags) => {
1069
- await withConfig(pkgVersion, "undo", flags, async ({ logger }) => {
1070
- const result = await undoCommand({ hard: !!flags.hard, logger });
1071
- if (!result.ok) process.exit(1);
1072
- });
1073
- });
1074
-
1075
1035
  program
1076
1036
  .command("sync")
1077
1037
  .description("Detect drift between code and the latest plan. Read-only by default; --apply writes a patch back to the Canvas.")