@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,203 @@
1
+ /**
2
+ * `kj harden` — install the quality harness (git hooks) into any repo.
3
+ *
4
+ * Thin CLI layer over harden-engine (KJC-TSK-0555): resolves stack-aware
5
+ * lint/format/test commands, runs the installer and reports. Config files
6
+ * (eslint/prettier) and CI gates land in later slices (H-C / H-D).
7
+ */
8
+
9
+ import { existsSync, readFileSync } from "node:fs";
10
+ import { join } from "node:path";
11
+
12
+ import { loadConfig } from "../config.js";
13
+ import { resolveTestOnPush } from "../harden/test-on-push.js";
14
+ import { compareHarden, formatAdvisoryReport } from "../harden/advisory.js";
15
+ import { interactiveHarden } from "../harden/interactive.js";
16
+ import { createWizard, isTTY } from "../utils/wizard.js";
17
+ import { installConfigsForRoots } from "../harden/config-engine.js";
18
+ import { installGuidelines } from "../harden/guidelines-engine.js";
19
+ import { commandsForLanguage } from "../harden/hook-commands.js";
20
+ import { installHooks } from "../harden/harden-engine.js";
21
+ import { installHarnessHooks } from "../harden/harness-hooks.js";
22
+ import { installSentinelHooks } from "../harden/sentinel-hooks.js";
23
+ import { detectStackRoots } from "../harden/stack-roots.js";
24
+ import { installWorkflows } from "../harden/workflow-engine.js";
25
+ import { detectTestFramework } from "../utils/project-detect.js";
26
+ import { ensureIdentity } from "../identity/bootstrap.js";
27
+
28
+ const JS_TEST_CMD = {
29
+ vitest: "npx vitest run",
30
+ jest: "npx jest",
31
+ mocha: "npx mocha",
32
+ };
33
+
34
+ /**
35
+ * Per-repo harden scope, persisted in package.json `kj.harden` so a repo with
36
+ * sub-tools (e.g. a python wrapper) excludes them once instead of on every
37
+ * invocation (KJC-TSK-0564). CLI flags are merged on top.
38
+ */
39
+ function readHardenConfig(projectDir) {
40
+ const pkgPath = join(projectDir, "package.json");
41
+ if (!existsSync(pkgPath)) return {};
42
+ try {
43
+ return JSON.parse(readFileSync(pkgPath, "utf8")).kj?.harden ?? {};
44
+ } catch {
45
+ return {};
46
+ }
47
+ }
48
+
49
+ /**
50
+ * Resolve the hook's lint/format/test commands for the primary language.
51
+ * Non-JS stacks use their native toolchain (go/ruff/…); JS/TS is built from
52
+ * the project's own package.json scripts so no npm command is ever assumed.
53
+ */
54
+ export async function resolveCmds(projectDir, language) {
55
+ const lang = language ?? detectStackRoots(projectDir)[0]?.language ?? null;
56
+ const cmds = { ...commandsForLanguage(lang) };
57
+ if (lang !== "javascript" && lang !== "typescript") return cmds;
58
+
59
+ const pkgPath = join(projectDir, "package.json");
60
+ if (existsSync(pkgPath)) {
61
+ try {
62
+ const scripts = JSON.parse(readFileSync(pkgPath, "utf8")).scripts ?? {};
63
+ if (scripts.lint) cmds.lint = "npm run -s lint";
64
+ if (scripts["format:check"]) cmds.format = "npm run -s format:check";
65
+ else if (scripts.format) cmds.format = "npm run -s format";
66
+ if (scripts.test) cmds.test = "npm test";
67
+ } catch {
68
+ /* unreadable package.json → fall back to framework detection */
69
+ }
70
+ }
71
+ if (!cmds.test) {
72
+ const { framework } = await detectTestFramework(projectDir);
73
+ if (framework && JS_TEST_CMD[framework]) cmds.test = JS_TEST_CMD[framework];
74
+ }
75
+ return cmds;
76
+ }
77
+
78
+ export async function hardenCommand({
79
+ projectDir = process.cwd(),
80
+ profile = "standard",
81
+ config = true,
82
+ ci = true,
83
+ guidelines = true,
84
+ mutation = false,
85
+ dryRun = false,
86
+ json = false,
87
+ report = false,
88
+ interactive = false,
89
+ only = [],
90
+ exclude = [],
91
+ logger = console,
92
+ } = {}) {
93
+ const repoCfg = readHardenConfig(projectDir);
94
+ const onlyDirs = [...(repoCfg.only ?? []), ...only];
95
+ const excludeDirs = [...(repoCfg.exclude ?? []), ...exclude];
96
+
97
+ // --report is read-only: compare against the kj standard and print/emit the
98
+ // advisory (Advisory B, KJC-TSK-0566), honouring the same scope as an install
99
+ // so it never proposes a root that `kj harden` would skip. Writes nothing.
100
+ if (report) {
101
+ const result = compareHarden({ projectDir, profile, only: onlyDirs, exclude: excludeDirs });
102
+ if (json) logger.info?.(JSON.stringify(result));
103
+ else for (const line of formatAdvisoryReport(result)) logger.info?.(line);
104
+ return { ok: true, report: true, ...result };
105
+ }
106
+
107
+ // --interactive: adopt the kj standard piece by piece, default-safe (keep the
108
+ // user's own). Only meaningful with a TTY — without one (CI, --json) we fall
109
+ // through to the normal seed-if-absent install so nothing breaks (KJC-TSK-0567).
110
+ if (interactive && isTTY() && !json) {
111
+ const wizard = createWizard();
112
+ try {
113
+ return await interactiveHarden({
114
+ projectDir,
115
+ profile,
116
+ only: onlyDirs,
117
+ exclude: excludeDirs,
118
+ ask: (prompt, def) => wizard.confirm(prompt, def),
119
+ logger,
120
+ });
121
+ } finally {
122
+ wizard.close();
123
+ }
124
+ }
125
+
126
+ const roots = detectStackRoots(projectDir, { only: onlyDirs, exclude: excludeDirs });
127
+ const cmds = await resolveCmds(projectDir, roots[0]?.language ?? null);
128
+ // KJC-TSK-0647: CI already running the suite per PR ⇒ pre-push drops its
129
+ // test command (false-red source under local parallelism); opt back in
130
+ // via package.json kj.harden.test_on_push.
131
+ const top = resolveTestOnPush({ projectDir, repoCfg, testCmd: cmds.test });
132
+ if (top.reason) {
133
+ logger.info?.(`kj harden: ${top.reason}`);
134
+ cmds.test = undefined;
135
+ }
136
+ // KJC-TSK-0648: branch-first guard — the base branch only moves via PR.
137
+ // Resolved from the project's kj config (default "main"); best-effort so
138
+ // harden keeps working on repos that never ran kj init.
139
+ let baseBranch = "main";
140
+ try {
141
+ baseBranch = (await loadConfig(projectDir))?.base_branch || "main";
142
+ } catch { /* no kj config — default stands */ }
143
+ let result;
144
+ try {
145
+ result = await installHooks({ projectDir, profile, cmds, dryRun, baseBranch });
146
+ // KJC-TSK-0710 — the TOOL gate: rules imposed at tool time (Claude Code
147
+ // PreToolUse). Standard+ only; minimal stays hooks-lite.
148
+ if (profile !== "minimal" && !dryRun) {
149
+ const hh = installHarnessHooks({ projectDir, logger });
150
+ result.harnessHooks = hh.wired ? "wired" : "script-only";
151
+ // KJC-TSK-0713 — the Sentinel: method state + Stop gate (turn cannot
152
+ // end red). Same Claude-only harness surface as the tool gate.
153
+ const sh = installSentinelHooks({ projectDir, logger });
154
+ result.sentinelHooks = sh.wired ? "wired" : "script-only";
155
+ }
156
+ } catch (err) {
157
+ if (json) logger.info?.(JSON.stringify({ ok: false, error: err.message }));
158
+ else logger.error?.(`kj harden: ${err.message}`);
159
+ return { ok: false, error: err.message };
160
+ }
161
+
162
+ // Config (lint/format/commit) ships with standard+, per language root so a
163
+ // fullstack monorepo is hardened on every side, not just one.
164
+ const withConfig = config && profile !== "minimal";
165
+ const cfg = withConfig ? installConfigsForRoots({ projectDir, roots, dryRun }) : null;
166
+ const withCi = ci && profile !== "minimal";
167
+ const wf = withCi
168
+ ? installWorkflows({ projectDir, language: roots[0]?.language ?? null, profile, mutation, dryRun })
169
+ : null;
170
+ const withGuidelines = guidelines && profile !== "minimal";
171
+ const gl = withGuidelines ? installGuidelines({ projectDir, dryRun }) : null;
172
+ const out = {
173
+ ok: true,
174
+ ...result,
175
+ configs: cfg?.configs ?? [],
176
+ workflows: wf?.workflows ?? [],
177
+ guidelines: gl?.guidelines ?? [],
178
+ };
179
+
180
+ if (json) {
181
+ logger.info?.(JSON.stringify(out));
182
+ return out;
183
+ }
184
+
185
+ const verb = dryRun ? "would install" : "installed";
186
+ logger.info?.(`kj harden (${profile}) — ${verb} ${result.hooks.length} hook(s) → ${result.hooksPath}`);
187
+ for (const h of result.hooks) logger.info?.(` • ${h.hook}: ${h.action}`);
188
+ for (const c of out.configs) {
189
+ const note = c.note ? ` (${c.note})` : "";
190
+ logger.info?.(` • ${c.file}: ${c.action}${note}`);
191
+ }
192
+ for (const w of out.workflows) logger.info?.(` • ${w.file}: ${w.action}`);
193
+ for (const g of out.guidelines) logger.info?.(` • ${g.file}: ${g.action}`);
194
+ if (!dryRun) logger.info?.("core.hooksPath set. Verify later with `kj check`.");
195
+ // IDN-A (KJC-TSK-0762): a hardened clone declares who works it. Captured
196
+ // only with a human confirming; headless runs get the pending command.
197
+ if (!dryRun) {
198
+ const id = await ensureIdentity({ projectDir, logger });
199
+ out.identity = id.declared ? id.identity : null;
200
+ if (id.pending) out.identityPending = id.pending;
201
+ }
202
+ return out;
203
+ }
@@ -0,0 +1,210 @@
1
+ /**
2
+ * `kj hu add|move|list` (AB-H, KJC-TSK-0658) — board writes for the brain.
3
+ * The v4 playbook orders "card first", but until now only the headless
4
+ * planner could create HUs. These commands operate on a per-project
5
+ * "brain-backlog" plan (created on first use) so any host agent can track
6
+ * work in the HU Board without the subprocess pipeline.
7
+ */
8
+ import { addHu, updateHuStatus } from "../plan/plan-hu-ops.js";
9
+ import { generatePlanId } from "../plan/plan-id.js";
10
+ import { savePlan, listPlans, loadPlan } from "../plan/plan-store.js";
11
+ import { detectHostAgent } from "../utils/agent-detect.js";
12
+
13
+ // KJC-TSK-0661 (Jorge's friction): every HU records WHO created it — the
14
+ // board must never show work nobody can trace. Host agent env → that agent;
15
+ // a human typing in a terminal → "human"; anything else headless → "agent".
16
+ export function creatorLabel() {
17
+ return detectHostAgent() || (process.stdin.isTTY ? "human" : "agent");
18
+ }
19
+
20
+ export const HU_STATUSES = ["pending", "running", "done", "failed", "skipped"];
21
+ const BACKLOG_NAME = "brain-backlog";
22
+
23
+ // KJC-TSK-0675 (issue #1288): agents that skip `kj hu list` created twins of
24
+ // existing work — sometimes in a DIFFERENT plan. Titles are compared
25
+ // normalized (case/punctuation-insensitive) across every live HU of every
26
+ // plan: identical → refuse; mostly-overlapping tokens → warn with candidates.
27
+ const normTitle = (t) => String(t || "").toLowerCase().replaceAll(/[^\p{L}\p{N}]+/gu, " ").trim();
28
+ const titleTokens = (t) => new Set(normTitle(t).split(" ").filter((w) => w.length > 2));
29
+
30
+ export function findTitleMatches(title, allHus) {
31
+ const norm = normTitle(title);
32
+ const toks = titleTokens(title);
33
+ const identical = [];
34
+ const similar = [];
35
+ for (const h of allHus) {
36
+ if (h.status === "skipped") continue; // discarded cards don't reserve titles
37
+ if (normTitle(h.title) === norm) { identical.push(h); continue; }
38
+ const other = titleTokens(h.title);
39
+ const shared = [...toks].filter((w) => other.has(w)).length;
40
+ const smaller = Math.min(toks.size, other.size);
41
+ if (smaller > 0 && shared / smaller >= 0.8) similar.push(h);
42
+ }
43
+ return { identical, similar };
44
+ }
45
+
46
+ async function backlogPlan(projectDir) {
47
+ const plans = await listPlans(projectDir);
48
+ const existing = plans.find((p) => p.alias === BACKLOG_NAME || p.name === BACKLOG_NAME);
49
+ if (existing) return loadPlan(projectDir, existing.planId);
50
+ const plan = {
51
+ version: 2, planId: generatePlanId(), name: BACKLOG_NAME,
52
+ task: "Host-agent tracked work (v4 environment)",
53
+ status: "ready", hus: [], createdAt: new Date().toISOString(),
54
+ };
55
+ const planId = await savePlan(projectDir, plan);
56
+ return loadPlan(projectDir, planId);
57
+ }
58
+
59
+ export async function huCommand({ config = null, action, args = [], flags = {} }) {
60
+ const projectDir = config?.projectDir || process.cwd();
61
+ const emit = (obj, human) => { console.log(flags.json ? JSON.stringify(obj) : human); return obj; };
62
+
63
+ // KJC-TSK-0684 (issue #1287): with an external board declared, kj never
64
+ // maintains a parallel HU Board — writes are refused with the pointer.
65
+ if (config?.state_backend === "external" && (action === "add" || action === "move")) {
66
+ const name = config?.board?.name || "an external board";
67
+ throw new Error(
68
+ `this project's board lives in ${name} (state_backend: external) — create and move cards there, `
69
+ + `through your agent's MCP/tools. kj does not mirror external boards.`
70
+ );
71
+ }
72
+
73
+ if (action === "list") {
74
+ const plans = await listPlans(projectDir);
75
+ const rows = [];
76
+ for (const meta of plans) {
77
+ const plan = await loadPlan(projectDir, meta.planId);
78
+ for (const h of plan.hus || []) {
79
+ rows.push({
80
+ id: h.id, short_id: h.short_id, title: h.title, status: h.status,
81
+ plan: plan.alias || plan.planId,
82
+ // KJC-TSK-0661: provenance — where a card came from is part of
83
+ // the card. Older HUs predate the stamp: shown as "?".
84
+ created_by: h.created_by || null, created_at: h.createdAt || null,
85
+ });
86
+ }
87
+ }
88
+ if (flags.json) { console.log(JSON.stringify(rows)); return rows; }
89
+ for (const r of rows) {
90
+ const origin = `${r.plan} · by ${r.created_by || "?"}${r.created_at ? ` · ${r.created_at.slice(0, 10)}` : ""}`;
91
+ console.log(`${(r.short_id || r.id).padEnd(28)} ${r.status.padEnd(8)} ${r.title} [${origin}]`);
92
+ }
93
+ if (rows.length === 0) console.log("no HUs yet — create one with: kj hu add \"<story>\"");
94
+ else console.log("→ work one: ask your agent, or kj run --plan <plan> · discard one: kj hu move <id> skipped");
95
+ return rows;
96
+ }
97
+
98
+ if (action === "add") {
99
+ const title = args[0];
100
+ if (!title || !title.trim()) throw new Error("kj hu add requires a title: kj hu add \"<story>\"");
101
+ // Cross-plan title dedup (KJC-TSK-0675) — check BEFORE creating anything.
102
+ const allHus = [];
103
+ for (const meta of await listPlans(projectDir)) {
104
+ const p = await loadPlan(projectDir, meta.planId);
105
+ for (const h of p.hus || []) allHus.push({ ...h, plan: p.alias || p.name || p.planId });
106
+ }
107
+ const { identical, similar } = findTitleMatches(title, allHus);
108
+ if (identical.length > 0) {
109
+ const ref = identical[0];
110
+ throw new Error(
111
+ `An HU with this title already exists: ${ref.short_id || ref.id} (status: ${ref.status}, plan: ${ref.plan}). `
112
+ + `HUs are never duplicated — work that card, move it with: kj hu move ${ref.short_id || ref.id} <status>, `
113
+ + `or run kj hu list before adding.`
114
+ );
115
+ }
116
+ if (similar.length > 0) {
117
+ const plural = similar.length === 1 ? "" : "s";
118
+ const candidates = similar.map((h) => ` · ${h.short_id || h.id} (${h.status}, plan: ${h.plan}) "${h.title}"`).join("\n");
119
+ console.warn(`⚠ possible duplicate${plural} — check before working it:\n${candidates}`);
120
+ }
121
+ const plan = await backlogPlan(projectDir);
122
+ // KJC-TSK-0669 (absolute rule): cards are permanent. The delete-and-
123
+ // recreate "fix" an agent improvises loses history and duplicates ids —
124
+ // refuse it with the norm spelled out.
125
+ if (flags.id) {
126
+ const dup = (plan.hus || []).find((h) => h.short_id === flags.id);
127
+ if (dup) {
128
+ throw new Error(
129
+ `HU "${flags.id}" already exists (status: ${dup.status}). HUs are never deleted or recreated — `
130
+ + `update its state with: kj hu move ${flags.id} <pending|running|done|failed|skipped>, `
131
+ + `or discard it with: kj hu move ${flags.id} skipped`
132
+ );
133
+ }
134
+ }
135
+ // KJC-TSK-0678 (issue #1296): complete HUs in ONE call. --ac / --tests
136
+ // are repeatable AND accept multiline strings; --criteria stays as the
137
+ // legacy single-criterion alias.
138
+ const TASK_TYPES = ["sw", "infra", "doc", "add-tests", "refactor"];
139
+ if (flags.taskType && !TASK_TYPES.includes(flags.taskType)) {
140
+ throw new Error(`invalid --task-type "${flags.taskType}" — valid: ${TASK_TYPES.join(", ")}`);
141
+ }
142
+ const splitLines = (v) => (Array.isArray(v) ? v : v ? [v] : [])
143
+ .flatMap((s) => String(s).split("\n")).map((s) => s.trim()).filter(Boolean);
144
+ const hu = addHu(plan, {
145
+ title,
146
+ short_id: flags.id || null,
147
+ acceptance_criteria: [...splitLines(flags.ac), ...splitLines(flags.criteria)],
148
+ acceptance_tests: splitLines(flags.tests),
149
+ scope: flags.scope || null,
150
+ task_type: flags.taskType || undefined,
151
+ });
152
+ hu.created_by = creatorLabel();
153
+ await savePlan(projectDir, plan);
154
+ const missing = [];
155
+ if (hu.acceptance_criteria.length === 0) missing.push("acceptance criteria (--ac \"...\")");
156
+ if (hu.acceptance_tests.length === 0) missing.push("tests (--tests \"...\")");
157
+ if (missing.length > 0) {
158
+ console.warn(`⚠ incomplete spec — kj run's spec review will flag it. Missing: ${missing.join(", ")}`);
159
+ }
160
+ return emit({
161
+ id: hu.id, short_id: hu.short_id, status: hu.status, created_by: hu.created_by,
162
+ acceptance_criteria: hu.acceptance_criteria, acceptance_tests: hu.acceptance_tests,
163
+ scope: hu.scope, task_type: hu.task_type,
164
+ }, `✓ HU created: ${hu.short_id || hu.id} (pending, by ${hu.created_by}) — it shows up in \`kj board\``);
165
+ }
166
+
167
+ if (action === "move") {
168
+ const [ref, status] = args;
169
+ if (!ref || !status) throw new Error("usage: kj hu move <id> <status>");
170
+ if (!HU_STATUSES.includes(status)) {
171
+ throw new Error(`invalid status "${status}" — valid: ${HU_STATUSES.join(", ")}`);
172
+ }
173
+ // Exact canonical id wins outright (it IS the disambiguator); only then
174
+ // fall back to short_id matches — which can repeat between plans, so
175
+ // silently moving the first hit could move the wrong card.
176
+ const byId = [];
177
+ const byShort = [];
178
+ const running = [];
179
+ for (const meta of await listPlans(projectDir)) {
180
+ const plan = await loadPlan(projectDir, meta.planId);
181
+ for (const hu of plan.hus || []) {
182
+ if (hu.id === ref) byId.push({ plan, hu });
183
+ else if (hu.short_id === ref) byShort.push({ plan, hu });
184
+ if (hu.status === "running") running.push(hu);
185
+ }
186
+ }
187
+ const matches = byId.length > 0 ? byId : byShort;
188
+ if (matches.length === 0) throw new Error(`HU "${ref}" not found — see kj hu list`);
189
+ if (matches.length > 1) {
190
+ const ids = matches.map((m) => m.hu.id).join(", ");
191
+ throw new Error(`"${ref}" is ambiguous (${matches.length} matches: ${ids}) — use the full id`);
192
+ }
193
+ const { plan, hu } = matches[0];
194
+ // KJC-TSK-0688 (MG-C): the nudge fires AT the deviation — a second
195
+ // concurrent task belongs in its own lane, not in the shared tree.
196
+ const others = running.filter((r) => r.id !== hu.id);
197
+ if (status === "running" && hu.status !== "running" && others.length > 0) {
198
+ const slug = String(hu.short_id || hu.id).toLowerCase();
199
+ console.warn(
200
+ `⚠ ${others.map((r) => r.short_id || r.id).join(", ")} ${others.length === 1 ? "is" : "are"} already running — `
201
+ + `a second concurrent task should live in its own lane: kj worktree start ${slug}`
202
+ );
203
+ }
204
+ updateHuStatus(plan, hu.id, status);
205
+ await savePlan(projectDir, plan);
206
+ return emit({ id: hu.id, status }, `✓ ${hu.short_id || hu.id} → ${status}`);
207
+ }
208
+
209
+ throw new Error(`unknown action "${action}" — use: add | move | list`);
210
+ }
@@ -0,0 +1,60 @@
1
+ /**
2
+ * `kj identity show|set` (IDN-A, KJC-TSK-0762, epic KJC-PCS-0079).
3
+ *
4
+ * show — declared identity vs what is ACTIVE now; exit 2 on mismatch or
5
+ * when nothing is declared (scriptable: the gate and hooks reuse it).
6
+ * set — capture the effective gh account + git email (or --gh/--email),
7
+ * confirm on a TTY, write .karajan/identity.local.yml. Never invents:
8
+ * no session and no flags → exit 1.
9
+ */
10
+
11
+ import { readIdentity, writeIdentity } from "../identity/store.js";
12
+ import { activeGhUser, effectiveGitEmail } from "../identity/detect.js";
13
+ import { compareIdentity } from "../identity/compare.js";
14
+ import { createWizard, isTTY } from "../utils/wizard.js";
15
+
16
+ export async function identityCommand({ action = "show", config, flags = {}, deps = {} }) {
17
+ const projectDir = config?.projectDir || process.cwd();
18
+ const log = deps.log || console.log;
19
+ const tty = deps.isTTY || isTTY;
20
+ const detectOpts = { hostsPath: deps.hostsPath, gitFn: deps.gitFn };
21
+ const effective = {
22
+ gh_user: activeGhUser(detectOpts.hostsPath ? { hostsPath: detectOpts.hostsPath } : {}),
23
+ git_email: effectiveGitEmail(projectDir, detectOpts.gitFn ? { gitFn: detectOpts.gitFn } : {}),
24
+ };
25
+
26
+ if (action === "set") {
27
+ const candidate = { gh_user: flags.gh || effective.gh_user, git_email: flags.email || effective.git_email };
28
+ if (!candidate.gh_user || !candidate.git_email) {
29
+ log(`kj identity: cannot declare — gh account: ${candidate.gh_user ?? "no session"}, git email: ${candidate.git_email ?? "none"}. Log in / set git config, or pass --gh <user> --email <email>.`);
30
+ return 1;
31
+ }
32
+ if (tty() && !flags.yes) {
33
+ const wizard = (deps.makeWizard || createWizard)();
34
+ try {
35
+ const ok = await wizard.confirm(`Bind this clone to gh ${candidate.gh_user} / git ${candidate.git_email}?`, true);
36
+ if (!ok) { log("kj identity: not declared."); return 1; }
37
+ } finally { wizard.close(); }
38
+ } else if (!flags.gh || !flags.email) {
39
+ // Proven live on day one: the active gh session had been flipped by
40
+ // ANOTHER session, and --yes bound the clone to the wrong account.
41
+ // Binding without confirmation is allowed, but never silent.
42
+ log("kj identity: WARNING — binding the ACTIVE session as-is without confirmation (another session may have switched it); prefer --gh/--email explicitly and verify with `kj identity show`.");
43
+ }
44
+ writeIdentity(projectDir, candidate);
45
+ log(`kj identity: declared gh ${candidate.gh_user} / git ${candidate.git_email} → .karajan/identity.local.yml (ignored by git).`);
46
+ return 0;
47
+ }
48
+
49
+ const declared = readIdentity(projectDir);
50
+ const result = compareIdentity(declared, effective);
51
+ if (!declared) {
52
+ log("kj identity: no identity declared for this clone — run `kj identity set`.");
53
+ return 2;
54
+ }
55
+ const mark = (field) => (result.mismatches.some((m) => m.field === field) ? "DISTINTA" : "ACTIVA");
56
+ log(`gh_user ${declared.gh_user} [${mark("gh_user")}: ${effective.gh_user ?? "no session"}]`);
57
+ log(`git_email ${declared.git_email} [${mark("git_email")}: ${effective.git_email ?? "none"}]`);
58
+ for (const m of result.mismatches) log(` → ${m.remedy}`);
59
+ return result.ok ? 0 : 2;
60
+ }