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
@@ -12,6 +12,8 @@ import { fileIndexState } from "../rag/coverage.js";
12
12
  import { query } from "../rag/retriever.js";
13
13
  import { pathNamedHits, withPathNamedHits } from "../rag/path-hits.js";
14
14
  import { installPostMergeHook, maybeAutoUpdate } from "../rag/auto-update.js";
15
+ import { noteDeadline } from "../rag/bootstrap-index.js";
16
+ import { claimLease, indexLeasePath, releaseLease } from "../rag/pid-lease.js";
15
17
  import { indexLibrary, LIBRARY_PROJECT } from "../rag/library.js";
16
18
  import { compareToBaseline, loadGoldenQueries, runEval } from "../rag/eval.js";
17
19
  import { getKarajanHome } from "../utils/paths.js";
@@ -47,8 +49,35 @@ async function indexFiles({ files, projectDir, db, embedder, slug, logger, json,
47
49
  return totals;
48
50
  }
49
51
 
50
- export async function ragIndexCommand({ config, logger, flags = {} }) {
52
+ // HU-3092: the background indexer is given the time it may stop at; unset, non-numeric or <= 0 means none.
53
+ const deadlineFromEnv = () => { const n = Number(process.env.KJ_RAG_DEADLINE); return Number.isFinite(n) && n > 0 ? n : null; };
54
+
55
+ // The partial index keeps its chunks but not its commit: the marker says why it stopped, the warning how to finish.
56
+ function reportDeadline({ totals, projectDir, logger, json }) {
57
+ noteDeadline(projectDir);
58
+ logger.warn?.(`[rag] KJ_RAG_DEADLINE reached after ${totals.files} file(s): the index is partial and its commit is not recorded; run kj rag index --with-sources by hand`);
59
+ if (json) process.stdout.write(`${JSON.stringify(totals)}\n`);
60
+ return totals;
61
+ }
62
+
63
+ // HU-3116: the cooperative stop only looks between files; a hung embed call is ended this long after the deadline.
64
+ // It stays inside DEADLINE_MARGIN_MS (60 s), so the child is gone before its lease reads as expired.
65
+ export const BACKSTOP_GRACE_MS = 30 * 1000;
66
+
67
+ export async function ragIndexCommand({ config, logger, flags = {}, backstop = {} }) {
68
+ const { setTimer = setTimeout, clearTimer = clearTimeout, exit = process.exit } = backstop;
51
69
  const projectDir = config?.projectDir || process.cwd();
70
+ const deadline = deadlineFromEnv();
71
+ // Past already (a queued start, a slow machine): nothing is opened, claimed or embedded.
72
+ if (deadline !== null && Date.now() >= deadline) return reportDeadline({ totals: { indexed: 0, failed: 0, files: 0, stopped: "deadline" }, projectDir, logger, json: flags.json });
73
+ let heldLease = null;
74
+ const timer = deadline === null ? null : setTimer(() => {
75
+ if (heldLease) releaseLease(heldLease);
76
+ noteDeadline(projectDir);
77
+ logger.warn?.("[rag] KJ_RAG_DEADLINE passed with an embed call still hung: the index is partial and its commit is not recorded; run kj rag index --with-sources by hand");
78
+ exit(0);
79
+ }, Math.max(0, deadline + BACKSTOP_GRACE_MS - Date.now()));
80
+ timer?.unref?.();
52
81
  const db = openDb(config);
53
82
  try {
54
83
  const slug = projectSlug(projectDir);
@@ -76,13 +105,22 @@ export async function ragIndexCommand({ config, logger, flags = {} }) {
76
105
  }
77
106
  }
78
107
  if (!totals) {
79
- totals = await indexProject(projectDir, {
80
- db, embedder,
81
- karajanHome: getKarajanHome(), logger,
82
- withSources: Boolean(flags.withSources),
83
- exclude: ragExclude(config),
84
- });
108
+ // HU-2907: a full foreground index holds the machine lease, so background lanes defer to it.
109
+ // The bootstrap child finds its spawning parent in the lease (it names itself first): kin.
110
+ const lease = indexLeasePath();
111
+ const claim = claimLease(lease, { projectDir, slug }, { kin: [process.ppid] });
112
+ if (claim.holder) logger.warn?.(`[rag] another index is running (${claim.holder.slug ?? "?"}, pid ${claim.holder.pid}); indexing anyway`);
113
+ if (claim.claimed) heldLease = lease;
114
+ try {
115
+ totals = await indexProject(projectDir, {
116
+ db, embedder,
117
+ karajanHome: getKarajanHome(), logger,
118
+ withSources: Boolean(flags.withSources),
119
+ exclude: ragExclude(config), deadline,
120
+ });
121
+ } finally { if (claim.claimed) releaseLease(lease); }
85
122
  }
123
+ if (totals.stopped) return reportDeadline({ totals, projectDir, logger, json: flags.json });
86
124
  if (totals.head) setLastIndexedCommit(db, slug, totals.head);
87
125
  // KJC-TSK-0697 — the library corpus refreshes on every index run.
88
126
  // Best-effort and cheap: a handful of cards, content-hash dedup.
@@ -101,6 +139,7 @@ export async function ragIndexCommand({ config, logger, flags = {} }) {
101
139
  }
102
140
  return totals;
103
141
  } finally {
142
+ if (timer) clearTimer(timer);
104
143
  db.close();
105
144
  }
106
145
  }
@@ -128,71 +167,98 @@ export async function ragQueryCommand({ text, config, logger, flags = {} }) {
128
167
  // KJC-TSK-0883: --library abre la base del canon, no la del proyecto.
129
168
  const db = flags.library ? openLibraryStore({ dim: config?.rag?.embedder?.dim || 768 }) : openDb(config);
130
169
  try {
170
+ const projectDir = config?.projectDir || process.cwd();
131
171
  const topK = Math.max(1, Number(flags.topK) || 5);
132
172
  const scope = flags.scope || "all";
133
- // KJC-TSK-0438 — project isolation. Auto-detect slug from projectDir
134
- // (basename normalised); `--project all` disables the filter, `--project
135
- // <slug>` overrides. Pre-v2.27 chunks with NULL slug are only visible
136
- // when no filter is in effect.
137
- const detected = projectSlug(config?.projectDir || process.cwd());
138
173
  // KJC-TSK-0697 — `--library` targets the distilled-canon collection:
139
174
  // its own project namespace plus the kind filter.
140
175
  const library = Boolean(flags.library);
141
- let project = flags.project === "all" ? null : (flags.project || detected || null);
142
- if (library) project = LIBRARY_PROJECT;
143
- // KJC-BUG-0061 follow-up: align the CLI `--json` shape with the MCP
144
- // handler. The MCP tool responds `{ hits: [], empty: true, topK, scope }`
145
- // so agents (and the `/kj-rag-query` skill from Camino B) have a
146
- // deterministic recovery signal. The CLI was emitting just `[]`, which
147
- // is indistinguishable from "query returned zero hits over a populated
148
- // store" and forced consumers to parse stderr.
149
- // KJC-TSK-0882: cuenta lo de ESTE proyecto; chunks ajenos no son respuesta.
150
- if (countChunks(db) === 0 || (project && countProjectChunks(db, project) === 0)) {
151
- // La library se rellena en cada `kj rag index`; migrar la llevaria al proyecto.
152
- const remedy = library ? "kj rag index" : emptyIndexRemedy({ slug: project, legacyPath: join(getKarajanHome(), "rag.db"), dim: config?.rag?.embedder?.dim || 768 });
153
- logger.warn(`[rag] ${library ? "the library index" : "this project's index"} holds no chunks of ${project || "any project"}: this is not an answer, run ${remedy}`);
154
- if (flags.json) process.stdout.write(`${JSON.stringify({ hits: [], empty: true, topK, scope, remedy })}\n`);
155
- return [];
156
- }
176
+ const project = library ? LIBRARY_PROJECT : queryProject(flags, projectDir);
177
+ if (reportEmptyIndex({ db, project, library, config, flags, topK, scope, logger })) return [];
157
178
  // KJC-BUG-0258: chunks of plans and briefs but none of the project's own files
158
179
  // answer nothing about the code; said now, not when kj review --staged blocks.
159
- if (!library && project && countProjectSources(db, project, config?.projectDir || process.cwd()) === 0) {
180
+ if (!library && project && countProjectSources(db, project, projectDir) === 0) {
160
181
  logger.warn("[rag] this project's index holds none of its own files (only plans or briefs): run kj rag index --with-sources");
161
182
  }
162
- const mode = flags.mode || "hybrid";
163
- // KJC-TSK-1180 (RAG-C, core 1.6.0): hybrid fusion is reciprocal rank; `alpha` weighs nothing
164
- // any more, so a value that is still around is said once, never silently ignored.
165
- if ((flags.alpha !== undefined && flags.alpha !== "0.6") || config?.rag?.search?.alpha !== undefined) {
166
- logger.warn("[rag] alpha no longer applies: hybrid fusion is reciprocal rank (RRF); tune rag.search.rrf_k instead and drop alpha from the config");
167
- }
168
- const rrfK = config?.rag?.search?.rrf_k;
169
- if (rrfK !== undefined && !(Number.isInteger(rrfK) && rrfK > 0)) throw new Error(`rag.search.rrf_k must be a positive integer, got ${JSON.stringify(rrfK)}`);
183
+ const { mode, rrfK } = searchSettings({ config, flags, logger });
170
184
  // KJC-TSK-1180 (RAG-B3): a relative `source~=` prefix is placed under this project's root.
171
- const whereRoot = config?.projectDir || process.cwd();
172
- // Safe by grammar: parseWhere (core where-parser.js) accepts ONLY
173
- // AND-joined key=value pairs — an OR or parens never parses, so the
174
- // composed clause cannot leak past the kind filter; it fails loudly.
175
- let where = flags.where || null;
176
- if (library) where = flags.where ? `kind=library AND ${flags.where}` : "kind=library";
185
+ const where = whereFor(flags, library);
177
186
  const rerankOpts = rerankOptionsFor({ config, flags, logger });
178
- const ranked = await query(db, makeGovernedEmbedder(config), text, { topK, scope, project, mode, rrfK, where, whereRoot, rerankOpts });
179
- const hits = library ? ranked : withPathNamedHits(pathNamedHits(db, text, { project, projectDir: config?.projectDir || process.cwd() }), ranked, topK);
180
- if (flags.json) {
181
- process.stdout.write(`${JSON.stringify(hits)}\n`);
182
- } else {
183
- for (const h of hits) {
184
- const label = h.metadata?.hu_id || h.metadata?.symbol || h.metadata?.headingPath?.join(" > ") || "block";
185
- logger.info(`[${h.kind} · ${label} · score=${h.score.toFixed(4)}] ${h.source}`);
186
- logger.info(h.text.length > 240 ? `${h.text.slice(0, 240)}…` : h.text);
187
- logger.info("");
188
- }
189
- }
187
+ const ranked = await query(db, makeGovernedEmbedder(config), text, { topK, scope, project, mode, rrfK, where, whereRoot: projectDir, rerankOpts });
188
+ const hits = library ? ranked : withPathNamedHits(pathNamedHits(db, text, { project, projectDir }), ranked, topK);
189
+ printHits(hits, flags, logger);
190
190
  return hits;
191
191
  } finally {
192
192
  db.close();
193
193
  }
194
194
  }
195
195
 
196
+ /**
197
+ * KJC-TSK-0438 — project isolation. Auto-detect slug from projectDir
198
+ * (basename normalised); `--project all` disables the filter, `--project
199
+ * <slug>` overrides. Pre-v2.27 chunks with NULL slug are only visible
200
+ * when no filter is in effect.
201
+ */
202
+ function queryProject(flags, projectDir) {
203
+ if (flags.project === "all") return null;
204
+ return flags.project || projectSlug(projectDir) || null;
205
+ }
206
+
207
+ /**
208
+ * KJC-BUG-0061 follow-up: align the CLI `--json` shape with the MCP
209
+ * handler. The MCP tool responds `{ hits: [], empty: true, topK, scope }`
210
+ * so agents (and the `/kj-rag-query` skill from Camino B) have a
211
+ * deterministic recovery signal. The CLI was emitting just `[]`, which
212
+ * is indistinguishable from "query returned zero hits over a populated
213
+ * store" and forced consumers to parse stderr.
214
+ * KJC-TSK-0882: cuenta lo de ESTE proyecto; chunks ajenos no son respuesta.
215
+ * @returns {boolean} true when the index has nothing to answer with (and it was said)
216
+ */
217
+ function reportEmptyIndex({ db, project, library, config, flags, topK, scope, logger }) {
218
+ if (countChunks(db) > 0 && !(project && countProjectChunks(db, project) === 0)) return false;
219
+ // La library se rellena en cada `kj rag index`; migrar la llevaria al proyecto.
220
+ const remedy = library ? "kj rag index" : emptyIndexRemedy({ slug: project, legacyPath: join(getKarajanHome(), "rag.db"), dim: config?.rag?.embedder?.dim || 768 });
221
+ logger.warn(`[rag] ${library ? "the library index" : "this project's index"} holds no chunks of ${project || "any project"}: this is not an answer, run ${remedy}`);
222
+ if (flags.json) process.stdout.write(`${JSON.stringify({ hits: [], empty: true, topK, scope, remedy })}\n`);
223
+ return true;
224
+ }
225
+
226
+ /**
227
+ * KJC-TSK-1180 (RAG-C, core 1.6.0): hybrid fusion is reciprocal rank; `alpha` weighs nothing
228
+ * any more, so a value that is still around is said once, never silently ignored.
229
+ */
230
+ function searchSettings({ config, flags, logger }) {
231
+ if ((flags.alpha !== undefined && flags.alpha !== "0.6") || config?.rag?.search?.alpha !== undefined) {
232
+ logger.warn("[rag] alpha no longer applies: hybrid fusion is reciprocal rank (RRF); tune rag.search.rrf_k instead and drop alpha from the config");
233
+ }
234
+ const rrfK = config?.rag?.search?.rrf_k;
235
+ if (rrfK !== undefined && !(Number.isInteger(rrfK) && rrfK > 0)) throw new Error(`rag.search.rrf_k must be a positive integer, got ${JSON.stringify(rrfK)}`);
236
+ return { mode: flags.mode || "hybrid", rrfK };
237
+ }
238
+
239
+ /**
240
+ * Safe by grammar: parseWhere (core where-parser.js) accepts ONLY
241
+ * AND-joined key=value pairs — an OR or parens never parses, so the
242
+ * composed clause cannot leak past the kind filter; it fails loudly.
243
+ */
244
+ function whereFor(flags, library) {
245
+ if (!library) return flags.where || null;
246
+ return flags.where ? `kind=library AND ${flags.where}` : "kind=library";
247
+ }
248
+
249
+ function printHits(hits, flags, logger) {
250
+ if (flags.json) {
251
+ process.stdout.write(`${JSON.stringify(hits)}\n`);
252
+ return;
253
+ }
254
+ for (const h of hits) {
255
+ const label = h.metadata?.hu_id || h.metadata?.symbol || h.metadata?.headingPath?.join(" > ") || "block";
256
+ logger.info(`[${h.kind} · ${label} · score=${h.score.toFixed(4)}] ${h.source}`);
257
+ logger.info(h.text.length > 240 ? `${h.text.slice(0, 240)}…` : h.text);
258
+ logger.info("");
259
+ }
260
+ }
261
+
196
262
  // KJC-TSK-1181 (RAG-D2): the cross-encoder, from the flag or from rag.search.rerank in the config
197
263
  // (enabled, top_n, model). Without the library or the model the retrieval answers alone and the
198
264
  // install is said once per process, never on every query, never in silence.