@karajan-family/code 4.21.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 (746) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +98 -0
  3. package/bin/karajan-mcp.js +2 -0
  4. package/bin/kj-rag-mcp.js +75 -0
  5. package/bin/kj-tail +361 -0
  6. package/bin/kj.js +2 -0
  7. package/docs/README.es.md +80 -0
  8. package/docs/karajan-code-logo-small.png +0 -0
  9. package/library/logical-clocks-lamport.md +40 -0
  10. package/package.json +140 -0
  11. package/packages/ai-trash/README.md +37 -0
  12. package/packages/ai-trash/bin/kj-trash.js +10 -0
  13. package/packages/ai-trash/package.json +43 -0
  14. package/packages/ai-trash/src/cli.js +200 -0
  15. package/packages/ai-trash/src/destructive-parser.js +74 -0
  16. package/packages/ai-trash/src/git-snapshot.js +128 -0
  17. package/packages/ai-trash/src/hook.js +137 -0
  18. package/packages/ai-trash/src/index.js +14 -0
  19. package/packages/ai-trash/src/install.js +73 -0
  20. package/packages/ai-trash/src/logger.js +60 -0
  21. package/packages/ai-trash/src/manifest.js +91 -0
  22. package/packages/ai-trash/src/permissions.js +26 -0
  23. package/packages/ai-trash/src/snapshot.js +66 -0
  24. package/packages/ai-trash/src/ulid.js +66 -0
  25. package/packages/hu-board/README.md +69 -0
  26. package/packages/hu-board/package.json +28 -0
  27. package/packages/hu-board/public/app.js +259 -0
  28. package/packages/hu-board/public/index.html +77 -0
  29. package/packages/hu-board/public/pipeline.css +132 -0
  30. package/packages/hu-board/public/pipeline.html +48 -0
  31. package/packages/hu-board/public/pipeline.js +200 -0
  32. package/packages/hu-board/public/rag.html +21 -0
  33. package/packages/hu-board/public/rag.js +39 -0
  34. package/packages/hu-board/public/styles.css +973 -0
  35. package/packages/hu-board/public/utils/api.js +139 -0
  36. package/packages/hu-board/public/utils/board-view.js +473 -0
  37. package/packages/hu-board/public/utils/command-launcher.js +213 -0
  38. package/packages/hu-board/public/utils/config-editor.js +181 -0
  39. package/packages/hu-board/public/utils/dashboard-view.js +103 -0
  40. package/packages/hu-board/public/utils/formatters.js +300 -0
  41. package/packages/hu-board/public/utils/graph-view.js +216 -0
  42. package/packages/hu-board/public/utils/hu-actions.js +224 -0
  43. package/packages/hu-board/public/utils/init-listeners.js +180 -0
  44. package/packages/hu-board/public/utils/log-panel.js +222 -0
  45. package/packages/hu-board/public/utils/modals.js +309 -0
  46. package/packages/hu-board/public/utils/plan-rollup-view.js +53 -0
  47. package/packages/hu-board/public/utils/preflight-view.js +89 -0
  48. package/packages/hu-board/public/utils/project-actions.js +143 -0
  49. package/packages/hu-board/public/utils/project-picker-view.js +139 -0
  50. package/packages/hu-board/public/utils/run-launcher.js +169 -0
  51. package/packages/hu-board/public/utils/server-push.js +252 -0
  52. package/packages/hu-board/public/utils/sessions-view.js +199 -0
  53. package/packages/hu-board/public/utils/story-detail-view.js +324 -0
  54. package/packages/hu-board/public/utils/story-edit-form.js +271 -0
  55. package/packages/hu-board/public/wiki.html +32 -0
  56. package/packages/hu-board/public/wiki.js +53 -0
  57. package/packages/hu-board/src/auth.js +92 -0
  58. package/packages/hu-board/src/boot-info.js +16 -0
  59. package/packages/hu-board/src/cleanup-zombies.js +145 -0
  60. package/packages/hu-board/src/command-runner.js +133 -0
  61. package/packages/hu-board/src/config-yaml.js +531 -0
  62. package/packages/hu-board/src/db.js +963 -0
  63. package/packages/hu-board/src/ephemeral-cleaner.js +196 -0
  64. package/packages/hu-board/src/event-bus.js +58 -0
  65. package/packages/hu-board/src/format.js +207 -0
  66. package/packages/hu-board/src/hu-zombie-reaper.js +103 -0
  67. package/packages/hu-board/src/journal-parser.js +180 -0
  68. package/packages/hu-board/src/plan-mutations.js +424 -0
  69. package/packages/hu-board/src/preflight.js +286 -0
  70. package/packages/hu-board/src/routes/api.js +1374 -0
  71. package/packages/hu-board/src/routes/pipeline.js +45 -0
  72. package/packages/hu-board/src/routes/rag.js +42 -0
  73. package/packages/hu-board/src/routes/wiki.js +43 -0
  74. package/packages/hu-board/src/run-tracker.js +121 -0
  75. package/packages/hu-board/src/server.js +438 -0
  76. package/packages/hu-board/src/sync.js +732 -0
  77. package/packages/hu-board/src/token-store.js +56 -0
  78. package/packages/hu-board/src/zombie-reaper.js +206 -0
  79. package/scripts/ai-attribution-guard.yml +84 -0
  80. package/scripts/audit-test-diet.mjs +151 -0
  81. package/scripts/build-sea.mjs +150 -0
  82. package/scripts/diet-baseline.mjs +170 -0
  83. package/scripts/dual-publish.mjs +67 -0
  84. package/scripts/esbuild-sea.config.mjs +273 -0
  85. package/scripts/git-hooks/post-merge +18 -0
  86. package/scripts/install-binary.ps1 +174 -0
  87. package/scripts/install-binary.sh +159 -0
  88. package/scripts/install-guard-all-repos.sh +85 -0
  89. package/scripts/install-kj.sh +193 -0
  90. package/scripts/install.js +901 -0
  91. package/scripts/install.sh +7 -0
  92. package/scripts/postinstall.js +117 -0
  93. package/scripts/protect-all-repos.sh +88 -0
  94. package/scripts/quickstart-gate.mjs +97 -0
  95. package/scripts/regen-arch-stats.sh +71 -0
  96. package/scripts/setup-multi-instance.sh +150 -0
  97. package/scripts/verify-pack.mjs +278 -0
  98. package/src/activity-log.js +59 -0
  99. package/src/agents/agy-agent.js +62 -0
  100. package/src/agents/aider-agent.js +78 -0
  101. package/src/agents/availability.js +52 -0
  102. package/src/agents/base-agent.js +134 -0
  103. package/src/agents/claude-agent.js +413 -0
  104. package/src/agents/codex-agent.js +112 -0
  105. package/src/agents/copilot-agent.js +65 -0
  106. package/src/agents/gemini-agent.js +85 -0
  107. package/src/agents/host-agent.js +38 -0
  108. package/src/agents/index.js +59 -0
  109. package/src/agents/kimi-agent.js +45 -0
  110. package/src/agents/model-registry.js +137 -0
  111. package/src/agents/opencode-agent.js +72 -0
  112. package/src/agents/qwen-agent.js +20 -0
  113. package/src/agents/resolve-bin.js +73 -0
  114. package/src/audit/agent-readiness.js +259 -0
  115. package/src/audit/ai-slop-findings.js +102 -0
  116. package/src/audit/audit-fallback.js +66 -0
  117. package/src/audit/audit-history-display.js +61 -0
  118. package/src/audit/audit-history.js +102 -0
  119. package/src/audit/basal-cost.js +281 -0
  120. package/src/audit/circular-deps.js +144 -0
  121. package/src/audit/dead-exports.js +186 -0
  122. package/src/audit/deterministic-summary.js +327 -0
  123. package/src/audit/harness-scorecard.js +100 -0
  124. package/src/audit/harness-section.js +81 -0
  125. package/src/audit/infra-findings.js +100 -0
  126. package/src/audit/injection-findings.js +114 -0
  127. package/src/audit/issue-filter.js +133 -0
  128. package/src/audit/osv-findings.js +167 -0
  129. package/src/audit/plan-adherence.js +224 -0
  130. package/src/audit/semgrep-findings.js +129 -0
  131. package/src/audit/sonar-findings.js +93 -0
  132. package/src/audit/webperf-input.js +133 -0
  133. package/src/autonomy/arbiter-role.js +71 -0
  134. package/src/autonomy/arbiter.js +22 -0
  135. package/src/autonomy/decider.js +18 -0
  136. package/src/autonomy/decision-resolver.js +58 -0
  137. package/src/autonomy/outcome-report.js +55 -0
  138. package/src/autonomy/policy.js +41 -0
  139. package/src/autonomy/stage-ask.js +30 -0
  140. package/src/bootstrap.js +276 -0
  141. package/src/brain/agent-error-classifier.js +116 -0
  142. package/src/brain/decision-tracker.js +125 -0
  143. package/src/brain/decisor.js +243 -0
  144. package/src/brain/solomon-consult.js +171 -0
  145. package/src/brain/standby-scheduler.js +8 -0
  146. package/src/brain/standby-store.js +12 -0
  147. package/src/brain/with-brain-recovery.js +235 -0
  148. package/src/budget/comparison.js +96 -0
  149. package/src/canvas/parse-md.js +238 -0
  150. package/src/canvas/schema.js +101 -0
  151. package/src/canvas/to-flat.js +85 -0
  152. package/src/canvas/validate.js +163 -0
  153. package/src/checks/ai-surface.js +79 -0
  154. package/src/checks/ai-trash.js +34 -0
  155. package/src/checks/binaries.js +207 -0
  156. package/src/checks/ci.js +105 -0
  157. package/src/checks/config-files.js +217 -0
  158. package/src/checks/dir-setup.js +103 -0
  159. package/src/checks/guarantee-level.js +38 -0
  160. package/src/checks/hardware.js +150 -0
  161. package/src/checks/harness-scorecard.js +41 -0
  162. package/src/checks/mcp-health.js +169 -0
  163. package/src/checks/method.js +73 -0
  164. package/src/checks/native-build.js +67 -0
  165. package/src/checks/node.js +70 -0
  166. package/src/checks/ollama.js +41 -0
  167. package/src/checks/orphans.js +77 -0
  168. package/src/checks/ports.js +188 -0
  169. package/src/checks/project-checks.js +245 -0
  170. package/src/checks/qmd.js +41 -0
  171. package/src/checks/rag-hooks.js +54 -0
  172. package/src/checks/release-check.js +102 -0
  173. package/src/checks/rtk.js +36 -0
  174. package/src/checks/runner.js +326 -0
  175. package/src/checks/skills.js +53 -0
  176. package/src/checks/sonar.js +67 -0
  177. package/src/checks/squeezr.js +36 -0
  178. package/src/checks/system.js +53 -0
  179. package/src/checks/tokens.js +172 -0
  180. package/src/checks/types.js +103 -0
  181. package/src/ci/dispatch.js +99 -0
  182. package/src/ci/index.js +3 -0
  183. package/src/ci/pr-diff.js +26 -0
  184. package/src/ci/repo.js +45 -0
  185. package/src/cli/_shared.js +30 -0
  186. package/src/cli/advanced-commands.js +61 -0
  187. package/src/cli/register-meta.js +772 -0
  188. package/src/cli/register-pipeline.js +335 -0
  189. package/src/cli/register-plan.js +224 -0
  190. package/src/cli/register-roles-skills.js +54 -0
  191. package/src/cli/register-sonar.js +28 -0
  192. package/src/cli/register-standby.js +26 -0
  193. package/src/cli.js +155 -0
  194. package/src/commands/advanced.js +31 -0
  195. package/src/commands/agent-run.js +63 -0
  196. package/src/commands/agents.js +105 -0
  197. package/src/commands/architect.js +123 -0
  198. package/src/commands/audit.js +430 -0
  199. package/src/commands/autorun.js +49 -0
  200. package/src/commands/board.js +458 -0
  201. package/src/commands/check.js +40 -0
  202. package/src/commands/clean.js +145 -0
  203. package/src/commands/code.js +45 -0
  204. package/src/commands/config.js +74 -0
  205. package/src/commands/discover.js +105 -0
  206. package/src/commands/doctor.js +251 -0
  207. package/src/commands/env.js +207 -0
  208. package/src/commands/harden.js +203 -0
  209. package/src/commands/hu.js +210 -0
  210. package/src/commands/identity.js +60 -0
  211. package/src/commands/init.js +950 -0
  212. package/src/commands/install-tools.js +432 -0
  213. package/src/commands/mutate.js +94 -0
  214. package/src/commands/ollama.js +44 -0
  215. package/src/commands/onboard.js +45 -0
  216. package/src/commands/plan/_shared.js +55 -0
  217. package/src/commands/plan/add-hu.js +23 -0
  218. package/src/commands/plan/delete.js +9 -0
  219. package/src/commands/plan/fix.js +99 -0
  220. package/src/commands/plan/generate.js +532 -0
  221. package/src/commands/plan/index.js +13 -0
  222. package/src/commands/plan/list.js +21 -0
  223. package/src/commands/plan/migrate-result.js +41 -0
  224. package/src/commands/plan/ready.js +46 -0
  225. package/src/commands/plan/remove-hu.js +17 -0
  226. package/src/commands/plan/share.js +85 -0
  227. package/src/commands/plan/show.js +81 -0
  228. package/src/commands/plan/unshare.js +41 -0
  229. package/src/commands/plan/validate.js +20 -0
  230. package/src/commands/plan.js +17 -0
  231. package/src/commands/policy.js +164 -0
  232. package/src/commands/privacy.js +45 -0
  233. package/src/commands/qmd.js +86 -0
  234. package/src/commands/rag-mcp.js +18 -0
  235. package/src/commands/rag.js +173 -0
  236. package/src/commands/report-issue.js +77 -0
  237. package/src/commands/report.js +469 -0
  238. package/src/commands/researcher.js +54 -0
  239. package/src/commands/resume.js +68 -0
  240. package/src/commands/review-gate.js +355 -0
  241. package/src/commands/review.js +89 -0
  242. package/src/commands/roles.js +116 -0
  243. package/src/commands/run.js +185 -0
  244. package/src/commands/scan.js +18 -0
  245. package/src/commands/skills.js +86 -0
  246. package/src/commands/sonar.js +53 -0
  247. package/src/commands/standby.js +117 -0
  248. package/src/commands/start.js +121 -0
  249. package/src/commands/status.js +36 -0
  250. package/src/commands/sync.js +103 -0
  251. package/src/commands/telemetry.js +70 -0
  252. package/src/commands/tournament.js +85 -0
  253. package/src/commands/triage.js +78 -0
  254. package/src/commands/undo.js +62 -0
  255. package/src/commands/watch.js +46 -0
  256. package/src/commands/webperf.js +162 -0
  257. package/src/commands/worktree.js +76 -0
  258. package/src/config/defaults.js +270 -0
  259. package/src/config/loader.js +204 -0
  260. package/src/config/overrides.js +220 -0
  261. package/src/config/role-resolver.js +171 -0
  262. package/src/config/schema.js +299 -0
  263. package/src/config/test-harness.js +78 -0
  264. package/src/config.js +34 -0
  265. package/src/domains/domain-loader.js +245 -0
  266. package/src/domains/domain-registry.js +140 -0
  267. package/src/domains/domain-synthesizer.js +129 -0
  268. package/src/environment/adr.js +45 -0
  269. package/src/environment/board-access.js +97 -0
  270. package/src/environment/board-select.js +59 -0
  271. package/src/environment/briefs.js +129 -0
  272. package/src/environment/issue-report.js +72 -0
  273. package/src/environment/mcp-wiring.js +44 -0
  274. package/src/environment/playbook.js +127 -0
  275. package/src/git/automation.js +334 -0
  276. package/src/git/hu-automation.js +171 -0
  277. package/src/git/hu-snapshot.js +10 -0
  278. package/src/golden/asserter.js +92 -0
  279. package/src/golden/loader.js +52 -0
  280. package/src/golden/runner.js +92 -0
  281. package/src/golden/schema.js +41 -0
  282. package/src/guards/intent-guard.js +161 -0
  283. package/src/guards/output-guard.js +149 -0
  284. package/src/guards/perf-guard.js +126 -0
  285. package/src/guards/policy-guard.js +90 -0
  286. package/src/guards/policy-resolver.js +85 -0
  287. package/src/guards/secret-redactor.js +71 -0
  288. package/src/harden/advisory.js +203 -0
  289. package/src/harden/alternatives.js +50 -0
  290. package/src/harden/check.js +81 -0
  291. package/src/harden/config-engine.js +128 -0
  292. package/src/harden/config-templates.js +122 -0
  293. package/src/harden/guidelines-engine.js +48 -0
  294. package/src/harden/guidelines-templates.js +36 -0
  295. package/src/harden/harden-engine.js +80 -0
  296. package/src/harden/harness-hooks.js +107 -0
  297. package/src/harden/hook-commands.js +25 -0
  298. package/src/harden/hook-templates.js +183 -0
  299. package/src/harden/interactive.js +76 -0
  300. package/src/harden/sentinel-hooks.js +721 -0
  301. package/src/harden/stack-roots.js +105 -0
  302. package/src/harden/test-on-push.js +38 -0
  303. package/src/harden/workflow-engine.js +116 -0
  304. package/src/harden/workflow-templates.js +285 -0
  305. package/src/hu/acceptance-runner.js +138 -0
  306. package/src/hu/auto-generator.js +358 -0
  307. package/src/hu/graph.js +71 -0
  308. package/src/hu/lazy-planner.js +109 -0
  309. package/src/hu/model-router.js +108 -0
  310. package/src/hu/parallel-executor.js +94 -0
  311. package/src/hu/split-validator.js +143 -0
  312. package/src/hu/splitting-detector.js +158 -0
  313. package/src/hu/splitting-generator.js +175 -0
  314. package/src/hu/store.js +392 -0
  315. package/src/hu/worktree-bootstrap.js +59 -0
  316. package/src/identity/bootstrap.js +48 -0
  317. package/src/identity/compare.js +38 -0
  318. package/src/identity/detect.js +51 -0
  319. package/src/identity/store.js +66 -0
  320. package/src/infrastructure/command-runner.js +44 -0
  321. package/src/infrastructure/environment.js +38 -0
  322. package/src/infrastructure/file-system-service.js +63 -0
  323. package/src/infrastructure/mocks.js +182 -0
  324. package/src/lang/chunk-go.js +94 -0
  325. package/src/lang/chunk-java.js +90 -0
  326. package/src/lang/chunk-python.js +88 -0
  327. package/src/lang/chunk-rust.js +102 -0
  328. package/src/lang/go.js +14 -0
  329. package/src/lang/java.js +16 -0
  330. package/src/lang/js.js +8 -0
  331. package/src/lang/python.js +14 -0
  332. package/src/lang/registry.js +79 -0
  333. package/src/lang/rust.js +14 -0
  334. package/src/lang/tree-sitter-loader.js +45 -0
  335. package/src/mcp/direct-role-runner.js +112 -0
  336. package/src/mcp/error-classifiers.js +66 -0
  337. package/src/mcp/handlers/direct-handlers.js +486 -0
  338. package/src/mcp/handlers/hu-handlers.js +93 -0
  339. package/src/mcp/handlers/management-handlers.js +265 -0
  340. package/src/mcp/handlers/rag-handler.js +52 -0
  341. package/src/mcp/handlers/run-handler.js +313 -0
  342. package/src/mcp/orphan-guard.js +131 -0
  343. package/src/mcp/preflight.js +47 -0
  344. package/src/mcp/progress.js +149 -0
  345. package/src/mcp/response-compressor.js +81 -0
  346. package/src/mcp/run-kj.js +135 -0
  347. package/src/mcp/server-handlers.js +79 -0
  348. package/src/mcp/server.js +66 -0
  349. package/src/mcp/shared-helpers.js +297 -0
  350. package/src/mcp/sovereignty-guard.js +112 -0
  351. package/src/mcp/suggest-handler.js +92 -0
  352. package/src/mcp/tool-arg-normalizers.js +16 -0
  353. package/src/mcp/tools.js +432 -0
  354. package/src/mutate/diff-scope.js +105 -0
  355. package/src/mutate/reviewer-signal.js +76 -0
  356. package/src/mutate/runner.js +72 -0
  357. package/src/mutate/tool-registry.js +90 -0
  358. package/src/onboarder/cache.js +24 -0
  359. package/src/onboarder/collectors/framework-multilang.js +64 -0
  360. package/src/onboarder/collectors/index.js +136 -0
  361. package/src/orchestrator/agent-fallback.js +81 -0
  362. package/src/orchestrator/brain-coordinator.js +186 -0
  363. package/src/orchestrator/ci-integration.js +139 -0
  364. package/src/orchestrator/config-init.js +510 -0
  365. package/src/orchestrator/direct-actions.js +217 -0
  366. package/src/orchestrator/drivers/error-recovery.js +287 -0
  367. package/src/orchestrator/drivers/init-context.js +227 -0
  368. package/src/orchestrator/drivers/iteration-loop.js +380 -0
  369. package/src/orchestrator/drivers/iteration-phases/coder-and-refactorer.js +69 -0
  370. package/src/orchestrator/drivers/iteration-phases/guards.js +84 -0
  371. package/src/orchestrator/drivers/iteration-phases/handle-approved.js +29 -0
  372. package/src/orchestrator/drivers/iteration-phases/quality-gates.js +114 -0
  373. package/src/orchestrator/drivers/iteration-phases/reviewer-gate.js +60 -0
  374. package/src/orchestrator/drivers/post-loop.js +383 -0
  375. package/src/orchestrator/drivers/pre-loop-phases/auto-hu-batch.js +136 -0
  376. package/src/orchestrator/drivers/pre-loop-phases/config-deprecations.js +47 -0
  377. package/src/orchestrator/drivers/pre-loop-phases/ensure-addyosmani-skills.js +84 -0
  378. package/src/orchestrator/drivers/pre-loop-phases/inject-loaded-plan.js +391 -0
  379. package/src/orchestrator/drivers/pre-loop.js +507 -0
  380. package/src/orchestrator/drivers/run-hu-batch.js +427 -0
  381. package/src/orchestrator/feedback-enrichment.js +140 -0
  382. package/src/orchestrator/feedback-queue.js +151 -0
  383. package/src/orchestrator/flow-control.js +170 -0
  384. package/src/orchestrator/flow-runner.js +364 -0
  385. package/src/orchestrator/fs-leak-detector.js +210 -0
  386. package/src/orchestrator/hu-scheduler.js +114 -0
  387. package/src/orchestrator/hu-sub-pipeline.js +616 -0
  388. package/src/orchestrator/integrations.js +81 -0
  389. package/src/orchestrator/iteration-gate.js +73 -0
  390. package/src/orchestrator/iteration-stages.js +9 -0
  391. package/src/orchestrator/parallel-limiter.js +74 -0
  392. package/src/orchestrator/pipeline-context.js +72 -0
  393. package/src/orchestrator/post-loop-stages.js +468 -0
  394. package/src/orchestrator/pre-loop-stages.js +11 -0
  395. package/src/orchestrator/preflight-checks.js +462 -0
  396. package/src/orchestrator/repair/repair-detector.js +117 -0
  397. package/src/orchestrator/repair/repair-runner.js +142 -0
  398. package/src/orchestrator/reviewer-fallback.js +45 -0
  399. package/src/orchestrator/role-output-compressor.js +189 -0
  400. package/src/orchestrator/session-journal.js +308 -0
  401. package/src/orchestrator/solomon-escalation.js +305 -0
  402. package/src/orchestrator/solomon-rules.js +212 -0
  403. package/src/orchestrator/stages/architect-stage.js +172 -0
  404. package/src/orchestrator/stages/coder-stage.js +480 -0
  405. package/src/orchestrator/stages/domain-curator-stage.js +82 -0
  406. package/src/orchestrator/stages/hu-reviewer-phases/detect-and-apply-splits.js +127 -0
  407. package/src/orchestrator/stages/hu-reviewer-stage.js +394 -0
  408. package/src/orchestrator/stages/perf-stage.js +140 -0
  409. package/src/orchestrator/stages/planner-stage.js +85 -0
  410. package/src/orchestrator/stages/rag-context-stage.js +77 -0
  411. package/src/orchestrator/stages/rag-preload-decisor.js +58 -0
  412. package/src/orchestrator/stages/research-stage.js +69 -0
  413. package/src/orchestrator/stages/reviewer-stage.js +422 -0
  414. package/src/orchestrator/stages/sonar-stage.js +421 -0
  415. package/src/orchestrator/stages/stage-classes.js +84 -0
  416. package/src/orchestrator/stages/stage-executor.js +155 -0
  417. package/src/orchestrator/stages/tdd-discipline-stage.js +56 -0
  418. package/src/orchestrator/stages/tool-judge-stage.js +53 -0
  419. package/src/orchestrator/stages/triage-stage.js +172 -0
  420. package/src/orchestrator/standby.js +71 -0
  421. package/src/orchestrator/verification-gate.js +183 -0
  422. package/src/orchestrator.js +22 -0
  423. package/src/plan/adr-generator.js +170 -0
  424. package/src/plan/adr-loader.js +60 -0
  425. package/src/plan/plan-executor.js +100 -0
  426. package/src/plan/plan-fixer.js +192 -0
  427. package/src/plan/plan-hu-ops.js +16 -0
  428. package/src/plan/plan-id.js +4 -0
  429. package/src/plan/plan-migrate-result.js +24 -0
  430. package/src/plan/plan-reviewer.js +236 -0
  431. package/src/plan/plan-schema.js +334 -0
  432. package/src/plan/plan-store.js +260 -0
  433. package/src/plan/plan-structural-pass.js +122 -0
  434. package/src/plan/plan-validation.js +4 -0
  435. package/src/plan/preflight-hu.js +105 -0
  436. package/src/plan/spec-detector.js +61 -0
  437. package/src/plan/tests-synthesizer.js +131 -0
  438. package/src/planning-game/adapter.js +108 -0
  439. package/src/planning-game/architect-adrs.js +45 -0
  440. package/src/planning-game/client.js +108 -0
  441. package/src/planning-game/decomposition.js +87 -0
  442. package/src/planning-game/pipeline-adapter.js +251 -0
  443. package/src/plugins/loader.js +67 -0
  444. package/src/policy/add.js +111 -0
  445. package/src/policy/decisions.js +42 -0
  446. package/src/policy/engine.js +82 -0
  447. package/src/policy/exceptions.js +60 -0
  448. package/src/privacy/onboarding.js +35 -0
  449. package/src/privacy/scan.js +120 -0
  450. package/src/prompts/arbiter.js +38 -0
  451. package/src/prompts/architect.js +103 -0
  452. package/src/prompts/audit.js +474 -0
  453. package/src/prompts/coder.js +287 -0
  454. package/src/prompts/diff-clip.js +27 -0
  455. package/src/prompts/discover.js +222 -0
  456. package/src/prompts/hu-reviewer.js +219 -0
  457. package/src/prompts/planner.js +312 -0
  458. package/src/prompts/prompt-layout.js +80 -0
  459. package/src/prompts/prompt-resolver.js +120 -0
  460. package/src/prompts/reviewer.js +75 -0
  461. package/src/prompts/rtk-snippet.js +25 -0
  462. package/src/prompts/spec-reviewer.js +66 -0
  463. package/src/prompts/split-signal.js +82 -0
  464. package/src/prompts/start-decision.js +52 -0
  465. package/src/prompts/tool-correctness-judge.js +31 -0
  466. package/src/prompts/triage.js +57 -0
  467. package/src/rag/auto-update.js +72 -0
  468. package/src/rag/chunker-ast.js +56 -0
  469. package/src/rag/chunker.js +132 -0
  470. package/src/rag/embedder.js +2 -0
  471. package/src/rag/embedders/_cloud-base.js +2 -0
  472. package/src/rag/embedders/cohere.js +2 -0
  473. package/src/rag/embedders/factory.js +2 -0
  474. package/src/rag/embedders/mistral.js +2 -0
  475. package/src/rag/embedders/onnx.js +2 -0
  476. package/src/rag/embedders/openai.js +2 -0
  477. package/src/rag/embedders/voyage.js +2 -0
  478. package/src/rag/eval.js +61 -0
  479. package/src/rag/governed-embedder.js +39 -0
  480. package/src/rag/indexer.js +199 -0
  481. package/src/rag/library.js +62 -0
  482. package/src/rag/ollama-capability.js +59 -0
  483. package/src/rag/ollama-manager.js +98 -0
  484. package/src/rag/onnx-fallback.js +69 -0
  485. package/src/rag/rerank.js +4 -0
  486. package/src/rag/retriever.js +2 -0
  487. package/src/rag/vec-store.js +17 -0
  488. package/src/rag/watcher.js +62 -0
  489. package/src/rag/where-parser.js +4 -0
  490. package/src/repeat-detector.js +88 -0
  491. package/src/review/card-first.js +99 -0
  492. package/src/review/card-verify.js +83 -0
  493. package/src/review/diff-generator.js +112 -0
  494. package/src/review/gate-gitignore.js +77 -0
  495. package/src/review/git-stash-helper.js +104 -0
  496. package/src/review/mutation-pregate.js +48 -0
  497. package/src/review/one-shot-review.js +122 -0
  498. package/src/review/parser.js +80 -0
  499. package/src/review/policy-gate.js +26 -0
  500. package/src/review/profiles.js +66 -0
  501. package/src/review/reviewer-fallback.js +125 -0
  502. package/src/review/schema.js +31 -0
  503. package/src/review/scope-filter.js +152 -0
  504. package/src/review/snapshot-diff.js +122 -0
  505. package/src/review/solomon-arbitration.js +113 -0
  506. package/src/review/sonar-pregate.js +63 -0
  507. package/src/review/tdd-discipline.js +90 -0
  508. package/src/review/tdd-policy.js +69 -0
  509. package/src/review/tests-with-code.js +33 -0
  510. package/src/review/verdict-store.js +87 -0
  511. package/src/review/workspace.js +21 -0
  512. package/src/roles/agent-role.js +194 -0
  513. package/src/roles/architect-role.js +77 -0
  514. package/src/roles/audit-role.js +258 -0
  515. package/src/roles/base-role.js +165 -0
  516. package/src/roles/coder-role.js +107 -0
  517. package/src/roles/commiter-role.js +110 -0
  518. package/src/roles/discover-role.js +81 -0
  519. package/src/roles/domain-curator-role.js +141 -0
  520. package/src/roles/hu-reviewer-role.js +64 -0
  521. package/src/roles/impeccable-role.js +85 -0
  522. package/src/roles/index.js +18 -0
  523. package/src/roles/karajan-brain-role.js +134 -0
  524. package/src/roles/onboarder-role.js +61 -0
  525. package/src/roles/perf-role.js +122 -0
  526. package/src/roles/planner-role.js +151 -0
  527. package/src/roles/refactorer-role.js +30 -0
  528. package/src/roles/repairer-role.js +181 -0
  529. package/src/roles/researcher-role.js +70 -0
  530. package/src/roles/reviewer-role.js +104 -0
  531. package/src/roles/security-role.js +73 -0
  532. package/src/roles/solomon-role.js +265 -0
  533. package/src/roles/sonar-role.js +70 -0
  534. package/src/roles/spec-reviewer-role.js +106 -0
  535. package/src/roles/tester-role.js +235 -0
  536. package/src/roles/tool-correctness-judge-role.js +78 -0
  537. package/src/roles/triage-role.js +99 -0
  538. package/src/session/journal/decisions-writer.js +200 -0
  539. package/src/session/journal/iteration-logger.js +194 -0
  540. package/src/session/journal/summary-writer.js +320 -0
  541. package/src/session/journal/tree-writer.js +164 -0
  542. package/src/session/journal/write-all.js +89 -0
  543. package/src/session/mutators.js +339 -0
  544. package/src/session/runtime-overrides.js +59 -0
  545. package/src/session/store.js +106 -0
  546. package/src/session-cleanup.js +116 -0
  547. package/src/skills/addyosmani-catalog.js +315 -0
  548. package/src/skills/addyosmani-role-map.js +139 -0
  549. package/src/skills/openskills-client.js +157 -0
  550. package/src/skills/semantic-detector.js +167 -0
  551. package/src/skills/skill-detector.js +385 -0
  552. package/src/skills/skill-loader.js +219 -0
  553. package/src/skills/skills-cache.js +128 -0
  554. package/src/sonar/api.js +128 -0
  555. package/src/sonar/cloud-scanner.js +78 -0
  556. package/src/sonar/config-resolver.js +88 -0
  557. package/src/sonar/credentials.js +60 -0
  558. package/src/sonar/discovery.js +124 -0
  559. package/src/sonar/enforcer.js +19 -0
  560. package/src/sonar/issue-filter.js +12 -0
  561. package/src/sonar/manager.js +181 -0
  562. package/src/sonar/project-key.js +120 -0
  563. package/src/sonar/scanner.js +307 -0
  564. package/src/sonar/token-bootstrap.js +205 -0
  565. package/src/sonar/token-recovery.js +67 -0
  566. package/src/spec-review/refine-loop.js +58 -0
  567. package/src/spec-review/run-spec-review.js +119 -0
  568. package/src/start/assessment.js +74 -0
  569. package/src/start/maturity.js +73 -0
  570. package/src/start/start-decider-role.js +79 -0
  571. package/src/start/sweep.js +157 -0
  572. package/src/sync/apply-canvas-patch.js +55 -0
  573. package/src/sync/detect-drift.js +113 -0
  574. package/src/tournament/crown.js +88 -0
  575. package/src/tournament/judge.js +150 -0
  576. package/src/tournament/run.js +142 -0
  577. package/src/tournament/scoreboard.js +124 -0
  578. package/src/tracker-bootstrap.js +44 -0
  579. package/src/types/agent.js +55 -0
  580. package/src/types/config.js +114 -0
  581. package/src/types/hu.js +47 -0
  582. package/src/types/index.js +38 -0
  583. package/src/types/policy.js +43 -0
  584. package/src/types/session.js +75 -0
  585. package/src/types/solomon.js +87 -0
  586. package/src/types/stage.js +68 -0
  587. package/src/utils/agent-detect.js +93 -0
  588. package/src/utils/ai-trash.js +48 -0
  589. package/src/utils/async-lock.js +31 -0
  590. package/src/utils/atomic-write.js +6 -0
  591. package/src/utils/banner.js +66 -0
  592. package/src/utils/binary-sources.js +70 -0
  593. package/src/utils/board-prompt-bridge.js +108 -0
  594. package/src/utils/budget.js +229 -0
  595. package/src/utils/cli-ask-question.js +93 -0
  596. package/src/utils/cli-progress.js +220 -0
  597. package/src/utils/cli-run-log.js +83 -0
  598. package/src/utils/cwd-confirm.js +39 -0
  599. package/src/utils/derive-project-name-from-cwd.js +119 -0
  600. package/src/utils/display/event-handlers.js +403 -0
  601. package/src/utils/display/formatters.js +132 -0
  602. package/src/utils/display/header.js +47 -0
  603. package/src/utils/display/resume-hint.js +41 -0
  604. package/src/utils/display/session-summary.js +118 -0
  605. package/src/utils/display/solomon.js +42 -0
  606. package/src/utils/display/spec-findings.js +44 -0
  607. package/src/utils/doc-links.js +29 -0
  608. package/src/utils/docker-install.js +34 -0
  609. package/src/utils/escape-regexp.js +15 -0
  610. package/src/utils/events.js +35 -0
  611. package/src/utils/fs.js +19 -0
  612. package/src/utils/garbage-collector.js +481 -0
  613. package/src/utils/git.js +279 -0
  614. package/src/utils/home-migration.js +87 -0
  615. package/src/utils/injection-guard.js +186 -0
  616. package/src/utils/install-hints.js +180 -0
  617. package/src/utils/json-extract.js +64 -0
  618. package/src/utils/locale.js +59 -0
  619. package/src/utils/logger.js +96 -0
  620. package/src/utils/managed-markers.js +93 -0
  621. package/src/utils/manifest-sniff.js +82 -0
  622. package/src/utils/messages.js +61 -0
  623. package/src/utils/model-selector.js +107 -0
  624. package/src/utils/os-detect.js +79 -0
  625. package/src/utils/paths.js +13 -0
  626. package/src/utils/pending-user-action.js +95 -0
  627. package/src/utils/port-check.js +6 -0
  628. package/src/utils/port-occupant.js +96 -0
  629. package/src/utils/pricing.js +29 -0
  630. package/src/utils/process.js +4 -0
  631. package/src/utils/project-detect.js +160 -0
  632. package/src/utils/prompt-project-name.js +35 -0
  633. package/src/utils/provider-env.js +116 -0
  634. package/src/utils/qmd-collection.js +72 -0
  635. package/src/utils/qmd-detect.js +18 -0
  636. package/src/utils/qmd-install.js +37 -0
  637. package/src/utils/quota-simulator.js +56 -0
  638. package/src/utils/rate-limit-detector.js +181 -0
  639. package/src/utils/repo-cleaner.js +79 -0
  640. package/src/utils/retry.js +88 -0
  641. package/src/utils/role-assigner.js +137 -0
  642. package/src/utils/role-env.js +58 -0
  643. package/src/utils/rtk-detect.js +18 -0
  644. package/src/utils/rtk-install.js +38 -0
  645. package/src/utils/rtk-wrapper.js +87 -0
  646. package/src/utils/run-context.js +75 -0
  647. package/src/utils/run-log.js +217 -0
  648. package/src/utils/run-registry.js +9 -0
  649. package/src/utils/shared-paths.js +12 -0
  650. package/src/utils/squeezr-detect.js +21 -0
  651. package/src/utils/squeezr-install.js +37 -0
  652. package/src/utils/stack-detect.js +135 -0
  653. package/src/utils/stall-detector.js +159 -0
  654. package/src/utils/status-dashboard.js +254 -0
  655. package/src/utils/task-file.js +109 -0
  656. package/src/utils/telemetry.js +124 -0
  657. package/src/utils/templates-root.js +61 -0
  658. package/src/utils/tool-call-extractor.js +56 -0
  659. package/src/utils/tool-governor.js +116 -0
  660. package/src/utils/tool-installer.js +93 -0
  661. package/src/utils/update-check.js +280 -0
  662. package/src/utils/vector-store-orphans.js +89 -0
  663. package/src/utils/welcome.js +47 -0
  664. package/src/utils/with-timeout.js +42 -0
  665. package/src/utils/wizard.js +47 -0
  666. package/src/webperf/cwv-gate.js +94 -0
  667. package/src/webperf/devtools-detect.js +112 -0
  668. package/src/webperf/scanner.js +209 -0
  669. package/src/webperf/webperf-role-integration.js +66 -0
  670. package/templates/coder-rules.md +45 -0
  671. package/templates/docker-compose.sonar.yml +60 -0
  672. package/templates/domains/example-dental.md +57 -0
  673. package/templates/kj.config.yml +128 -0
  674. package/templates/review-rules.md +17 -0
  675. package/templates/roles/architect/anthropic.md +74 -0
  676. package/templates/roles/architect/default.md +72 -0
  677. package/templates/roles/architect/google.md +61 -0
  678. package/templates/roles/architect/openai.md +60 -0
  679. package/templates/roles/architect/opencode.md +59 -0
  680. package/templates/roles/architect.md +76 -0
  681. package/templates/roles/audit.md +68 -0
  682. package/templates/roles/coder/anthropic.md +81 -0
  683. package/templates/roles/coder/default.md +78 -0
  684. package/templates/roles/coder/google.md +87 -0
  685. package/templates/roles/coder/openai.md +68 -0
  686. package/templates/roles/coder/opencode.md +58 -0
  687. package/templates/roles/coder.md +152 -0
  688. package/templates/roles/commiter.md +44 -0
  689. package/templates/roles/discover.md +167 -0
  690. package/templates/roles/domain-curator.md +52 -0
  691. package/templates/roles/hu-reviewer.md +236 -0
  692. package/templates/roles/impeccable-design.md +87 -0
  693. package/templates/roles/impeccable.md +125 -0
  694. package/templates/roles/karajan-brain.md +95 -0
  695. package/templates/roles/onboarder.md +45 -0
  696. package/templates/roles/planner/anthropic.md +59 -0
  697. package/templates/roles/planner/default.md +57 -0
  698. package/templates/roles/planner/google.md +75 -0
  699. package/templates/roles/planner/openai.md +55 -0
  700. package/templates/roles/planner/opencode.md +62 -0
  701. package/templates/roles/planner.md +61 -0
  702. package/templates/roles/refactorer.md +48 -0
  703. package/templates/roles/repairer.md +103 -0
  704. package/templates/roles/researcher.md +41 -0
  705. package/templates/roles/reviewer/anthropic.md +61 -0
  706. package/templates/roles/reviewer/default.md +62 -0
  707. package/templates/roles/reviewer/google.md +63 -0
  708. package/templates/roles/reviewer/openai.md +57 -0
  709. package/templates/roles/reviewer/opencode.md +42 -0
  710. package/templates/roles/reviewer-paranoid.md +38 -0
  711. package/templates/roles/reviewer-relaxed.md +34 -0
  712. package/templates/roles/reviewer-strict.md +37 -0
  713. package/templates/roles/reviewer.md +62 -0
  714. package/templates/roles/security.md +54 -0
  715. package/templates/roles/solomon/anthropic.md +71 -0
  716. package/templates/roles/solomon/default.md +83 -0
  717. package/templates/roles/solomon/google.md +61 -0
  718. package/templates/roles/solomon/openai.md +53 -0
  719. package/templates/roles/solomon/opencode.md +55 -0
  720. package/templates/roles/solomon.md +83 -0
  721. package/templates/roles/sonar.md +49 -0
  722. package/templates/roles/spec-reviewer.md +47 -0
  723. package/templates/roles/tester.md +50 -0
  724. package/templates/roles/triage.md +69 -0
  725. package/templates/skills/kj-architect.md +45 -0
  726. package/templates/skills/kj-audit.md +63 -0
  727. package/templates/skills/kj-board.md +16 -0
  728. package/templates/skills/kj-code.md +51 -0
  729. package/templates/skills/kj-csv-transform.md +40 -0
  730. package/templates/skills/kj-data-report.md +44 -0
  731. package/templates/skills/kj-discover.md +24 -0
  732. package/templates/skills/kj-rag-query.md +50 -0
  733. package/templates/skills/kj-review.md +47 -0
  734. package/templates/skills/kj-run.md +73 -0
  735. package/templates/skills/kj-security.md +49 -0
  736. package/templates/skills/kj-sonar.md +41 -0
  737. package/templates/skills/kj-sql-analysis.md +40 -0
  738. package/templates/skills/kj-test.md +40 -0
  739. package/templates/workflows/automerge.yml +30 -0
  740. package/templates/workflows/houston-override.yml +46 -0
  741. package/templates/workflows/kj-ci-gateway.yml +58 -0
  742. package/vendor/tree-sitter-grammars/README.md +21 -0
  743. package/vendor/tree-sitter-grammars/go.wasm +0 -0
  744. package/vendor/tree-sitter-grammars/java.wasm +0 -0
  745. package/vendor/tree-sitter-grammars/python.wasm +0 -0
  746. package/vendor/tree-sitter-grammars/rust.wasm +0 -0
@@ -0,0 +1,392 @@
1
+ /**
2
+ * HU (Historia de Usuario / User Story) storage. Persists HU batches and
3
+ * their stories to the session directory.
4
+ *
5
+ * @typedef {import("../types/hu.js").HUStory} HUStory
6
+ * @typedef {import("../types/hu.js").HUBatch} HUBatch
7
+ * @typedef {import("../types/hu.js").HUStatus} HUStatus
8
+ */
9
+
10
+ import fs from "node:fs/promises";
11
+ import path from "node:path";
12
+ import { execFile } from "node:child_process";
13
+ import { promisify } from "node:util";
14
+
15
+ const execFileAsync = promisify(execFile);
16
+ import { getKarajanHome } from "../utils/paths.js";
17
+
18
+ // FUTURE: hu-storage adapter for PG/Trello/etc — currently local files only
19
+
20
+ /**
21
+ * Valid HU story status values.
22
+ * @type {Readonly<{PENDING: "pending", CODING: "coding", REVIEWING: "reviewing", DONE: "done", FAILED: "failed", BLOCKED: "blocked", CERTIFIED: "certified", NEEDS_CONTEXT: "needs_context"}>}
23
+ */
24
+ export const HU_STATUS = Object.freeze({
25
+ PENDING: "pending",
26
+ CODING: "coding",
27
+ REVIEWING: "reviewing",
28
+ DONE: "done",
29
+ FAILED: "failed",
30
+ BLOCKED: "blocked",
31
+ CERTIFIED: "certified",
32
+ NEEDS_CONTEXT: "needs_context"
33
+ });
34
+
35
+ /** @returns {string} Path to the hu-stories directory (evaluated at call time). */
36
+ function getHuDir() {
37
+ return path.join(getKarajanHome(), "hu-stories");
38
+ }
39
+
40
+ /**
41
+ * Create a new HU batch from an array of story definitions.
42
+ * @param {string} sessionId - The session identifier.
43
+ * @param {Array<{id?: string, text: string, blocked_by?: string[]}>} stories - Raw story inputs.
44
+ * @returns {Promise<object>} The created batch object.
45
+ */
46
+ export async function createHuBatch(sessionId, stories) {
47
+ const dir = path.join(getHuDir(), sessionId);
48
+ await fs.mkdir(dir, { recursive: true });
49
+
50
+ const batch = {
51
+ session_id: sessionId,
52
+ created_at: new Date().toISOString(),
53
+ stories: stories.map((s, i) => ({
54
+ id: s.id || `HU-${Date.now()}-${i}`,
55
+ status: "pending",
56
+ original: { text: s.text },
57
+ blocked_by: s.blocked_by || [],
58
+ certified: null,
59
+ quality: null,
60
+ context_requests: [],
61
+ created_at: new Date().toISOString(),
62
+ updated_at: new Date().toISOString()
63
+ }))
64
+ };
65
+
66
+ await fs.writeFile(path.join(dir, "batch.json"), JSON.stringify(batch, null, 2));
67
+ return batch;
68
+ }
69
+
70
+ /**
71
+ * Load an existing HU batch from disk.
72
+ * @param {string} sessionId - The session identifier.
73
+ * @returns {Promise<object>} The loaded batch object.
74
+ */
75
+ export async function loadHuBatch(sessionId) {
76
+ const file = path.join(getHuDir(), sessionId, "batch.json");
77
+ const raw = await fs.readFile(file, "utf8");
78
+ return JSON.parse(raw);
79
+ }
80
+
81
+ /**
82
+ * Save a batch back to disk.
83
+ *
84
+ * Ensures the target directory exists before writing — the previous
85
+ * implementation assumed createHuBatch had already done the mkdir,
86
+ * which holds for the auto-HU path but NOT for plan-driven runs:
87
+ * `kj run --plan <id>` derives a batchSessionId from the plan id,
88
+ * loads the (non-existent) batch.json, falls back to in-memory, then
89
+ * crashes here with ENOENT on the first save attempt because no one
90
+ * created `~/.karajan/hu-stories/<sessionId>/`. The fix is one
91
+ * mkdir -p; cheap and idempotent.
92
+ *
93
+ * @param {string} sessionId - The session identifier.
94
+ * @param {object} batch - The batch object to persist.
95
+ * @returns {Promise<void>}
96
+ */
97
+ export async function saveHuBatch(sessionId, batch) {
98
+ const dir = path.join(getHuDir(), sessionId);
99
+ await fs.mkdir(dir, { recursive: true });
100
+ batch.updated_at = new Date().toISOString();
101
+ await fs.writeFile(path.join(dir, "batch.json"), JSON.stringify(batch, null, 2));
102
+ }
103
+
104
+ /**
105
+ * Update the status of a single story within a batch.
106
+ * @param {object} batch - The batch object.
107
+ * @param {string} storyId - Story ID to update.
108
+ * @param {string} status - New status value.
109
+ * @param {object} [extra={}] - Additional fields to merge.
110
+ * @returns {object} The updated story.
111
+ */
112
+ export function updateStoryStatus(batch, storyId, status, extra = {}) {
113
+ const story = batch.stories.find(s => s.id === storyId);
114
+ if (!story) throw new Error(`Story ${storyId} not found`);
115
+ story.status = status;
116
+ const now = new Date().toISOString();
117
+ story.statusChangedAt = now;
118
+ story.updated_at = now;
119
+ Object.assign(story, extra);
120
+ return story;
121
+ }
122
+
123
+ /**
124
+ * Store quality scores on a story.
125
+ * @param {object} batch - The batch object.
126
+ * @param {string} storyId - Story ID.
127
+ * @param {object} quality - Quality scores object.
128
+ * @returns {object} The updated story.
129
+ */
130
+ export function updateStoryQuality(batch, storyId, quality) {
131
+ const story = batch.stories.find(s => s.id === storyId);
132
+ if (!story) throw new Error(`Story ${storyId} not found`);
133
+ story.quality = { ...quality, evaluated_at: new Date().toISOString() };
134
+ story.updated_at = new Date().toISOString();
135
+ return story;
136
+ }
137
+
138
+ /**
139
+ * Mark a story as certified with the provided certified data.
140
+ * @param {object} batch - The batch object.
141
+ * @param {string} storyId - Story ID.
142
+ * @param {object} certified - Certified HU data.
143
+ * @returns {object} The updated story.
144
+ */
145
+ export function updateStoryCertified(batch, storyId, certified) {
146
+ const story = batch.stories.find(s => s.id === storyId);
147
+ if (!story) throw new Error(`Story ${storyId} not found`);
148
+ story.certified = certified;
149
+ story.status = "certified";
150
+ story.updated_at = new Date().toISOString();
151
+ return story;
152
+ }
153
+
154
+ /**
155
+ * Add a context request to a story and set its status to needs_context.
156
+ * @param {object} batch - The batch object.
157
+ * @param {string} storyId - Story ID.
158
+ * @param {{fields_needed: string[], question: string}} request - Context request.
159
+ * @returns {object} The updated story.
160
+ */
161
+ export function addContextRequest(batch, storyId, request) {
162
+ const story = batch.stories.find(s => s.id === storyId);
163
+ if (!story) throw new Error(`Story ${storyId} not found`);
164
+ story.context_requests.push({
165
+ requested_at: new Date().toISOString(),
166
+ fields_needed: request.fields_needed,
167
+ question_to_fde: request.question,
168
+ answered_at: null,
169
+ answer: null
170
+ });
171
+ story.status = "needs_context";
172
+ story.updated_at = new Date().toISOString();
173
+ return story;
174
+ }
175
+
176
+ /**
177
+ * Answer the most recent pending context request and reset status to pending.
178
+ * @param {object} batch - The batch object.
179
+ * @param {string} storyId - Story ID.
180
+ * @param {string} answer - The FDE's answer.
181
+ * @returns {object} The updated story.
182
+ */
183
+ export function answerContextRequest(batch, storyId, answer) {
184
+ const story = batch.stories.find(s => s.id === storyId);
185
+ if (!story) throw new Error(`Story ${storyId} not found`);
186
+ const pending = story.context_requests.find(r => !r.answered_at);
187
+ if (pending) {
188
+ pending.answered_at = new Date().toISOString();
189
+ pending.answer = answer;
190
+ }
191
+ story.status = "pending"; // back to pending for re-evaluation
192
+ story.updated_at = new Date().toISOString();
193
+ return story;
194
+ }
195
+
196
+ /**
197
+ * Create a lightweight history record for a pipeline run.
198
+ * Stores a minimal single-HU batch in the same hu-stories directory
199
+ * so the HU Board can pick it up alongside full batches.
200
+ * @param {string} sessionId - The session identifier.
201
+ * @param {{task: string, result: string, approved: boolean, summary?: string, timestamp?: string}} data
202
+ * @returns {Promise<object>} The created batch object.
203
+ */
204
+ export async function createHistoryRecord(sessionId, { task, result, approved, summary, timestamp }) {
205
+ const ts = timestamp || new Date().toISOString();
206
+ const dir = path.join(getHuDir(), sessionId);
207
+ await fs.mkdir(dir, { recursive: true });
208
+
209
+ const batch = {
210
+ session_id: sessionId,
211
+ created_at: ts,
212
+ stories: [
213
+ {
214
+ id: `HU-hist-${sessionId}`,
215
+ status: approved ? "certified" : "failed",
216
+ original: { text: task },
217
+ blocked_by: [],
218
+ certified: approved ? { summary: summary || result } : null,
219
+ quality: null,
220
+ context_requests: [],
221
+ created_at: ts,
222
+ updated_at: ts
223
+ }
224
+ ],
225
+ history: {
226
+ task,
227
+ result,
228
+ approved,
229
+ summary: summary || null,
230
+ timestamp: ts
231
+ }
232
+ };
233
+
234
+ await fs.writeFile(path.join(dir, "batch.json"), JSON.stringify(batch, null, 2));
235
+ return batch;
236
+ }
237
+
238
+ /* ── Splitting metadata ──────────────────────────────────────────── */
239
+
240
+ /**
241
+ * Add splitting metadata to a story within a batch.
242
+ * Used to track the relationship between an original HU and its sub-HUs
243
+ * after a split operation.
244
+ *
245
+ * @param {object} batch - The batch object.
246
+ * @param {string} huId - Story ID to annotate.
247
+ * @param {{ original_hu_id?: string, split_children?: string[], indicators_detected?: string[], heuristic_applied?: string, split_confirmed_by_fde?: boolean, validation?: object }} metadata - Splitting metadata.
248
+ * @returns {object} The updated story.
249
+ */
250
+ export function addSplittingMetadata(batch, huId, metadata) {
251
+ const story = batch.stories.find(s => s.id === huId);
252
+ if (!story) throw new Error(`Story ${huId} not found`);
253
+ story.splitting = { ...(story.splitting || {}), ...metadata };
254
+ story.updated_at = new Date().toISOString();
255
+ return story;
256
+ }
257
+
258
+ /* ── Manual HU management ─────────────────────────────────────────── */
259
+
260
+ /**
261
+ * Detect project info from the given directory.
262
+ * @param {string} cwd - Directory to detect project from.
263
+ * @returns {Promise<{ name: string, remoteUrl: string|null }>}
264
+ */
265
+ export async function detectProject(cwd) {
266
+ const name = path.basename(cwd);
267
+ let remoteUrl = null;
268
+ try {
269
+ const { stdout } = await execFileAsync("git", ["remote", "get-url", "origin"], { cwd, encoding: "utf8" });
270
+ remoteUrl = stdout.trim();
271
+ } catch { /* not a git repo or no remote */ }
272
+ return { name, remoteUrl };
273
+ }
274
+
275
+ /**
276
+ * Derive a project slug from a directory path.
277
+ * @param {string} projectDir - Absolute path to the project.
278
+ * @returns {string}
279
+ */
280
+ function projectSlug(projectDir) {
281
+ return path.basename(projectDir);
282
+ }
283
+
284
+ /**
285
+ * Get the batch file path for a project.
286
+ * @param {string} projectDir
287
+ * @returns {string}
288
+ */
289
+ function projectBatchPath(projectDir) {
290
+ return path.join(getHuDir(), projectSlug(projectDir), "batch.json");
291
+ }
292
+
293
+ /**
294
+ * Load the project batch, or return a fresh empty batch if none exists.
295
+ * @param {string} projectDir
296
+ * @returns {Promise<object>}
297
+ */
298
+ async function loadProjectBatch(projectDir) {
299
+ const filePath = projectBatchPath(projectDir);
300
+ try {
301
+ const raw = await fs.readFile(filePath, "utf8");
302
+ return JSON.parse(raw);
303
+ } catch { /* no saved batch for this project */
304
+ return {
305
+ project: projectSlug(projectDir),
306
+ created_at: new Date().toISOString(),
307
+ stories: []
308
+ };
309
+ }
310
+ }
311
+
312
+ /**
313
+ * Save a project batch to disk (auto-creates directory).
314
+ * @param {string} projectDir
315
+ * @param {object} batch
316
+ */
317
+ async function saveProjectBatch(projectDir, batch) {
318
+ const filePath = projectBatchPath(projectDir);
319
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
320
+ batch.updated_at = new Date().toISOString();
321
+ await fs.writeFile(filePath, JSON.stringify(batch, null, 2));
322
+ }
323
+
324
+ /**
325
+ * Create a manual HU (user story) for a project.
326
+ * Auto-creates the batch file if it doesn't exist.
327
+ * @param {string} projectDir
328
+ * @param {{ title: string, description?: string, status?: string, acceptanceCriteria?: string }} data
329
+ * @returns {Promise<object>} The created HU.
330
+ */
331
+ export async function createManualHu(projectDir, { title, description, status, acceptanceCriteria }) {
332
+ if (!title) throw new Error("title is required to create a HU");
333
+ const batch = await loadProjectBatch(projectDir);
334
+ const now = new Date().toISOString();
335
+ const hu = {
336
+ id: `HU-${Date.now()}-${batch.stories.length}`,
337
+ title,
338
+ description: description || "",
339
+ status: status || HU_STATUS.PENDING,
340
+ acceptanceCriteria: acceptanceCriteria || "",
341
+ createdAt: now,
342
+ updatedAt: now
343
+ };
344
+ batch.stories.push(hu);
345
+ await saveProjectBatch(projectDir, batch);
346
+ return hu;
347
+ }
348
+
349
+ /**
350
+ * List all HUs for a project.
351
+ * @param {string} projectDir
352
+ * @returns {Promise<Array<{ id: string, title: string, status: string, createdAt: string }>>}
353
+ */
354
+ export async function listHus(projectDir) {
355
+ const batch = await loadProjectBatch(projectDir);
356
+ return batch.stories.map(s => ({
357
+ id: s.id,
358
+ title: s.title,
359
+ status: s.status,
360
+ createdAt: s.createdAt
361
+ }));
362
+ }
363
+
364
+ /**
365
+ * Update the status of a specific HU.
366
+ * @param {string} projectDir
367
+ * @param {string} huId
368
+ * @param {string} status
369
+ * @returns {Promise<object>} The updated HU.
370
+ */
371
+ export async function updateHuStatus(projectDir, huId, status) {
372
+ const batch = await loadProjectBatch(projectDir);
373
+ const hu = batch.stories.find(s => s.id === huId);
374
+ if (!hu) throw new Error(`HU ${huId} not found`);
375
+ hu.status = status;
376
+ hu.updatedAt = new Date().toISOString();
377
+ await saveProjectBatch(projectDir, batch);
378
+ return hu;
379
+ }
380
+
381
+ /**
382
+ * Get a single HU by id.
383
+ * @param {string} projectDir
384
+ * @param {string} huId
385
+ * @returns {Promise<object>}
386
+ */
387
+ export async function getHu(projectDir, huId) {
388
+ const batch = await loadProjectBatch(projectDir);
389
+ const hu = batch.stories.find(s => s.id === huId);
390
+ if (!hu) throw new Error(`HU ${huId} not found`);
391
+ return hu;
392
+ }
@@ -0,0 +1,59 @@
1
+ /**
2
+ * PAR-G (KJC-TSK-0630): make a freshly created lane worktree operative.
3
+ *
4
+ * `git worktree add` produces a clean checkout: no node_modules, no
5
+ * initialized submodules — and a container/bind-mounted process cannot
6
+ * init them itself because the worktree's real .git lives in the parent
7
+ * repo (gotcha reported by Jorge del Casar's worktree-docker-envs skill).
8
+ * Without this step, --parallel lanes die on the first `npm test` in any
9
+ * real project.
10
+ *
11
+ * Best-effort by contract: a failed or slow bootstrap warns and the lane
12
+ * continues — the acceptance tests deliver the real verdict.
13
+ */
14
+ import { existsSync } from "node:fs";
15
+ import { join } from "node:path";
16
+ import { runCommand } from "../utils/process.js";
17
+
18
+ const STEP_TIMEOUT_MS = 5 * 60 * 1000;
19
+
20
+ /**
21
+ * @param {object} params
22
+ * @param {string} params.worktreePath Absolute path of the lane worktree.
23
+ * @param {string|null} [params.setupCommand] session.worktree_setup — wins over auto-detect.
24
+ * @param {object|null} [params.logger]
25
+ * @param {number} [params.timeoutMs]
26
+ * @param {Function} [params.run] Injectable runner (tests).
27
+ * @returns {Promise<{ok: boolean, steps: string[], warnings: string[]}>}
28
+ */
29
+ export async function bootstrapWorktree({ worktreePath, setupCommand = null, logger = null, timeoutMs = STEP_TIMEOUT_MS, run = runCommand }) {
30
+ const warnings = [];
31
+ const steps = [];
32
+
33
+ if (existsSync(join(worktreePath, ".gitmodules"))) {
34
+ steps.push({ name: "submodules", cmd: "git", args: ["submodule", "update", "--init", "--recursive"] });
35
+ }
36
+
37
+ const explicit = typeof setupCommand === "string" && setupCommand.trim() ? setupCommand.trim() : null;
38
+ if (explicit) {
39
+ steps.push({ name: "setup", cmd: "sh", args: ["-c", explicit] });
40
+ } else if (existsSync(join(worktreePath, "package-lock.json"))) {
41
+ steps.push({ name: "deps", cmd: "npm", args: ["ci", "--no-audit", "--no-fund"] });
42
+ }
43
+
44
+ for (const step of steps) {
45
+ try {
46
+ const res = await run(step.cmd, step.args, { cwd: worktreePath, timeout: timeoutMs });
47
+ if (res.exitCode !== 0) {
48
+ warnings.push(`${step.name} failed (exit ${res.exitCode}): ${String(res.stderr || res.stdout || "").slice(0, 200)}`);
49
+ } else {
50
+ logger?.info?.(`worktree bootstrap: ${step.name} ok`);
51
+ }
52
+ } catch (err) {
53
+ warnings.push(`${step.name} threw: ${err.message}`);
54
+ }
55
+ }
56
+
57
+ for (const w of warnings) logger?.warn?.(`worktree bootstrap: ${w} — lane continues`);
58
+ return { ok: warnings.length === 0, steps: steps.map((s) => s.name), warnings };
59
+ }
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Identity lock — bootstrap (IDN-A, KJC-TSK-0762). Runs at the end of
3
+ * `kj harden` (and therefore `kj env install`): if this clone has no declared
4
+ * identity, capture it — but ONLY with a human confirming on a TTY. Headless
5
+ * runs never bind blindly (the first real `set --yes` bound a clone to an
6
+ * account another session had switched to); they report the pending step
7
+ * with the exact command instead. Fail-loud, never a guess.
8
+ */
9
+
10
+ import { readIdentity, writeIdentity } from "./store.js";
11
+ import { activeGhUser, effectiveGitEmail } from "./detect.js";
12
+ import { createWizard, isTTY } from "../utils/wizard.js";
13
+
14
+ /**
15
+ * @param {{projectDir: string, logger?: object, deps?: object}} args
16
+ * @returns {Promise<{declared: boolean, identity: object|null, pending: string|null}>}
17
+ */
18
+ export async function ensureIdentity({ projectDir, logger = null, deps = {} }) {
19
+ const existing = readIdentity(projectDir);
20
+ if (existing) return { declared: true, identity: existing, pending: null };
21
+
22
+ const gh = activeGhUser(deps.hostsPath ? { hostsPath: deps.hostsPath } : {});
23
+ const email = effectiveGitEmail(projectDir, deps.gitFn ? { gitFn: deps.gitFn } : {});
24
+ const hint = `kj identity set --gh ${gh ?? "<user>"} --email ${email ?? "<email>"}`;
25
+ const tty = (deps.isTTY || isTTY)();
26
+
27
+ if (!tty || !gh || !email) {
28
+ const why = !gh || !email ? "no active gh session or git email" : "non-interactive run";
29
+ const pending = `identity not declared for this clone (${why}) — run: ${hint}`;
30
+ logger?.warn?.(`kj identity: ${pending}`);
31
+ return { declared: false, identity: null, pending };
32
+ }
33
+
34
+ const wizard = (deps.makeWizard || createWizard)();
35
+ try {
36
+ const ok = await wizard.confirm(`Bind this clone to gh ${gh} / git ${email}? (other sessions may switch gh accounts — verify)`, true);
37
+ if (!ok) {
38
+ const pending = `identity not declared (declined) — run: ${hint}`;
39
+ logger?.warn?.(`kj identity: ${pending}`);
40
+ return { declared: false, identity: null, pending };
41
+ }
42
+ } finally {
43
+ wizard.close();
44
+ }
45
+ const identity = writeIdentity(projectDir, { gh_user: gh, git_email: email });
46
+ logger?.info?.(`kj identity: declared gh ${gh} / git ${email} → .karajan/identity.local.yml (ignored by git)`);
47
+ return { declared: true, identity, pending: null };
48
+ }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Identity lock — compare (IDN-A, KJC-TSK-0762). Pure: declared vs effective
3
+ * → {ok, mismatches}. Every mismatch carries the LITERAL remedy, because the
4
+ * gate (IDN-B) and the hooks (IDN-C) print it instead of auto-switching —
5
+ * changing the user's keyring is the user's act, never the agent's.
6
+ */
7
+
8
+ /**
9
+ * @param {{gh_user: string, git_email: string}|null} declared
10
+ * @param {{gh_user: string|null, git_email: string|null}} effective
11
+ * @returns {{ok: boolean, mismatches: Array<{field: string, declared: string|null, effective: string|null, remedy: string}>}}
12
+ */
13
+ export function compareIdentity(declared, effective) {
14
+ if (!declared) {
15
+ return {
16
+ ok: false,
17
+ mismatches: [{ field: "identity", declared: null, effective: null, remedy: "kj identity set — this clone has no declared identity yet" }],
18
+ };
19
+ }
20
+ const mismatches = [];
21
+ if (effective.gh_user !== declared.gh_user) {
22
+ mismatches.push({
23
+ field: "gh_user",
24
+ declared: declared.gh_user,
25
+ effective: effective.gh_user ?? null,
26
+ remedy: effective.gh_user ? `gh auth switch --user ${declared.gh_user}` : `gh auth login (as ${declared.gh_user}) or gh auth switch --user ${declared.gh_user}`,
27
+ });
28
+ }
29
+ if (effective.git_email !== declared.git_email) {
30
+ mismatches.push({
31
+ field: "git_email",
32
+ declared: declared.git_email,
33
+ effective: effective.git_email ?? null,
34
+ remedy: `git config user.email ${declared.git_email} (or -c user.email=${declared.git_email} on the command)`,
35
+ });
36
+ }
37
+ return { ok: mismatches.length === 0, mismatches };
38
+ }
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Identity lock — detect (IDN-A, KJC-TSK-0762). What is EFFECTIVE right now,
3
+ * with no network and no spawned `gh`: the active gh account is read from
4
+ * gh's own hosts.yml (the file `gh auth switch` mutates), the git email from
5
+ * `git config user.email`. Both return null when unknown — never a guess.
6
+ */
7
+
8
+ import { existsSync, readFileSync } from "node:fs";
9
+ import { execFileSync } from "node:child_process";
10
+ import { join } from "node:path";
11
+ import { homedir } from "node:os";
12
+ import yaml from "js-yaml";
13
+
14
+ export function defaultHostsPath() {
15
+ const base = process.env.GH_CONFIG_DIR || join(process.env.XDG_CONFIG_HOME || join(homedir(), ".config"), "gh");
16
+ return join(base, "hosts.yml");
17
+ }
18
+
19
+ /**
20
+ * @param {{hostsPath?: string, host?: string}} [opts]
21
+ * @returns {string|null} active gh login for the host, null without a session
22
+ */
23
+ export function activeGhUser({ hostsPath = defaultHostsPath(), host = "github.com" } = {}) {
24
+ if (!existsSync(hostsPath)) return null;
25
+ try {
26
+ const parsed = yaml.load(readFileSync(hostsPath, "utf8"));
27
+ const user = parsed?.[host]?.user;
28
+ return typeof user === "string" && user.length > 0 ? user : null;
29
+ } catch {
30
+ return null;
31
+ }
32
+ }
33
+
34
+ const defaultGitFn = (projectDir) =>
35
+ execFileSync("git", ["config", "--get", "user.email"], { cwd: projectDir, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
36
+
37
+ /**
38
+ * @param {string} projectDir
39
+ * @param {{gitFn?: (projectDir: string) => string}} [opts]
40
+ * @returns {string|null}
41
+ */
42
+ export function effectiveGitEmail(projectDir, { gitFn = defaultGitFn } = {}) {
43
+ try {
44
+ // --get yields the single effective value; keep the last line anyway so a
45
+ // multi-line answer from an odd config can never leak a newline into it.
46
+ const out = String(gitFn(projectDir) || "").trim().split("\n").at(-1).trim();
47
+ return out.length > 0 ? out : null;
48
+ } catch {
49
+ return null;
50
+ }
51
+ }
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Identity lock — store (IDN-A, KJC-TSK-0762, epic KJC-PCS-0079).
3
+ *
4
+ * Each CLONE declares the identity it is worked with: the gh account and the
5
+ * git email. It is per developer, not per project, so it lives in
6
+ * `.karajan/identity.local.yml`, never tracked (this module keeps it in the
7
+ * .gitignore). Born from the 2026-08-20 incident: one `gh` call without an
8
+ * explicit account switch posted as a client account on a public repo.
9
+ */
10
+
11
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
12
+ import { join } from "node:path";
13
+ import yaml from "js-yaml";
14
+
15
+ export const IDENTITY_FILE = ".karajan/identity.local.yml";
16
+
17
+ /** @param {string} projectDir */
18
+ export function identityPath(projectDir) {
19
+ return join(projectDir, ".karajan", "identity.local.yml");
20
+ }
21
+
22
+ /**
23
+ * @param {string} projectDir
24
+ * @returns {{gh_user: string, git_email: string, declared_at: string}|null}
25
+ */
26
+ export function readIdentity(projectDir) {
27
+ const p = identityPath(projectDir);
28
+ if (!existsSync(p)) return null;
29
+ let parsed;
30
+ try {
31
+ parsed = yaml.load(readFileSync(p, "utf8"));
32
+ } catch {
33
+ return null; // corrupt or half-written file = no identity (review catch)
34
+ }
35
+ if (!parsed || typeof parsed !== "object" || !parsed.gh_user || !parsed.git_email) return null;
36
+ return { gh_user: String(parsed.gh_user), git_email: String(parsed.git_email), declared_at: String(parsed.declared_at || "") };
37
+ }
38
+
39
+ /**
40
+ * Write the declaration and make sure it never gets tracked. Fails loud on
41
+ * an incomplete identity — a half-declared lock is no lock.
42
+ * @param {string} projectDir
43
+ * @param {{gh_user: string, git_email: string}} identity
44
+ */
45
+ export function writeIdentity(projectDir, identity) {
46
+ for (const field of ["gh_user", "git_email"]) {
47
+ if (!identity?.[field] || typeof identity[field] !== "string") {
48
+ throw new Error(`identity: "${field}" is required (got ${JSON.stringify(identity?.[field])})`);
49
+ }
50
+ }
51
+ // Ignore FIRST, write SECOND (review catch): if the ignore step fails, no
52
+ // unignored identity file is ever left on disk for git to pick up.
53
+ ensureIgnored(projectDir);
54
+ mkdirSync(join(projectDir, ".karajan"), { recursive: true });
55
+ const record = { gh_user: identity.gh_user, git_email: identity.git_email, declared_at: new Date().toISOString() };
56
+ writeFileSync(identityPath(projectDir), yaml.dump(record, { lineWidth: 120 }), "utf8");
57
+ return record;
58
+ }
59
+
60
+ function ensureIgnored(projectDir) {
61
+ const ignorePath = join(projectDir, ".gitignore");
62
+ const current = existsSync(ignorePath) ? readFileSync(ignorePath, "utf8") : "";
63
+ if (current.split("\n").some((line) => line.trim() === IDENTITY_FILE)) return;
64
+ const sep = current.length === 0 || current.endsWith("\n") ? "" : "\n";
65
+ writeFileSync(ignorePath, `${current}${sep}${IDENTITY_FILE}\n`, "utf8");
66
+ }