@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,60 @@
1
+ /**
2
+ * Load SonarQube credentials from ~/.karajan/sonar-credentials.json.
3
+ *
4
+ * File format (any subset):
5
+ * {
6
+ * "user": "admin",
7
+ * "password": "your-password",
8
+ * "token": "squ_..."
9
+ * }
10
+ *
11
+ * Returns { user, password, token } with each field null when missing.
12
+ *
13
+ * The `token` field is consumed by resolveSonarTokenAsync as the
14
+ * lowest-priority fallback. Until v2.7.5 it was not extracted here, which
15
+ * meant a token persisted to the credentials file by `kj init` was never
16
+ * actually used at scan time — Karajan would silently fall back to the
17
+ * stale token in kj.config.yml or fail with a 401.
18
+ */
19
+
20
+ import fs from "node:fs/promises";
21
+ import path from "node:path";
22
+ import { getKarajanHome } from "../utils/paths.js";
23
+
24
+ const CREDENTIALS_FILENAME = "sonar-credentials.json";
25
+
26
+ export async function loadSonarCredentials() {
27
+ try {
28
+ const filePath = path.join(getKarajanHome(), CREDENTIALS_FILENAME);
29
+ const raw = await fs.readFile(filePath, "utf8");
30
+ const data = JSON.parse(raw);
31
+ return {
32
+ user: data.user || null,
33
+ password: data.password || null,
34
+ token: data.token || null
35
+ };
36
+ } catch { /* credentials file may not exist */
37
+ return { user: null, password: null, token: null };
38
+ }
39
+ }
40
+
41
+ export function credentialsPath() {
42
+ return path.join(getKarajanHome(), CREDENTIALS_FILENAME);
43
+ }
44
+
45
+ /**
46
+ * Save a generated token to ~/.karajan/sonar-credentials.json so it persists across sessions.
47
+ * Merges with existing credentials (preserves user/password if present).
48
+ */
49
+ export async function saveSonarToken(token) {
50
+ const filePath = path.join(getKarajanHome(), CREDENTIALS_FILENAME);
51
+ let existing = {};
52
+ try {
53
+ const raw = await fs.readFile(filePath, "utf8");
54
+ existing = JSON.parse(raw);
55
+ } catch { /* file may not exist */ }
56
+ existing.token = token;
57
+ const dir = getKarajanHome();
58
+ await fs.mkdir(dir, { recursive: true });
59
+ await fs.writeFile(filePath, JSON.stringify(existing, null, 2), { encoding: "utf8", mode: 0o600 });
60
+ }
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Discover running SonarQube containers regardless of the user's
3
+ * config. The point: never bother the user about port 9000 being
4
+ * "occupied by an unknown process" — if there's a Sonar already up
5
+ * somewhere, just point at it and move on.
6
+ *
7
+ * The previous preflight check insisted on owning port 9000 by name
8
+ * (`karajan-sonarqube`). If you happened to have a `sonarqube` from
9
+ * another project running on 9000 (or had pulled a different image
10
+ * tag), we'd error out asking the user to "stop the conflicting
11
+ * process". That's busywork — Sonar is Sonar; reuse what's there.
12
+ *
13
+ * The discovery strategy:
14
+ * 1. List Docker containers whose image looks like sonarqube
15
+ * (image-name regex / ancestor filter — covers `sonarqube`,
16
+ * `sonarqube:community`, `sonarqube:lts`, `sonarqube:9.9`, …).
17
+ * 2. Parse the published host port (`0.0.0.0:9001->9000/tcp`).
18
+ * 3. Optionally HTTP-probe to confirm it's actually serving
19
+ * `/api/system/status` so a misnamed image can't hijack us.
20
+ */
21
+
22
+ import { runCommand } from "../utils/process.js";
23
+ import { isSonarReachable } from "./manager.js";
24
+ import { escapeRegExp } from "../utils/escape-regexp.js";
25
+
26
+ /**
27
+ * @typedef {Object} DiscoveredSonar
28
+ * @property {boolean} found
29
+ * @property {string} [containerName]
30
+ * @property {string} [image]
31
+ * @property {number} [port] - host port (what we connect to)
32
+ * @property {string} [host] - http://localhost:<port>
33
+ * @property {boolean} [reachable] - true after a successful HTTP probe
34
+ */
35
+
36
+ /**
37
+ * Parse the Ports column from `docker ps`. Looks for any host binding
38
+ * that maps to the container's `internalPort` (default 9000).
39
+ * Examples:
40
+ * "0.0.0.0:9000->9000/tcp" → 9000
41
+ * "127.0.0.1:9001->9000/tcp" → 9001
42
+ * "9000/tcp" → null (no host binding)
43
+ * "0.0.0.0:9000->9000/tcp, 9092/tcp" → 9000
44
+ *
45
+ * @param {string} portsStr
46
+ * @param {number} [internalPort=9000]
47
+ * @returns {number|null}
48
+ */
49
+ export function extractHostPort(portsStr, internalPort = 9000) {
50
+ if (!portsStr) return null;
51
+ const re = new RegExp(
52
+ `(?:0\\.0\\.0\\.0|127\\.0\\.0\\.1|::|\\[::\\]):(\\d+)\\s*->\\s*${escapeRegExp(internalPort)}\\/tcp`,
53
+ "g"
54
+ );
55
+ const matches = [...portsStr.matchAll(re)];
56
+ if (matches.length === 0) return null;
57
+ // Prefer the smallest port number (likeliest the "main" binding);
58
+ // arbitrary but deterministic.
59
+ return Math.min(...matches.map((m) => Number(m[1])));
60
+ }
61
+
62
+ /**
63
+ * Run `docker ps` with a list-of-images filter and parse the result.
64
+ * Returns the FIRST container with a usable host port, or null.
65
+ *
66
+ * @returns {Promise<DiscoveredSonar|null>}
67
+ */
68
+ async function dockerPsForSonar() {
69
+ // List all running containers with their image so we can image-match
70
+ // ourselves. Cheap (single docker call) and tolerant of image tags.
71
+ const res = await runCommand("docker", [
72
+ "ps",
73
+ "--format", "{{.ID}}|{{.Names}}|{{.Image}}|{{.Ports}}",
74
+ ]);
75
+ if (res.exitCode !== 0 || !res.stdout?.trim()) return null;
76
+
77
+ const lines = res.stdout.trim().split("\n");
78
+ for (const line of lines) {
79
+ const [, name, image, ports] = line.split("|");
80
+ if (!image) continue;
81
+ if (!/sonarqube/i.test(image)) continue;
82
+ const port = extractHostPort(ports, 9000);
83
+ if (!port) continue;
84
+ return {
85
+ found: true,
86
+ containerName: name,
87
+ image,
88
+ port,
89
+ host: `http://localhost:${port}`,
90
+ };
91
+ }
92
+ return null;
93
+ }
94
+
95
+ /**
96
+ * Public entry point: find a usable, reachable Sonar.
97
+ *
98
+ * `probe`: when true (default) HTTP-pings `/api/system/status` to
99
+ * confirm the container is actually serving Sonar. Tests can disable
100
+ * the probe for hermetic mocking.
101
+ *
102
+ * @param {object} [opts]
103
+ * @param {boolean} [opts.probe=true]
104
+ * @param {number} [opts.healthcheckSeconds=5]
105
+ * @returns {Promise<DiscoveredSonar>}
106
+ */
107
+ export async function discoverRunningSonar(opts = {}) {
108
+ const { probe = true, healthcheckSeconds = 5 } = opts;
109
+ let candidate;
110
+ try {
111
+ candidate = await dockerPsForSonar();
112
+ } catch {
113
+ candidate = null;
114
+ }
115
+ if (!candidate) return { found: false };
116
+ if (!probe) return { ...candidate, reachable: true };
117
+ let reachable;
118
+ try {
119
+ reachable = await isSonarReachable(candidate.host, healthcheckSeconds);
120
+ } catch {
121
+ reachable = false;
122
+ }
123
+ return { ...candidate, reachable };
124
+ }
@@ -0,0 +1,19 @@
1
+ export function shouldBlockByProfile({ gateStatus, profile = "pragmatic" }) {
2
+ if (profile === "paranoid") {
3
+ return gateStatus !== "OK";
4
+ }
5
+
6
+ return gateStatus === "ERROR";
7
+ }
8
+
9
+ export function summarizeIssues(issues) {
10
+ const bySeverity = issues.reduce((acc, issue) => {
11
+ const severity = issue.severity || "UNKNOWN";
12
+ acc[severity] = (acc[severity] || 0) + 1;
13
+ return acc;
14
+ }, {});
15
+
16
+ return Object.entries(bySeverity)
17
+ .map(([severity, count]) => `${severity}: ${count}`)
18
+ .join(", ");
19
+ }
@@ -0,0 +1,12 @@
1
+ // @deprecated — moved to src/audit/issue-filter.js (v2.17.0). This shim
2
+ // re-exports the generalised filter so existing imports keep working. All
3
+ // Sonar-specific behaviour (default `tool="sonar"`, legacy
4
+ // `// karajan-sonar-ignore: <rule>` markers) is preserved by the new module.
5
+ //
6
+ // New code should import from "../audit/issue-filter.js" directly.
7
+
8
+ export {
9
+ filterFalsePositives,
10
+ hasInlineIgnore,
11
+ DEFAULT_FALSE_POSITIVES,
12
+ } from "../audit/issue-filter.js";
@@ -0,0 +1,181 @@
1
+ import fs from "node:fs/promises";
2
+ import { ensureDir } from "../utils/fs.js";
3
+ import { runCommand } from "../utils/process.js";
4
+ import { getKarajanHome, getSonarComposePath } from "../utils/paths.js";
5
+ import { loadConfig } from "../config.js";
6
+
7
+ const KARAJAN_HOME = getKarajanHome();
8
+ const COMPOSE_PATH = getSonarComposePath();
9
+
10
+ function normalizeSonarConfig(sonarqube = {}) {
11
+ const timeouts = sonarqube.timeouts || {};
12
+ return {
13
+ host: sonarqube.host || "http://localhost:9000",
14
+ external: sonarqube.external === true,
15
+ containerName: sonarqube.container_name || "karajan-sonarqube",
16
+ network: sonarqube.network || "karajan_sonar_net",
17
+ volumes: {
18
+ data: sonarqube?.volumes?.data || "karajan_sonar_data",
19
+ logs: sonarqube?.volumes?.logs || "karajan_sonar_logs",
20
+ extensions: sonarqube?.volumes?.extensions || "karajan_sonar_extensions"
21
+ },
22
+ timeouts: {
23
+ healthcheckSeconds: Number(timeouts.healthcheck_seconds) > 0 ? Number(timeouts.healthcheck_seconds) : 5,
24
+ composeUpMs: Number(timeouts.compose_up_ms) > 0 ? Number(timeouts.compose_up_ms) : 5 * 60 * 1000,
25
+ composeControlMs: Number(timeouts.compose_control_ms) > 0 ? Number(timeouts.compose_control_ms) : 2 * 60 * 1000,
26
+ logsMs: Number(timeouts.logs_ms) > 0 ? Number(timeouts.logs_ms) : 30 * 1000
27
+ }
28
+ };
29
+ }
30
+
31
+ function buildComposeTemplate(sonarConfig) {
32
+ return `services:
33
+ sonarqube:
34
+ image: sonarqube:community
35
+ container_name: ${sonarConfig.containerName}
36
+ ports:
37
+ - "9000:9000"
38
+ volumes:
39
+ - ${sonarConfig.volumes.data}:/opt/sonarqube/data
40
+ - ${sonarConfig.volumes.logs}:/opt/sonarqube/logs
41
+ - ${sonarConfig.volumes.extensions}:/opt/sonarqube/extensions
42
+ environment:
43
+ - SONAR_ES_BOOTSTRAP_CHECKS_DISABLE=true
44
+ networks:
45
+ - ${sonarConfig.network}
46
+ restart: unless-stopped
47
+
48
+ volumes:
49
+ ${sonarConfig.volumes.data}:
50
+ ${sonarConfig.volumes.logs}:
51
+ ${sonarConfig.volumes.extensions}:
52
+
53
+ networks:
54
+ ${sonarConfig.network}:
55
+ name: ${sonarConfig.network}
56
+ `;
57
+ }
58
+
59
+ export async function ensureComposeFile(sonarqube = null) {
60
+ const sonarConfig = sonarqube ? normalizeSonarConfig(sonarqube) : normalizeSonarConfig((await loadConfig()).config.sonarqube);
61
+ const composeTemplate = buildComposeTemplate(sonarConfig);
62
+ await ensureDir(KARAJAN_HOME);
63
+ await fs.writeFile(COMPOSE_PATH, composeTemplate, "utf8");
64
+ return COMPOSE_PATH;
65
+ }
66
+
67
+ export async function isSonarReachable(host, healthcheckSeconds = 5) {
68
+ const timeout = Number(healthcheckSeconds) > 0 ? String(Number(healthcheckSeconds)) : "5";
69
+ const res = await runCommand("curl", ["-s", "-o", "/dev/null", "-w", "%{http_code}", "--max-time", timeout, `${host}/api/system/status`]);
70
+ return res.exitCode === 0 && res.stdout.trim().startsWith("2");
71
+ }
72
+
73
+ export async function sonarUp(hostOverride = null) {
74
+ const { config } = await loadConfig();
75
+ const sonarConfig = normalizeSonarConfig(config.sonarqube);
76
+ const host = hostOverride || sonarConfig.host;
77
+
78
+ if (await isSonarReachable(host, sonarConfig.timeouts.healthcheckSeconds)) {
79
+ return { exitCode: 0, stdout: `SonarQube already reachable at ${host}, skipping container start.`, stderr: "" };
80
+ }
81
+
82
+ if (sonarConfig.external) {
83
+ return {
84
+ exitCode: 1,
85
+ stdout: "",
86
+ stderr: `Configured external SonarQube is not reachable at ${host}.`
87
+ };
88
+ }
89
+
90
+ // Discover-before-spawn (v2.7.5): if there's already a SonarQube
91
+ // container running anywhere — even under a different name on a
92
+ // different port — reuse it instead of spinning up a second one.
93
+ // Avoids the user accidentally accumulating Sonar containers across
94
+ // projects, and matches what the port preflight check already does.
95
+ const { discoverRunningSonar } = await import("./discovery.js");
96
+ const discovered = await discoverRunningSonar({
97
+ healthcheckSeconds: sonarConfig.timeouts.healthcheckSeconds,
98
+ });
99
+ if (discovered.found && discovered.reachable) {
100
+ return {
101
+ exitCode: 0,
102
+ stdout: `Reusing existing SonarQube container "${discovered.containerName}" at ${discovered.host} (skipping container start).`,
103
+ stderr: "",
104
+ reusedHost: discovered.host,
105
+ };
106
+ }
107
+
108
+ const compose = await ensureComposeFile(config.sonarqube);
109
+ return runCommand("docker", ["compose", "-f", compose, "up", "-d"], { timeout: sonarConfig.timeouts.composeUpMs });
110
+ }
111
+
112
+ export async function sonarDown() {
113
+ const { config } = await loadConfig();
114
+ const sonarConfig = normalizeSonarConfig(config.sonarqube);
115
+ if (sonarConfig.external) {
116
+ return { exitCode: 0, stdout: "sonarqube.external=true, skipping Docker stop.", stderr: "" };
117
+ }
118
+ const compose = await ensureComposeFile(config.sonarqube);
119
+ return runCommand("docker", ["compose", "-f", compose, "stop"], { timeout: sonarConfig.timeouts.composeControlMs });
120
+ }
121
+
122
+ export async function sonarStatus() {
123
+ const { config } = await loadConfig();
124
+ const sonarConfig = normalizeSonarConfig(config.sonarqube);
125
+ const host = sonarConfig.host;
126
+
127
+ if (sonarConfig.external) {
128
+ if (await isSonarReachable(host, sonarConfig.timeouts.healthcheckSeconds)) {
129
+ return { exitCode: 0, stdout: `external SonarQube running at ${host}`, stderr: "" };
130
+ }
131
+ return { exitCode: 1, stdout: "", stderr: `external SonarQube is not reachable at ${host}` };
132
+ }
133
+
134
+ const containerRes = await runCommand("docker", ["ps", "--filter", `name=${sonarConfig.containerName}`, "--format", "{{.Status}}"]);
135
+ if (containerRes.stdout?.trim()) return containerRes;
136
+
137
+ if (await isSonarReachable(host, sonarConfig.timeouts.healthcheckSeconds)) {
138
+ return { exitCode: 0, stdout: `external SonarQube running at ${host}`, stderr: "" };
139
+ }
140
+
141
+ return containerRes;
142
+ }
143
+
144
+ export async function sonarLogs() {
145
+ const { config } = await loadConfig();
146
+ const sonarConfig = normalizeSonarConfig(config.sonarqube);
147
+ if (sonarConfig.external) {
148
+ return { exitCode: 1, stdout: "", stderr: "sonarqube.external=true, Docker logs are not available." };
149
+ }
150
+ return runCommand("docker", ["logs", "--tail", "100", sonarConfig.containerName], { timeout: sonarConfig.timeouts.logsMs });
151
+ }
152
+
153
+ const MIN_MAP_COUNT = 262144;
154
+
155
+ export async function checkVmMaxMapCount(platform) {
156
+ if (platform === "darwin" || platform === "win32") {
157
+ return { ok: true, reason: "vm.max_map_count check not required on this platform" };
158
+ }
159
+
160
+ const res = await runCommand("sysctl", ["vm.max_map_count"]);
161
+ if (res.exitCode !== 0) {
162
+ return {
163
+ ok: false,
164
+ reason: "Could not read vm.max_map_count",
165
+ fix: `sudo sysctl -w vm.max_map_count=${MIN_MAP_COUNT}`
166
+ };
167
+ }
168
+
169
+ const match = /=\s*(\d+)/.exec(res.stdout);
170
+ const current = match ? Number(match[1]) : 0;
171
+
172
+ if (current >= MIN_MAP_COUNT) {
173
+ return { ok: true, reason: `vm.max_map_count = ${current}` };
174
+ }
175
+
176
+ return {
177
+ ok: false,
178
+ reason: `vm.max_map_count = ${current} (needs >= ${MIN_MAP_COUNT})`,
179
+ fix: `sudo sysctl -w vm.max_map_count=${MIN_MAP_COUNT} && echo "vm.max_map_count=${MIN_MAP_COUNT}" | sudo tee -a /etc/sysctl.conf`
180
+ };
181
+ }
@@ -0,0 +1,120 @@
1
+ import crypto from "node:crypto";
2
+ import { runCommand } from "../utils/process.js";
3
+
4
+ function slug(value) {
5
+ return String(value || "")
6
+ .toLowerCase()
7
+ .replaceAll(/[^a-z0-9._:-]+/g, "-")
8
+ .replaceAll(/-{2,}/g, "-")
9
+ .replaceAll(/(^-+)|(-+$)/g, "");
10
+ }
11
+
12
+ function normalizeProjectKey(value) {
13
+ const out = slug(value);
14
+ if (!out) return "kj-default";
15
+ return /[a-z]/.test(out) ? out : `kj-${out}`;
16
+ }
17
+
18
+ function digest(input) {
19
+ return crypto.createHash("sha1").update(String(input)).digest("hex").slice(0, 12);
20
+ }
21
+
22
+ function parseScpLikeRemote(remoteUrl) {
23
+ // Example: git@github.com:owner/repo.git
24
+ const match = /^(?:[^@]+@)?([^:]+):(.+)$/.exec(String(remoteUrl || "").trim());
25
+ if (!match) return null;
26
+ return { host: match[1], path: match[2] };
27
+ }
28
+
29
+ function parseUrlLikeRemote(remoteUrl) {
30
+ try {
31
+ const parsed = new URL(String(remoteUrl || "").trim());
32
+ return { host: parsed.hostname, path: parsed.pathname.replace(/^\/+/, "") };
33
+ } catch { /* not a valid URL */
34
+ return null;
35
+ }
36
+ }
37
+
38
+ function canonicalRepoId(remoteUrl) {
39
+ const raw = String(remoteUrl || "").trim();
40
+ if (!raw) return null;
41
+
42
+ const parsed = raw.includes("://") ? parseUrlLikeRemote(raw) : (parseScpLikeRemote(raw) || parseUrlLikeRemote(raw));
43
+ if (!parsed) return null;
44
+
45
+ const host = String(parsed.host || "").trim().toLowerCase();
46
+ const cleanPath = String(parsed.path || "")
47
+ .trim()
48
+ .replaceAll(/(^\/+)|(\/+$)/g, "")
49
+ .replace(/\.git$/i, "")
50
+ .toLowerCase();
51
+ const segments = cleanPath.split("/").filter(Boolean);
52
+ if (!host || segments.length < 2) return null;
53
+
54
+ // Keep full repository path (owner/subgroups/repo) to avoid collisions in nested groups.
55
+ return `${host}/${segments.join("/")}`;
56
+ }
57
+
58
+ export async function resolveSonarProjectKey(config, options = {}) {
59
+ const explicit = String(
60
+ options.projectKey || process.env.KJ_SONAR_PROJECT_KEY || config?.sonarqube?.project_key || ""
61
+ ).trim();
62
+ if (explicit) {
63
+ return normalizeProjectKey(explicit);
64
+ }
65
+
66
+ const remote = await runCommand("git", ["config", "--get", "remote.origin.url"]);
67
+ const remoteUrl = String(remote.stdout || "").trim();
68
+ if (remote.exitCode !== 0 || !remoteUrl) {
69
+ throw new Error(
70
+ "Missing git remote.origin.url. Configure remote origin or set sonarqube.project_key explicitly."
71
+ );
72
+ }
73
+
74
+ const repoId = canonicalRepoId(remoteUrl);
75
+ if (!repoId) {
76
+ throw new Error(
77
+ "Unable to parse git remote.origin.url. Use a valid SSH/HTTPS remote or set sonarqube.project_key explicitly."
78
+ );
79
+ }
80
+
81
+ const repo = slug(repoId.split("/").pop());
82
+ return normalizeProjectKey(`kj-${repo}-${digest(repoId)}`);
83
+ }
84
+
85
+ /**
86
+ * Non-throwing predicate: can a Sonar project key be resolved for `config`?
87
+ *
88
+ * Used by callers (audit collector, run-loop SonarStage) that want to skip
89
+ * the Sonar work cleanly instead of letting `resolveSonarProjectKey` throw
90
+ * "Missing git remote.origin.url" deep inside the scanner. The scanner's
91
+ * thrown error is fine for an explicit `kj sonar` call (the user asked
92
+ * for it), but for implicit pipeline gates it produces a noisy "Sonar
93
+ * scan failed" loop in fresh /tmp/... repos.
94
+ *
95
+ * Returns true when EITHER:
96
+ * - an explicit `project_key` is set (env var, config, or per-call option),
97
+ * - OR `git config --get remote.origin.url` succeeds with a non-empty value.
98
+ *
99
+ * Side-effect-free apart from the git probe.
100
+ *
101
+ * @param {object} config
102
+ * @param {object} [options]
103
+ * @param {string} [options.projectKey]
104
+ * @returns {Promise<boolean>}
105
+ */
106
+ export async function canResolveSonarProjectKey(config, options = {}) {
107
+ const explicit = String(
108
+ options.projectKey || process.env.KJ_SONAR_PROJECT_KEY || config?.sonarqube?.project_key || ""
109
+ ).trim();
110
+ if (explicit) return true;
111
+ // try/catch (instead of `.catch(...)`) tolerates two legitimate test
112
+ // realities: a runCommand mock that returns undefined, and a real
113
+ // promise rejection from a missing git binary. Either way we treat
114
+ // it as "no remote available" and let the caller skip Sonar cleanly.
115
+ let remote;
116
+ try { remote = await runCommand("git", ["config", "--get", "remote.origin.url"]); }
117
+ catch { return false; }
118
+ if (!remote) return false;
119
+ return remote.exitCode === 0 && String(remote.stdout || "").trim().length > 0;
120
+ }