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
@@ -0,0 +1,53 @@
1
+ /**
2
+ * The main checkout of the repo a dir belongs to: lanes and plans hang from it, never from a
3
+ * lane (#2566). Not the Sentinel's lane identity (ADR 0002). Outside git, the dir unchanged.
4
+ */
5
+ import fs from "node:fs";
6
+ import path from "node:path";
7
+ import { execFileSync } from "node:child_process";
8
+
9
+ // null only for "not a git repository"; any other git failure is loud, never a silent nested lane.
10
+ const gitOrNull = (args, cwd) => {
11
+ // A git hook exports GIT_DIR & co: left in, they would override `cwd` and answer for the wrong repo.
12
+ const env = { ...process.env };
13
+ for (const name of ["GIT_DIR", "GIT_WORK_TREE", "GIT_COMMON_DIR", "LANGUAGE"]) delete env[name];
14
+ env.LC_ALL = "C"; // the stderr check below reads git's English message (KJC-BUG-0409)
15
+ try {
16
+ return execFileSync("git", args, { cwd, env, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }).trim();
17
+ } catch (err) {
18
+ if (/not a git repository/i.test(String(err.stderr))) return null;
19
+ throw new Error(`cannot resolve the main checkout of ${cwd}: ${String(err.stderr || err.message).trim()}`, { cause: err });
20
+ }
21
+ };
22
+
23
+ const mains = new Map(); // two git spawns per lookup, and plan list/load loops ask once per plan
24
+ export const mainCheckout = (dir) => mains.get(dir) ?? mains.set(dir, resolveMain(dir)).get(dir);
25
+
26
+ function resolveMain(dir) {
27
+ const out = gitOrNull(["rev-parse", "--path-format=absolute", "--git-common-dir", "--is-bare-repository"], dir);
28
+ if (out === null) return dir;
29
+ const [common, bare] = out.split("\n");
30
+ if (bare === "true") throw new Error(`${dir} belongs to a bare repository: kj lanes need a main checkout`);
31
+ // The main checkout is the dir whose `.git` IS the common dir or a file pointing at it. Git
32
+ // records no path back to it, so the candidates are the ancestors of the toplevel (lanes live
33
+ // under it; --separate-git-dir, submodules) and the common dir's parent (a lane beside it).
34
+ const top = gitOrNull(["rev-parse", "--show-toplevel"], dir);
35
+ const candidates = [];
36
+ for (let up = top; path.dirname(up) !== up; up = path.dirname(up)) candidates.push(up);
37
+ const found = [...candidates, path.dirname(common)].find((c) => dotGitIs(path.join(c, ".git"), common));
38
+ if (!found) {
39
+ throw new Error(`cannot find the main checkout of ${dir}: its git dir is separate and the worktree sits outside the checkout`);
40
+ }
41
+ return found;
42
+ }
43
+
44
+ const GITDIR_PREFIX = "gitdir:";
45
+ const dotGitIs = (dotGit, common) => {
46
+ try {
47
+ if (fs.statSync(dotGit).isDirectory()) return fs.realpathSync(dotGit) === common;
48
+ const line = fs.readFileSync(dotGit, "utf8").split("\n").find((l) => l.startsWith(GITDIR_PREFIX));
49
+ return line !== undefined && fs.realpathSync(path.resolve(path.dirname(dotGit), line.slice(GITDIR_PREFIX.length).trim())) === common;
50
+ } catch {
51
+ return false; // no ".git" here: keep climbing
52
+ }
53
+ };
@@ -2,7 +2,9 @@ import path from "node:path";
2
2
  import { existsSync, statSync } from "node:fs";
3
3
  import { runCommand } from "./process.js";
4
4
 
5
- export const QMD_DEFAULT_PATHS = ["docs", ".reviews", ".karajan/plans"];
5
+ // ADR 0032: the wiki indexes what travels with the project, so a whole team gets the same one:
6
+ // the docs and the plans shared with `kj plan share` (private plans stay out of it).
7
+ export const QMD_DEFAULT_PATHS = ["docs", ".karajan-shared/plans"];
6
8
 
7
9
  export function projectSlug(projectDir) {
8
10
  const base = path.basename(path.resolve(projectDir));
@@ -10,11 +10,11 @@ const A = {
10
10
  };
11
11
 
12
12
  const QUICK_START = [
13
- ["kj run <task>", "Run the full coder+reviewer pipeline"],
14
13
  ["kj init", "Initialize config and setup"],
14
+ ["kj hu add", "Put a piece of work on the board before it starts"],
15
+ ["kj review --staged", "Have another AI review the diff you are about to commit"],
16
+ ["kj board start", "Open the HU board and its governance view"],
15
17
  ["kj doctor", "Check environment and agent availability"],
16
- ["kj status", "Show pipeline dashboard"],
17
- ["kj report", "Show latest session report"],
18
18
  ];
19
19
 
20
20
  /**
@@ -1,3 +1,8 @@
1
+ ---
2
+ name: kj-architect
3
+ description: "Architecture Design"
4
+ kind: command
5
+ ---
1
6
  # kj-architect — Architecture Design
2
7
 
3
8
  Analyze the task and propose an architecture before implementation.
@@ -1,3 +1,8 @@
1
+ ---
2
+ name: kj-audit
3
+ description: "Codebase Health Audit"
4
+ kind: command
5
+ ---
1
6
  # kj-audit — Codebase Health Audit
2
7
 
3
8
  Analyze the current codebase for security, code quality, performance, architecture, and testing issues. This is a READ-ONLY analysis — do not modify any files.
@@ -1,3 +1,8 @@
1
+ ---
2
+ name: kj-board
3
+ description: "HU Board Dashboard"
4
+ kind: command
5
+ ---
1
6
  # kj-board — HU Board Dashboard
2
7
 
3
8
  Manage the Karajan HU Board for visualizing user stories and sessions.
@@ -1,3 +1,8 @@
1
+ ---
2
+ name: kj-code
3
+ description: "Coder with Guardrails"
4
+ kind: command
5
+ ---
1
6
  # kj-code — Coder with Guardrails
2
7
 
3
8
  Implement the task with TDD methodology and built-in quality checks.
@@ -1,3 +1,8 @@
1
+ ---
2
+ name: kj-csv-transform
3
+ description: "CSV & Data Transformation"
4
+ kind: command
5
+ ---
1
6
  # kj-csv-transform — CSV & Data Transformation
2
7
 
3
8
  Transform, validate, and process CSV and tabular data files.
@@ -1,3 +1,8 @@
1
+ ---
2
+ name: kj-data-report
3
+ description: "Data Report Generation"
4
+ kind: command
5
+ ---
1
6
  # kj-data-report — Data Report Generation
2
7
 
3
8
  Generate structured data reports with clear findings, methodology, and recommendations.
@@ -1,3 +1,8 @@
1
+ ---
2
+ name: kj-discover
3
+ description: "Gap Detection"
4
+ kind: command
5
+ ---
1
6
  # kj-discover — Gap Detection
2
7
 
3
8
  Analyze the task for gaps, ambiguities, and missing information BEFORE coding.
@@ -1,3 +1,8 @@
1
+ ---
2
+ name: kj-rag-query
3
+ description: "Query Project RAG index"
4
+ kind: command
5
+ ---
1
6
  # kj-rag-query — Query Project RAG index
2
7
 
3
8
  Query the Project RAG (vector store + embedder) and return the top-K most relevant chunks of the indexed project: plans, onboarding briefs, and (optionally) source code.
@@ -1,3 +1,8 @@
1
+ ---
2
+ name: kj-review
3
+ description: "Code Review with Quality Gates"
4
+ kind: command
5
+ ---
1
6
  # kj-review — Code Review with Quality Gates
2
7
 
3
8
  Review the current changes against task requirements and quality standards.
@@ -1,3 +1,8 @@
1
+ ---
2
+ name: kj-security
3
+ description: "Security Audit"
4
+ kind: command
5
+ ---
1
6
  # kj-security — Security Audit
2
7
 
3
8
  Perform a security audit on the current changes.
@@ -1,3 +1,8 @@
1
+ ---
2
+ name: kj-sonar
3
+ description: "Static Analysis"
4
+ kind: command
5
+ ---
1
6
  # kj-sonar — Static Analysis
2
7
 
3
8
  Run SonarQube/SonarCloud analysis and fix any issues found.
@@ -1,3 +1,8 @@
1
+ ---
2
+ name: kj-sql-analysis
3
+ description: "SQL Analysis & Generation"
4
+ kind: command
5
+ ---
1
6
  # kj-sql-analysis — SQL Analysis & Generation
2
7
 
3
8
  Generate and review SQL queries with a focus on correctness, performance, and security.
@@ -1,3 +1,8 @@
1
+ ---
2
+ name: kj-test
3
+ description: "Test Quality Audit"
4
+ kind: command
5
+ ---
1
6
  # kj-test — Test Quality Audit
2
7
 
3
8
  Evaluate test coverage and quality for the current changes.
@@ -1,169 +0,0 @@
1
- // KJC-TSK-0501 step 8f/8 — Preflight gate + run launcher.
2
- //
3
- // Classic script (no exports). Loaded by index.html before app.js so the
4
- // top-level `function`/`let` declarations are hoisted into the shared
5
- // realm and the inline handlers in app.js (and elsewhere) resolve
6
- // `runProject` / `confirmRunWithPreflight` via that hoisting.
7
- //
8
- // Globals consumed from earlier scripts / app.js:
9
- // - esc() (utils/formatters.js)
10
- // - ensureDialog() (app.js)
11
- // - showError() (utils/modals.js)
12
- // - renderBoard() (app.js)
13
- // - openLogViewer() (utils/log-panel.js)
14
- // - lastLaunchedPlanId (mutable in app.js — assignment crosses
15
- // scripts transparently)
16
- // - lastOpenedLog (mutable in app.js — same)
17
-
18
- // ---- Preflight panel + safety modal ----
19
- //
20
- // Goal: when a non-technical user opens a project, they should see at
21
- // a glance whether the environment is ready (git initialised, remote
22
- // configured, agents installed, Node version, etc.). Each missing
23
- // item is rendered with a plain-Spanish "consequence" so the user
24
- // understands what's at stake.
25
- //
26
- // The panel doubles as the gate for ▶ Run plan / ▶ Run HU: if any
27
- // blocker (status:fail with blocking:true) is present, we refuse to
28
- // launch. If only warnings are present, we open a confirm modal
29
- // listing them and require an explicit "Lanzar de todos modos".
30
-
31
- let preflightCache = null; // memoise per-render so the modal can re-use what the panel already fetched
32
-
33
- async function fetchPreflight(projectId) {
34
- try {
35
- const r = await fetch(`/api/projects/${encodeURIComponent(projectId)}/preflight`);
36
- if (!r.ok) return null;
37
- return await r.json();
38
- } catch { return null; }
39
- }
40
-
41
- function preflightStatusIcon(status) {
42
- if (status === 'ok') return '✓';
43
- if (status === 'warn') return '⚠';
44
- if (status === 'fail') return '✗';
45
- return 'ℹ';
46
- }
47
- function preflightStatusColor(status) {
48
- if (status === 'ok') return 'var(--color-green)';
49
- if (status === 'warn') return 'var(--color-yellow,#eab308)';
50
- if (status === 'fail') return 'var(--color-red,#ef4444)';
51
- return 'var(--text-muted)';
52
- }
53
-
54
- /**
55
- * Pre-run safety modal. Returns true if the user wants to proceed,
56
- * false to cancel. Call BEFORE invoking the run endpoint.
57
- *
58
- * Behaviour:
59
- * - All green → returns true immediately (no modal).
60
- * - Blockers present → modal explains them in plain Spanish; only
61
- * "Cancelar" button (no proceed-anyway) because blockers are
62
- * known to break the run.
63
- * - Only warnings → modal lists them with their consequences and
64
- * offers "Cancelar" or "Lanzar de todos modos" (red button so
65
- * the user notices they're accepting risk).
66
- */
67
- async function confirmRunWithPreflight(projectId) {
68
- const data = preflightCache || await fetchPreflight(projectId);
69
- if (!data) return true; // can't fetch → don't block the user
70
- const blockers = data.blockers || [];
71
- const warnings = data.warnings || [];
72
- if (blockers.length === 0 && warnings.length === 0) return true;
73
-
74
- return await new Promise((resolve) => {
75
- const dlg = document.getElementById('app-dialog') || ensureDialog();
76
- const isBlocked = blockers.length > 0;
77
- const headerColor = isBlocked ? 'var(--color-red,#ef4444)' : 'var(--color-yellow,#eab308)';
78
- const allItems = [...blockers, ...warnings];
79
- dlg.innerHTML = `
80
- <div style="padding:14px 18px;border-bottom:1px solid var(--border);font-weight:700;display:flex;align-items:center;gap:10px;background:${headerColor};color:#000;">
81
- <span style="font-size:1.2rem;">${isBlocked ? '✗' : '⚠'}</span>
82
- <span>${isBlocked ? 'No se puede lanzar — falta algo crítico' : 'Atención antes de lanzar'}</span>
83
- </div>
84
- <div style="padding:14px 18px;max-height:60vh;overflow:auto;">
85
- <p style="margin:0 0 10px;font-size:0.9rem;color:var(--text);">
86
- ${isBlocked
87
- ? 'Se detectaron problemas bloqueantes que impedirán que Karajan funcione correctamente:'
88
- : 'Se detectaron avisos. Karajan puede ejecutarse, pero con limitaciones:'}
89
- </p>
90
- <ul style="list-style:none;padding:0;margin:0;display:flex;flex-direction:column;gap:8px;">
91
- ${allItems.map((c) => `
92
- <li style="padding:8px 10px;background:var(--bg-primary);border-left:3px solid ${preflightStatusColor(c.status)};border-radius:var(--radius-sm);">
93
- <div style="font-weight:600;color:var(--text);font-size:0.85rem;">
94
- ${preflightStatusIcon(c.status)} ${esc(c.label)} — <span style="color:var(--text-muted);font-weight:400;">${esc(c.detail || '')}</span>
95
- </div>
96
- ${c.consequence ? `<div style="font-size:0.8rem;color:var(--text);margin-top:4px;">${esc(c.consequence)}</div>` : ''}
97
- </li>
98
- `).join('')}
99
- </ul>
100
- </div>
101
- <div style="padding:12px 18px;border-top:1px solid var(--border);display:flex;gap:8px;justify-content:flex-end;">
102
- <button id="preflight-cancel" style="padding:8px 16px;background:var(--bg-primary);border:1px solid var(--border);color:var(--text);border-radius:var(--radius-sm);cursor:pointer;">Cancelar</button>
103
- ${isBlocked ? '' : `<button id="preflight-proceed" style="padding:8px 16px;background:var(--color-red,#ef4444);border:none;color:#fff;border-radius:var(--radius-sm);cursor:pointer;font-weight:600;">Lanzar de todos modos</button>`}
104
- </div>
105
- `;
106
- if (typeof dlg.showModal === 'function' && !dlg.open) dlg.showModal();
107
- const cancel = dlg.querySelector('#preflight-cancel');
108
- const proceed = dlg.querySelector('#preflight-proceed');
109
- const close = (val) => { try { dlg.close(); } catch { /* ignore */ } resolve(val); };
110
- cancel?.addEventListener('click', () => close(false), { once: true });
111
- proceed?.addEventListener('click', () => close(true), { once: true });
112
- dlg.addEventListener('close', () => resolve(false), { once: true });
113
- });
114
- }
115
-
116
- async function runProject(projectId) {
117
- try {
118
- const res = await fetch(`/api/projects/${encodeURIComponent(projectId)}/run`, {
119
- method: 'POST',
120
- headers: { 'Content-Type': 'application/json' },
121
- body: JSON.stringify({}),
122
- });
123
- if (!res.ok) {
124
- if (res.status === 404) {
125
- await showError(
126
- 'The board server does not recognise the "run" endpoint.\n\n'
127
- + 'Most likely cause: the board process is running a pre-v2.7.5 build. '
128
- + 'Restart it with:\n\n'
129
- + ' kj board stop && kj board start',
130
- { title: 'Board out of date' }
131
- );
132
- return;
133
- }
134
- const msg = (await res.json().catch(() => ({}))).error || `HTTP ${res.status}`;
135
- await showError(msg, { title: 'Could not launch run' });
136
- return;
137
- }
138
- const body = await res.json();
139
- // Best-effort: a chokidar tick may still be in flight, so fetch
140
- // once explicitly to surface the "running" state without waiting
141
- // for the watcher debounce.
142
- await fetch('/api/sync', { method: 'POST' }).catch(() => {});
143
- await renderBoard();
144
-
145
- // Remember the first successful planId so the section header can
146
- // offer a "View log" button without the user having to re-launch.
147
- const firstOk = (body.results || []).find((r) => r.ok);
148
- if (firstOk && firstOk.planId) {
149
- lastLaunchedPlanId = firstOk.planId;
150
- lastOpenedLog = {
151
- id: firstOk.planId,
152
- label: 'Run log',
153
- tailUrl: (offset) => `/api/plans/${encodeURIComponent(firstOk.planId)}/log?offset=${offset}`,
154
- };
155
- // Open the log viewer straight away — the user's mental model is
156
- // "I clicked Run, I want to see what's happening", not "I clicked
157
- // Run, now where do I look".
158
- openLogViewer(firstOk.planId);
159
- } else {
160
- await showError(
161
- `Pipeline launched for ${body.launched}/${body.total} plan(s) but `
162
- + 'no planId came back, so there\'s no log to show.',
163
- { title: 'Run started' }
164
- );
165
- }
166
- } catch (err) {
167
- await showError(err.message, { title: 'Could not launch run' });
168
- }
169
- }
@@ -1,121 +0,0 @@
1
- /**
2
- * Run tracker — registro híbrido (memoria + disco) de procesos kj run.
3
- *
4
- * KJC-TSK-0396: el botón ⏹ Stop del board combina dos fuentes:
5
- *
6
- * 1. **Memoria** (`runs` Map) — runs lanzados desde el board vía
7
- * `runPlan` en plan-mutations.js. Bajo coste, sin I/O.
8
- *
9
- * 2. **Disco** (`~/.karajan/runs/<runId>.json` vía run-registry.js) —
10
- * runs lanzados desde la terminal externa (cualquier `kj run`). El
11
- * CLI escribe el registro al arranque y lo borra al final. Esto da
12
- * bidireccionalidad terminal ↔ board.
13
- *
14
- * `getActiveRuns(planId)` une las dos fuentes y dedupe por PID. Los
15
- * registros con PID muerto se filtran automáticamente y los del disco
16
- * se borran como cleanup (responsabilidad de run-registry).
17
- */
18
-
19
- import { listActiveRuns as fsList } from "karajan-core/run-registry";
20
-
21
- const runs = new Map();
22
- let reaperTimer = null;
23
-
24
- /**
25
- * Registra un run lanzado desde el board (memoria).
26
- *
27
- * @param {string} planId
28
- * @param {{ pid: number, huIds?: string[]|null }} info
29
- */
30
- export function trackRun(planId, info) {
31
- if (!planId || !info?.pid) return;
32
- const set = runs.get(planId) || new Set();
33
- set.add({ pid: info.pid, huIds: info.huIds || null, startedAt: Date.now() });
34
- runs.set(planId, set);
35
- ensureReaper();
36
- }
37
-
38
- /**
39
- * Devuelve los runs activos para un planId. Une memoria + FS y dedupe
40
- * por PID. Filtra PIDs muertos.
41
- */
42
- export function getActiveRuns(planId) {
43
- const seen = new Set();
44
- const out = [];
45
- // Memoria
46
- const set = runs.get(planId);
47
- if (set) {
48
- for (const r of set) {
49
- if (isAlive(r.pid)) {
50
- seen.add(r.pid);
51
- out.push({ pid: r.pid, huIds: r.huIds, startedAt: r.startedAt, source: "board" });
52
- } else set.delete(r);
53
- }
54
- if (set.size === 0) runs.delete(planId);
55
- }
56
- // Disco
57
- for (const entry of fsList({ planId })) {
58
- if (seen.has(entry.pid)) continue;
59
- seen.add(entry.pid);
60
- out.push({
61
- pid: entry.pid,
62
- huIds: entry.huIds,
63
- startedAt: entry.startedAt,
64
- source: entry.source || "cli",
65
- projectDir: entry.projectDir,
66
- });
67
- }
68
- return out;
69
- }
70
-
71
- /**
72
- * Igual que getActiveRuns pero para todos los planes (memoria + FS).
73
- */
74
- export function getAllActiveRuns() {
75
- const out = {};
76
- // Memoria
77
- for (const planId of runs.keys()) {
78
- const alive = getActiveRuns(planId);
79
- if (alive.length > 0) out[planId] = alive;
80
- }
81
- // FS — añadir planes que solo viven en disco (no se vieron arriba).
82
- for (const entry of fsList()) {
83
- if (!entry.planId) continue;
84
- if (out[entry.planId]) continue;
85
- out[entry.planId] = getActiveRuns(entry.planId);
86
- }
87
- return out;
88
- }
89
-
90
- /**
91
- * Quita el registro de un PID de memoria. Los registros FS los limpia
92
- * el propio CLI (vía registry.unregisterRun en su finally).
93
- */
94
- export function untrack(planId, pid) {
95
- const set = runs.get(planId);
96
- if (!set) return;
97
- for (const r of set) {
98
- if (r.pid === pid) set.delete(r);
99
- }
100
- if (set.size === 0) runs.delete(planId);
101
- }
102
-
103
- function isAlive(pid) {
104
- if (!pid) return false;
105
- try { process.kill(pid, 0); return true; }
106
- catch (err) { return err.code === "EPERM"; }
107
- }
108
-
109
- /** Test-only reset. */
110
- export function _resetForTests() {
111
- runs.clear();
112
- if (reaperTimer) { clearInterval(reaperTimer); reaperTimer = null; }
113
- }
114
-
115
- function ensureReaper() {
116
- if (reaperTimer || process.env.VITEST) return;
117
- reaperTimer = setInterval(() => {
118
- for (const planId of [...runs.keys()]) getActiveRuns(planId);
119
- }, 30_000);
120
- reaperTimer.unref?.();
121
- }
@@ -1,59 +0,0 @@
1
- import fs from "node:fs/promises";
2
- import path from "node:path";
3
- import { getSessionRoot } from "./utils/paths.js";
4
- import { ensureDir } from "./utils/fs.js";
5
-
6
- function formatLine(entry) {
7
- const ts = entry.timestamp || new Date().toISOString();
8
- const lvl = (entry.level || "info").toUpperCase().padEnd(5);
9
- const ctx = entry.context
10
- ? Object.entries(entry.context)
11
- .filter(([, v]) => v !== undefined)
12
- .map(([k, v]) => `${k}=${v}`)
13
- .join(" ")
14
- : "";
15
- const ctxStr = ctx ? ` ${ctx}` : "";
16
- return `${ts} [${lvl}]${ctxStr} ${entry.message || ""}`;
17
- }
18
-
19
- export function createActivityLog(sessionId) {
20
- const logPath = path.join(getSessionRoot(), sessionId, "activity.log");
21
- let buffer = [];
22
- let flushing = false;
23
-
24
- async function flush() {
25
- if (flushing || buffer.length === 0) return;
26
- flushing = true;
27
- const lines = buffer.splice(0);
28
- try {
29
- await ensureDir(path.dirname(logPath));
30
- await fs.appendFile(logPath, lines.join("\n") + "\n", "utf8");
31
- } catch {
32
- // best-effort: I/O errors do not crash the flow
33
- }
34
- flushing = false;
35
- if (buffer.length > 0) flush();
36
- }
37
-
38
- return {
39
- write(logEntry) {
40
- buffer.push(formatLine(logEntry));
41
- flush();
42
- },
43
- writeEvent(progressEvent) {
44
- const entry = {
45
- timestamp: progressEvent.timestamp,
46
- level: progressEvent.status === "fail" ? "error" : "info",
47
- context: {
48
- iteration: progressEvent.iteration,
49
- stage: progressEvent.stage
50
- },
51
- message: progressEvent.message || progressEvent.type
52
- };
53
- this.write(entry);
54
- },
55
- get path() {
56
- return logPath;
57
- }
58
- };
59
- }
@@ -1,38 +0,0 @@
1
- /**
2
- * Host Agent — delegates task execution to the MCP host AI via elicitation.
3
- *
4
- * Instead of spawning a subprocess, returns the prompt to the host AI
5
- * (Claude, Codex, etc.) for direct execution. The host has full access
6
- * to the codebase and tools — no subprocess overhead.
7
- *
8
- * Used when: the MCP host IS the same agent configured for a role.
9
- */
10
-
11
- import { BaseAgent } from "./base-agent.js";
12
-
13
- export class HostAgent extends BaseAgent {
14
- constructor(config, logger, { askHost }) {
15
- super("host", config, logger);
16
- this._askHost = askHost;
17
- }
18
-
19
- async runTask(task) {
20
- const { prompt, onOutput } = task;
21
-
22
- if (!this._askHost) {
23
- return { ok: false, output: "", error: "Host agent has no askHost callback" };
24
- }
25
-
26
- if (onOutput) onOutput({ stream: "info", line: "[host-agent] Delegating to host AI..." });
27
-
28
- const answer = await this._askHost(prompt);
29
-
30
- if (!answer) {
31
- return { ok: false, output: "", error: "Host AI declined or returned no response" };
32
- }
33
-
34
- if (onOutput) onOutput({ stream: "info", line: "[host-agent] Host AI completed task" });
35
-
36
- return { ok: true, output: answer, exitCode: 0 };
37
- }
38
- }