karajan-code 4.70.4 → 5.0.1

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