@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,70 @@
1
+ /**
2
+ * Node.js runtime version check. Requires Node >= 22 — the Active LTS
3
+ * baseline since Karajan v3.0.0 (KJC-TSK-0500, 2026-06-03). Node 20 was
4
+ * dropped because (a) Node 20 reaches EOL on 2026-04-30 and (b) three
5
+ * dependencies forced the bump: commander 15 needs ≥22.12.0 and
6
+ * better-sqlite3 v12.10+ dropped Node 20 prebuilds. engines.node is
7
+ * ">=22.12.0" — the highest RUNTIME floor. KJC-BUG-0111: it briefly sat
8
+ * at 22.22.1 (lint-staged 17's floor — a devDependency end users never
9
+ * run) and npm silently served karajan-code@2.34.0 to every Node
10
+ * 22.0-22.21 install; keep dev-tool floors out of engines.
11
+ * Strategy: manual — we cannot auto-upgrade the runtime. Users on older
12
+ * Node get a clear upgrade instruction with nvm + brew hints instead of a
13
+ * silent runtime crash.
14
+ */
15
+
16
+ import { STRATEGY } from "./types.js";
17
+
18
+ export const MIN_NODE_MAJOR = 22;
19
+
20
+ /**
21
+ * Accepts a version string in the form "v20.12.1" or "20.12.1" and returns
22
+ * an object { major, minor, patch } or null when the shape is invalid.
23
+ */
24
+ export function parseNodeVersion(versionString) {
25
+ const str = String(versionString || "").trim();
26
+ const m = str.match(/^v?(\d+)\.(\d+)\.(\d+)/);
27
+ if (!m) return null;
28
+ return { major: Number(m[1]), minor: Number(m[2]), patch: Number(m[3]) };
29
+ }
30
+
31
+ /**
32
+ * Create the Node version check. Accepts an optional override of the
33
+ * reported version (useful in tests).
34
+ *
35
+ * @param {{ version?: string }} [opts]
36
+ * @returns {import("./types.js").Check}
37
+ */
38
+ export function createNodeVersionCheck(opts = {}) {
39
+ return {
40
+ name: "node-version",
41
+ label: "Node.js runtime",
42
+ strategy: STRATEGY.MANUAL,
43
+ async detect() {
44
+ const raw = opts.version ?? process.env.KJ_FORCE_NODE_VERSION ?? process.version;
45
+ const parsed = parseNodeVersion(raw);
46
+ if (!parsed) {
47
+ return {
48
+ ok: false,
49
+ severity: "fail",
50
+ detail: `Unrecognized Node version: ${raw}`,
51
+ fix: `Install Node ${MIN_NODE_MAJOR}+ from https://nodejs.org/ (current: ${raw}).`,
52
+ };
53
+ }
54
+ if (parsed.major < MIN_NODE_MAJOR) {
55
+ return {
56
+ ok: false,
57
+ severity: "fail",
58
+ detail: `Node ${raw} detected, requires >=${MIN_NODE_MAJOR}`,
59
+ fix: `Upgrade Node to ${MIN_NODE_MAJOR}+ (nvm install ${MIN_NODE_MAJOR} && nvm use ${MIN_NODE_MAJOR}, or brew upgrade node).`,
60
+ extra: { detected: parsed, required: MIN_NODE_MAJOR },
61
+ };
62
+ }
63
+ return { ok: true, severity: "info", detail: `${raw} (>= ${MIN_NODE_MAJOR} required)` };
64
+ },
65
+ };
66
+ }
67
+
68
+ export function getNodeChecks() {
69
+ return [createNodeVersionCheck()];
70
+ }
@@ -0,0 +1,41 @@
1
+ // KJC-TSK-0437 — `kj doctor` check for the RAG embedder.
2
+ // Only fires when rag.preload.enabled === true; otherwise reports
3
+ // "Disabled in config" so doctor stays quiet on greenfield projects
4
+ // that never opted in to RAG.
5
+ import { isOllamaReachable } from "../rag/ollama-manager.js";
6
+ import { STRATEGY } from "./types.js";
7
+
8
+ function ragEnabled(config) {
9
+ return config?.rag?.preload?.enabled === true;
10
+ }
11
+ function ollamaHost(config) {
12
+ const port = config?.rag?.embedder?.port || 11434;
13
+ return config?.rag?.embedder?.host || `http://localhost:${port}`;
14
+ }
15
+
16
+ function createOllamaStatusCheck() {
17
+ return {
18
+ name: "ollama",
19
+ label: "Ollama (RAG embedder)",
20
+ strategy: STRATEGY.NONE,
21
+ async detect({ config }) {
22
+ if (!ragEnabled(config)) {
23
+ return { ok: true, severity: "info", detail: "Disabled in config (rag.preload.enabled=false)" };
24
+ }
25
+ const host = ollamaHost(config);
26
+ let reachable;
27
+ try { reachable = await isOllamaReachable(host); } catch { reachable = false; }
28
+ return {
29
+ ok: reachable,
30
+ severity: reachable ? "info" : "warn",
31
+ detail: reachable ? `Reachable at ${host}` : `Not reachable at ${host}`,
32
+ fix: reachable ? undefined : "Run `kj ollama start` to bootstrap the container, or `kj init --no-ollama` to opt out.",
33
+ extra: { host, reachable },
34
+ };
35
+ },
36
+ };
37
+ }
38
+
39
+ export function getOllamaChecks() {
40
+ return [createOllamaStatusCheck()];
41
+ }
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Orphaned scanner detection for `kj doctor` (KJC-TSK-0668). After the CPU
3
+ * storm, timed-out scans left semgrep-core processes reparented to init /
4
+ * systemd, silently burning cores. This check finds processes of tools kj
5
+ * governs whose parent is init (pid 1) or a systemd reaper, reports them,
6
+ * and — strategy "prompt" — offers to kill them.
7
+ */
8
+
9
+ import { execFile } from "node:child_process";
10
+ import { promisify } from "node:util";
11
+ import { STRATEGY } from "./types.js";
12
+
13
+ const execFileAsync = promisify(execFile);
14
+ const GOVERNED_TOOLS = new Set(["semgrep", "semgrep-core", "osv-scanner", "lighthouse"]);
15
+
16
+ /**
17
+ * Scan the process table for governed tools whose parent is init or a
18
+ * systemd reaper (where the kernel sends orphans). `runPs` injectable.
19
+ */
20
+ export async function findOrphanToolProcesses(runPs = execFileAsync) {
21
+ if (process.platform === "win32") return { supported: false, orphans: [] };
22
+ let stdout;
23
+ try {
24
+ ({ stdout } = await runPs("ps", ["-eo", "pid=,ppid=,comm="]));
25
+ } catch {
26
+ return { supported: false, orphans: [] };
27
+ }
28
+ const rows = [];
29
+ const commByPid = new Map();
30
+ for (const line of String(stdout).split("\n")) {
31
+ const m = line.trim().match(/^(\d+)\s+(\d+)\s+(.+)$/);
32
+ if (!m) continue;
33
+ const row = { pid: Number(m[1]), ppid: Number(m[2]), comm: m[3].trim() };
34
+ rows.push(row);
35
+ commByPid.set(row.pid, row.comm);
36
+ }
37
+ const orphans = rows.filter((r) =>
38
+ GOVERNED_TOOLS.has(r.comm) && (r.ppid === 1 || commByPid.get(r.ppid) === "systemd")
39
+ );
40
+ return { supported: true, orphans };
41
+ }
42
+
43
+ function createOrphanCheck() {
44
+ return {
45
+ name: "tool-orphans",
46
+ label: "Orphaned scanner processes",
47
+ strategy: STRATEGY.PROMPT,
48
+ describe: "Kill orphaned scanner processes left behind by interrupted runs",
49
+ async detect({ runPs } = {}) {
50
+ const { supported, orphans } = await findOrphanToolProcesses(runPs || execFileAsync);
51
+ if (!supported) return { ok: true, severity: "info", detail: "orphan detection not supported on this platform" };
52
+ if (orphans.length === 0) return { ok: true, severity: "info", detail: "no orphaned scanner processes" };
53
+ const list = orphans.map((o) => `${o.comm}(${o.pid})`).join(", ");
54
+ return {
55
+ ok: false,
56
+ severity: "warn",
57
+ detail: `${orphans.length} orphaned scanner process(es) burning CPU: ${list}`,
58
+ fix: `kill -9 ${orphans.map((o) => o.pid).join(" ")}`,
59
+ extra: { orphans },
60
+ };
61
+ },
62
+ async remediate({ extra, kill = process.kill } = {}) {
63
+ let killed = 0;
64
+ for (const o of extra?.orphans || []) {
65
+ try {
66
+ kill(o.pid, "SIGKILL");
67
+ killed += 1;
68
+ } catch { /* already gone */ }
69
+ }
70
+ return { fixed: killed > 0, detail: `killed ${killed} orphaned scanner process(es)` };
71
+ },
72
+ };
73
+ }
74
+
75
+ export function getOrphanChecks() {
76
+ return [createOrphanCheck()];
77
+ }
@@ -0,0 +1,188 @@
1
+ /**
2
+ * Port availability checks for services Karajan controls.
3
+ *
4
+ * - SonarQube port (default 9000): the Docker container binds a fixed port,
5
+ * so if it's occupied by a non-Karajan process we cannot "move" it; we
6
+ * report FAIL with the occupant PID/command to help the user stop the
7
+ * conflicting process. Strategy: manual.
8
+ *
9
+ * - HU Board port (default 4000): an in-process Node server we can rebind
10
+ * to any free port in runtime overrides. Strategy: auto.
11
+ */
12
+
13
+ import { isPortAvailable, findAvailablePort } from "../utils/port-check.js";
14
+ import { getPortOccupant } from "../utils/port-occupant.js";
15
+ import { discoverRunningSonar } from "../sonar/discovery.js";
16
+ import { isSonarReachable } from "../sonar/manager.js";
17
+ import { STRATEGY } from "./types.js";
18
+
19
+ const DEFAULT_SONAR_PORT = 9000;
20
+ const DEFAULT_HU_BOARD_PORT = 4000;
21
+
22
+ function extractPortFromHost(host, fallback) {
23
+ const m = String(host || "").match(/:(\d+)(?:\/|$)/);
24
+ return m ? Number(m[1]) : fallback;
25
+ }
26
+
27
+ /**
28
+ * @internal Exported for dynamic import from tests/checks/ports.test.js
29
+ * and tests/checks/auto-remediation-e2e.test.js. Knip false positive.
30
+ */
31
+ export function createSonarPortCheck() {
32
+ return {
33
+ name: "port:sonar",
34
+ label: "SonarQube port",
35
+ // AUTO since v2.7.5 — Karajan now resolves SonarQube discovery on
36
+ // its own. If a Sonar container is running anywhere (any name, any
37
+ // image tag), point Karajan at it. If port 9000 is occupied by
38
+ // someone non-Sonar, rebind to the next free port. Asking the user
39
+ // to "stop the unknown process" was busywork.
40
+ strategy: STRATEGY.AUTO,
41
+ applies: (config) => {
42
+ if (config?.sonarqube?.external === true) {
43
+ return { applies: false, reason: "sonarqube.external is true — port managed outside Karajan" };
44
+ }
45
+ return true;
46
+ },
47
+ describe: "Discover or rebind SonarQube port (no user action needed)",
48
+ async detect({ config }) {
49
+ const configuredPort = extractPortFromHost(config?.sonarqube?.host, DEFAULT_SONAR_PORT);
50
+
51
+ // Step 1 — is there ANY running SonarQube container we can reuse?
52
+ // Container name doesn't matter; we just need a published host port
53
+ // that responds to /api/system/status. This avoids "port 9000 is
54
+ // taken by an unknown process" errors when the unknown process is
55
+ // actually a perfectly good SonarQube from another project.
56
+ const discovered = await discoverRunningSonar();
57
+ if (discovered.found && discovered.reachable) {
58
+ // If the discovered host matches what's already configured,
59
+ // there's nothing to fix — happy path.
60
+ if (discovered.port === configuredPort) {
61
+ return {
62
+ ok: true,
63
+ severity: "info",
64
+ detail: `Reusing running SonarQube container "${discovered.containerName}" on port ${discovered.port}`,
65
+ };
66
+ }
67
+ // Otherwise we want to rewrite the host config at runtime.
68
+ return {
69
+ ok: false,
70
+ severity: "warn",
71
+ detail: `Found running SonarQube container "${discovered.containerName}" on port ${discovered.port} (config points at ${configuredPort})`,
72
+ extra: { remap: { host: discovered.host, port: discovered.port, container: discovered.containerName } },
73
+ };
74
+ }
75
+
76
+ // Step 2 — no running container. Is the configured port even free?
77
+ const free = await isPortAvailable(configuredPort);
78
+ if (free) {
79
+ return {
80
+ ok: true,
81
+ severity: "info",
82
+ detail: `Port ${configuredPort} is free (Sonar container will be started on demand)`,
83
+ };
84
+ }
85
+
86
+ // Step 3 — port is busy. Maybe the occupant IS Sonar but not
87
+ // discovered by `docker ps` (rare: bare-metal Sonar, host-network
88
+ // container, etc.). HTTP-probe to find out.
89
+ const probeHost = `http://localhost:${configuredPort}`;
90
+ if (await isSonarReachable(probeHost)) {
91
+ return {
92
+ ok: true,
93
+ severity: "info",
94
+ detail: `Port ${configuredPort} held by a Sonar instance (HTTP /api/system/status responds) — reusing it`,
95
+ };
96
+ }
97
+
98
+ // Step 4 — really not Sonar. Find an alternate free port and tell
99
+ // the runtime to use it. The compose template's published port is
100
+ // hardcoded at 9000 so we can't auto-rebind the container itself,
101
+ // but we CAN warn loudly with a clear, fixable message.
102
+ const occupant = await getPortOccupant(configuredPort);
103
+ const alt = await findAvailablePort(configuredPort + 1, 20);
104
+ if (alt) {
105
+ return {
106
+ ok: false,
107
+ severity: "warn",
108
+ detail: `Port ${configuredPort} occupied by ${occupant?.command || "unknown"} (PID ${occupant?.pid ?? "?"}). Will rebind Karajan-managed Sonar to ${alt}.`,
109
+ extra: { remap: { host: `http://localhost:${alt}`, port: alt, fromPort: configuredPort } },
110
+ };
111
+ }
112
+ // Last-resort failure (no free port in the next 20).
113
+ return {
114
+ ok: false,
115
+ severity: "fail",
116
+ detail: `Port ${configuredPort} occupied by ${occupant?.command || "unknown"} (PID ${occupant?.pid ?? "?"}) and no free port in ${configuredPort + 1}..${configuredPort + 20}`,
117
+ fix: "Stop the conflicting process or set sonarqube.host in kj.config.yml.",
118
+ };
119
+ },
120
+ async remediate({ extra }) {
121
+ if (!extra?.remap) {
122
+ return { fixed: false, detail: "No remap available" };
123
+ }
124
+ const { host, container, fromPort } = extra.remap;
125
+ const detail = container
126
+ ? `Pointed Karajan at running SonarQube ${container} (${host})`
127
+ : `Rebound Karajan-managed Sonar from port ${fromPort} to ${host}`;
128
+ return {
129
+ fixed: true,
130
+ detail,
131
+ // The runner merges this into the runtime config so every
132
+ // downstream Sonar caller (scanner, manager, MCP handler) sees
133
+ // the new host without the user touching kj.config.yml.
134
+ changes: { sonarqube: { host } },
135
+ };
136
+ },
137
+ };
138
+ }
139
+
140
+ /**
141
+ * @internal Exported for dynamic import from tests/checks/ports.test.js
142
+ * and tests/checks/auto-remediation-e2e.test.js. Knip false positive.
143
+ */
144
+ export function createHuBoardPortCheck() {
145
+ return {
146
+ name: "port:hu-board",
147
+ label: "HU Board port",
148
+ strategy: STRATEGY.AUTO,
149
+ applies: (config) => {
150
+ if (config?.hu_board?.enabled === false) {
151
+ return { applies: false, reason: "hu_board.enabled is false in kj.config.yml — HU Board dashboard skipped" };
152
+ }
153
+ return true;
154
+ },
155
+ describe: "Rebind HU Board to the next free port",
156
+ async detect({ config }) {
157
+ const port = config?.hu_board?.port || DEFAULT_HU_BOARD_PORT;
158
+ const free = await isPortAvailable(port);
159
+ if (free) {
160
+ return { ok: true, severity: "info", detail: `Port ${port} is free` };
161
+ }
162
+ const occupant = await getPortOccupant(port);
163
+ const who = occupant
164
+ ? `${occupant.command || "unknown"} (PID ${occupant.pid ?? "?"})`
165
+ : "unknown process";
166
+ return {
167
+ ok: false,
168
+ severity: "warn",
169
+ detail: `Port ${port} occupied by ${who}`,
170
+ fix: `Free port ${port} or set hu_board.port in kj.config.yml`,
171
+ extra: { port, occupant },
172
+ };
173
+ },
174
+ async remediate({ extra }) {
175
+ const start = (extra?.port ?? DEFAULT_HU_BOARD_PORT) + 1;
176
+ const found = await findAvailablePort(start, 20);
177
+ return {
178
+ fixed: true,
179
+ detail: `Rebound HU Board to port ${found} (in-memory override)`,
180
+ changes: { hu_board: { port: found } },
181
+ };
182
+ },
183
+ };
184
+ }
185
+
186
+ export function getPortChecks() {
187
+ return [createSonarPortCheck(), createHuBoardPortCheck()];
188
+ }
@@ -0,0 +1,245 @@
1
+ /**
2
+ * Project-aware preflight checks (KJC-TSK-0393).
3
+ *
4
+ * `kj doctor` (global) y el preflight estándar verifican el ENTORNO de Karajan
5
+ * (CLIs instaladas, node, dirs ~/.karajan/, sonar). Pero **nada** validaba que
6
+ * el PROYECTO actual tuviera lo que necesita: tools detectables por signals
7
+ * (docker si hay Dockerfile, firebase si hay firebase.json, etc.), permisos
8
+ * write sobre projectDir, configuración inicializada, .env consistente con
9
+ * .env.example.
10
+ *
11
+ * Este módulo registra checks dinámicos basados en signals del proyecto. Se
12
+ * integra en preflight-checks.js como "fase project-aware" tras la fase global.
13
+ * También expone `kj doctor --project` para ejecutar solo esta fase manualmente.
14
+ *
15
+ * Filosofía: si un check falla, el mensaje incluye el comando EJECUTABLE para
16
+ * resolverlo (no "Run X or Y"), y siempre que sea posible se marca como
17
+ * `degradable` (KJC-BUG-0049) para no abortar runs por features opcionales.
18
+ */
19
+
20
+ import fs from "node:fs";
21
+ import path from "node:path";
22
+ import { runCommand } from "../utils/process.js";
23
+ import { checkBinary } from "../utils/agent-detect.js";
24
+ import { getInstallCommand } from "../utils/os-detect.js";
25
+ import { STRATEGY } from "./types.js";
26
+
27
+ /**
28
+ * Detect signals del proyecto. Devuelve un set de tags con qué hay en el
29
+ * projectDir. Pure-function, solo I/O de filesystem síncrono (rápido).
30
+ *
31
+ * @param {string} projectDir
32
+ * @returns {Set<string>}
33
+ */
34
+ export function detectProjectSignals(projectDir) {
35
+ const signals = new Set();
36
+ if (!projectDir || !fs.existsSync(projectDir)) return signals;
37
+ const has = (rel) => fs.existsSync(path.join(projectDir, rel));
38
+ if (has("package.json")) signals.add("node");
39
+ if (has("Dockerfile") || has("docker-compose.yml") || has("compose.yml")) signals.add("docker");
40
+ if (has("firebase.json") || has(".firebaserc")) signals.add("firebase");
41
+ if (has("pyproject.toml") || has("requirements.txt") || has("setup.py")) signals.add("python");
42
+ if (has("Cargo.toml")) signals.add("rust");
43
+ if (has("go.mod")) signals.add("go");
44
+ if (has(".env.example") || has(".env.sample") || has(".env.template")) signals.add("env-example");
45
+ if (has(".env")) signals.add("env");
46
+ // Terraform / OpenTofu
47
+ try {
48
+ const entries = fs.readdirSync(projectDir);
49
+ if (entries.some((e) => e.endsWith(".tf") || e.endsWith(".tofu"))) signals.add("terraform");
50
+ } catch { /* unreadable dir */ }
51
+ return signals;
52
+ }
53
+
54
+ /**
55
+ * Check de tool específico del signal. Si el signal está presente pero la tool
56
+ * no, emite WARN con install command ejecutable.
57
+ */
58
+ function createToolCheck({ signal, tool, label, signals }) {
59
+ return {
60
+ name: `project:tool:${tool}`,
61
+ label,
62
+ strategy: STRATEGY.MANUAL,
63
+ applies: () => signals.has(signal),
64
+ async detect() {
65
+ const res = await checkBinary(tool);
66
+ if (res.ok) {
67
+ return { ok: true, severity: "info", detail: `${tool} ${res.version} — required by ${signal} signal` };
68
+ }
69
+ const installCmd = getInstallCommand(tool) || `<install ${tool} for your OS>`;
70
+ return {
71
+ ok: false,
72
+ severity: "warn",
73
+ detail: `${tool} no instalada pero el proyecto tiene signal '${signal}' (puede no necesitarla para esta HU, pero la mayoría sí)`,
74
+ fix: installCmd,
75
+ };
76
+ },
77
+ };
78
+ }
79
+
80
+ /**
81
+ * Permisos write check. Critical: si projectDir, .kj/ o .karajan/ no son
82
+ * escribibles, el pipeline va a fallar muy tarde con errores oscuros.
83
+ */
84
+ function createWritePermsCheck({ projectDir }) {
85
+ return {
86
+ name: "project:write-perms",
87
+ label: "Write permissions (projectDir + .kj/ + .karajan/)",
88
+ strategy: STRATEGY.MANUAL,
89
+ async detect() {
90
+ const targets = [
91
+ projectDir,
92
+ path.join(projectDir, ".kj"),
93
+ path.join(projectDir, ".karajan"),
94
+ ];
95
+ const failed = [];
96
+ for (const target of targets) {
97
+ try {
98
+ if (!fs.existsSync(target)) continue;
99
+ fs.accessSync(target, fs.constants.W_OK);
100
+ } catch {
101
+ failed.push(target);
102
+ }
103
+ }
104
+ if (failed.length === 0) {
105
+ return { ok: true, severity: "info", detail: "Karajan puede escribir en projectDir, .kj/ y .karajan/" };
106
+ }
107
+ return {
108
+ ok: false,
109
+ severity: "fail",
110
+ detail: `Sin permisos de escritura en: ${failed.join(", ")}`,
111
+ fix: `chmod -R u+w ${failed.join(" ")}`,
112
+ };
113
+ },
114
+ };
115
+ }
116
+
117
+ /**
118
+ * .env consistency check: si existe .env.example pero NO .env, o si las vars
119
+ * que .env.example declara faltan en .env, emite WARN con la lista.
120
+ */
121
+ function createEnvConsistencyCheck({ projectDir, signals }) {
122
+ return {
123
+ name: "project:env-consistency",
124
+ label: ".env consistency (vs .env.example)",
125
+ strategy: STRATEGY.MANUAL,
126
+ applies: () => signals.has("env-example"),
127
+ async detect() {
128
+ const exampleFile = ["env.example", ".env.sample", ".env.template"]
129
+ .map((n) => path.join(projectDir, n.startsWith(".") ? n : `.${n}`))
130
+ .find((p) => fs.existsSync(p));
131
+ const realFile = path.join(projectDir, ".env");
132
+ const declaredVars = parseEnvKeys(exampleFile);
133
+ if (declaredVars.length === 0) {
134
+ return { ok: true, severity: "info", detail: ".env.example sin variables declaradas" };
135
+ }
136
+ const realVars = fs.existsSync(realFile) ? new Set(parseEnvKeys(realFile)) : new Set();
137
+ const missing = declaredVars.filter((k) => !realVars.has(k));
138
+ if (missing.length === 0) {
139
+ return { ok: true, severity: "info", detail: `.env tiene las ${declaredVars.length} variables declaradas en .env.example` };
140
+ }
141
+ return {
142
+ ok: false,
143
+ severity: "warn",
144
+ detail: `.env no declara ${missing.length} variable(s) que sí están en .env.example: ${missing.slice(0, 5).join(", ")}${missing.length > 5 ? "..." : ""}`,
145
+ fix: `cp ${path.basename(exampleFile)} .env && edit it`,
146
+ };
147
+ },
148
+ };
149
+ }
150
+
151
+ function parseEnvKeys(filePath) {
152
+ try {
153
+ const content = fs.readFileSync(filePath, "utf8");
154
+ return content
155
+ .split("\n")
156
+ .map((l) => l.trim())
157
+ .filter((l) => l && !l.startsWith("#") && l.includes("="))
158
+ .map((l) => l.split("=")[0].trim())
159
+ .filter(Boolean);
160
+ } catch { return []; }
161
+ }
162
+
163
+ /**
164
+ * gh remote-specific check: cuando auto_pr está activo, no basta con que `gh`
165
+ * esté autenticado en general (eso lo cubre token:gh ya). Hay que verificar
166
+ * que el usuario tiene push access AL REMOTE de este proyecto.
167
+ */
168
+ function createGhRemoteCheck({ projectDir }) {
169
+ return {
170
+ name: "project:gh-remote-access",
171
+ label: "GitHub push access (current remote)",
172
+ strategy: STRATEGY.MANUAL,
173
+ applies: (config) => config?.git?.auto_pr === true,
174
+ degradable: {
175
+ disables: ["git.auto_pr"],
176
+ warn: "auto_pr DESACTIVADO — no se pueden crear PRs al remote actual. Verifica permisos con `gh repo view`",
177
+ },
178
+ async detect() {
179
+ // Verifica que el remote responde a ls-remote (read access mínimo,
180
+ // proxy para push access — el push real solo se valida al pushear).
181
+ try {
182
+ const res = await runCommand("git", ["-C", projectDir, "ls-remote", "--heads", "origin"], { reject: false });
183
+ if (res.exitCode === 0) {
184
+ return { ok: true, severity: "info", detail: "Remote origin accesible vía git ls-remote" };
185
+ }
186
+ return {
187
+ ok: false,
188
+ severity: "warn",
189
+ detail: `git ls-remote origin falló (exit ${res.exitCode}): ${(res.stderr || "").slice(0, 120)}`,
190
+ fix: "Verifica el remote con `git remote -v` y la auth con `gh repo view`",
191
+ };
192
+ } catch (err) {
193
+ return { ok: false, severity: "warn", detail: `git ls-remote error: ${err.message}`, fix: "Verifica git remote y auth gh" };
194
+ }
195
+ },
196
+ };
197
+ }
198
+
199
+ /**
200
+ * `kj init` ran check: si no existe ~/.karajan/kj.config.yml NI .karajan/coder-rules.md,
201
+ * el usuario probablemente no ejecutó `kj init`. WARN con instrucción ejecutable.
202
+ */
203
+ function createKjInitCheck({ projectDir }) {
204
+ return {
205
+ name: "project:kj-init-ran",
206
+ label: "Karajan project initialized",
207
+ strategy: STRATEGY.MANUAL,
208
+ async detect() {
209
+ const projectKjFile = path.join(projectDir, ".karajan", "coder-rules.md");
210
+ const globalKjFile = path.join(process.env.HOME || "", ".karajan", "kj.config.yml");
211
+ if (fs.existsSync(projectKjFile) || fs.existsSync(globalKjFile)) {
212
+ return { ok: true, severity: "info", detail: "Karajan config presente (global o local del proyecto)" };
213
+ }
214
+ return {
215
+ ok: false,
216
+ severity: "warn",
217
+ detail: "No se encontró kj.config.yml global ni .karajan/coder-rules.md local — probablemente falta `kj init`",
218
+ fix: "kj init",
219
+ };
220
+ },
221
+ };
222
+ }
223
+
224
+ /**
225
+ * Construye el set completo de project-aware checks basado en projectDir.
226
+ *
227
+ * @param {{ projectDir: string }} ctx
228
+ * @returns {Check[]}
229
+ */
230
+ export function getProjectChecks({ projectDir }) {
231
+ if (!projectDir) return [];
232
+ const signals = detectProjectSignals(projectDir);
233
+ return [
234
+ createKjInitCheck({ projectDir }),
235
+ createWritePermsCheck({ projectDir }),
236
+ createToolCheck({ signal: "docker", tool: "docker", label: "Docker (project signal)", signals }),
237
+ createToolCheck({ signal: "firebase", tool: "firebase", label: "firebase-cli (project signal)", signals }),
238
+ createToolCheck({ signal: "python", tool: "python3", label: "Python 3 (project signal)", signals }),
239
+ createToolCheck({ signal: "rust", tool: "cargo", label: "Cargo / Rust (project signal)", signals }),
240
+ createToolCheck({ signal: "go", tool: "go", label: "Go (project signal)", signals }),
241
+ createToolCheck({ signal: "terraform", tool: "terraform", label: "Terraform (project signal)", signals }),
242
+ createEnvConsistencyCheck({ projectDir, signals }),
243
+ createGhRemoteCheck({ projectDir }),
244
+ ];
245
+ }
@@ -0,0 +1,41 @@
1
+ /**
2
+ * QMD availability check. Manual strategy — installation
3
+ * depends on the host platform and is handled by getInstallCommand().
4
+ *
5
+ * QMD (Quick Markdown Search) provides semantic search over the
6
+ * user's wiki / docs / notes collections. Karajan ships it as a
7
+ * default integration (mirror of Squeezr): kj init installs it,
8
+ * kj doctor reports its presence.
9
+ */
10
+
11
+ import { runCommand } from "../utils/process.js";
12
+ import { getInstallCommand } from "../utils/os-detect.js";
13
+ import { withDocLink } from "../utils/doc-links.js";
14
+ import { STRATEGY } from "./types.js";
15
+
16
+ function createQmdCheck() {
17
+ return {
18
+ name: "qmd",
19
+ label: "QMD",
20
+ strategy: STRATEGY.MANUAL,
21
+ async detect() {
22
+ try {
23
+ const res = await runCommand("qmd", ["--version"]);
24
+ if (res.exitCode === 0) {
25
+ return { ok: true, severity: "info", detail: `${res.stdout.trim()} — semantic wiki active` };
26
+ }
27
+ } catch { /* not installed */ }
28
+ const installCmd = getInstallCommand("qmd");
29
+ return {
30
+ ok: false,
31
+ severity: "warn",
32
+ detail: "Not found — semantic wiki via QMD available",
33
+ fix: withDocLink(`Install: ${installCmd}`, "qmd_install"),
34
+ };
35
+ },
36
+ };
37
+ }
38
+
39
+ export function getQmdChecks() {
40
+ return [createQmdCheck()];
41
+ }