@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,462 @@
1
+ /**
2
+ * Preflight environment checks for kj_run.
3
+ *
4
+ * Runs AFTER policy resolution (so we know which stages are active)
5
+ * and BEFORE session iteration loop (so we fail fast).
6
+ *
7
+ * Design: SonarQube checks are BLOCKING when enabled — if SonarQube is
8
+ * configured but not available, the pipeline STOPS with a clear error.
9
+ * Security agent checks remain graceful (warning, auto-disable).
10
+ */
11
+
12
+ import { checkBinary } from "../utils/agent-detect.js";
13
+ import { isSonarReachable, sonarUp } from "../sonar/manager.js";
14
+ import { resolveSonarProjectKey, canResolveSonarProjectKey } from "../sonar/project-key.js";
15
+ import { runCommand } from "../utils/process.js";
16
+ import { emitProgress, makeEvent } from "../utils/events.js";
17
+ import { msg, getLang } from "../utils/messages.js";
18
+ import {
19
+ resolveSonarHost,
20
+ resolveSonarTokenAsync,
21
+ resolveSonarCredentials,
22
+ } from "../sonar/config-resolver.js";
23
+ import { saveSonarToken } from "../sonar/credentials.js";
24
+ import { withDocLink } from "../utils/doc-links.js";
25
+ import { runChecks as runCheckPipeline } from "../checks/runner.js";
26
+ import { STATUS } from "../checks/types.js";
27
+ import { getNodeChecks } from "../checks/node.js";
28
+ import { getDirSetupChecks } from "../checks/dir-setup.js";
29
+ import { getPortChecks } from "../checks/ports.js";
30
+ import { getTokenChecks } from "../checks/tokens.js";
31
+ import { getMcpHealthChecks } from "../checks/mcp-health.js";
32
+ import { getSkillsChecks } from "../checks/skills.js";
33
+ import { getProjectChecks } from "../checks/project-checks.js";
34
+ import { resolveTestHarness } from "../config/test-harness.js";
35
+
36
+ function parseJsonSafe(text) {
37
+ try {
38
+ return JSON.parse(text);
39
+ } catch { /* invalid JSON */
40
+ return null;
41
+ }
42
+ }
43
+
44
+ async function checkDocker() {
45
+ const result = await checkBinary("docker");
46
+ return {
47
+ name: "docker",
48
+ ok: result.ok,
49
+ detail: result.ok ? `Docker ${result.version}` : "Docker not found",
50
+ };
51
+ }
52
+
53
+ const SONAR_STARTUP_POLL_MS = 5000;
54
+ const SONAR_STARTUP_MAX_WAIT_MS = 60000;
55
+
56
+ async function waitForSonar(host, maxWaitMs = SONAR_STARTUP_MAX_WAIT_MS) {
57
+ const deadline = Date.now() + maxWaitMs;
58
+ while (Date.now() < deadline) {
59
+ if (await isSonarReachable(host)) return true;
60
+ await new Promise(r => setTimeout(r, SONAR_STARTUP_POLL_MS));
61
+ }
62
+ return false;
63
+ }
64
+
65
+ async function checkSonarReachable(host) {
66
+ const reachable = await isSonarReachable(host);
67
+ if (reachable) {
68
+ return { name: "sonar-reachable", ok: true, detail: `SonarQube reachable at ${host}`, remediated: false };
69
+ }
70
+
71
+ // Auto-remediation: start SonarQube and wait for it to be ready
72
+ try {
73
+ const upResult = await sonarUp(host);
74
+ if (upResult.exitCode === 0) {
75
+ // SonarQube needs 20-40s to start. Poll until ready.
76
+ if (await waitForSonar(host)) {
77
+ return { name: "sonar-reachable", ok: true, detail: `SonarQube started and reachable at ${host}`, remediated: true };
78
+ }
79
+ }
80
+ } catch {
81
+ // sonarUp failed, fall through
82
+ }
83
+
84
+ return { name: "sonar-reachable", ok: false, detail: `SonarQube not reachable at ${host} (auto-start failed after ${SONAR_STARTUP_MAX_WAIT_MS / 1000}s)` };
85
+ }
86
+
87
+ async function checkSonarAuth(config) {
88
+ const host = resolveSonarHost(config.sonarqube?.host);
89
+
90
+ // Check explicit token first (including persisted tokens from credentials file)
91
+ const explicitToken = await resolveSonarTokenAsync(config);
92
+ if (explicitToken) {
93
+ // Validate the token works
94
+ const res = await runCommand("curl", [
95
+ "-sS", "-o", "/dev/null", "-w", "%{http_code}",
96
+ "-H", `Authorization: Bearer ${explicitToken}`,
97
+ "--max-time", "5",
98
+ `${host}/api/authentication/validate`
99
+ ]);
100
+ if (res.exitCode === 0 && res.stdout.trim().startsWith("2")) {
101
+ return { name: "sonar-auth", ok: true, detail: "Sonar token valid", token: explicitToken };
102
+ }
103
+ }
104
+
105
+ // Try admin credentials via centralized resolver
106
+ const { user: adminUser, passwords } = await resolveSonarCredentials(config);
107
+
108
+ if (!adminUser || passwords.length === 0) {
109
+ return { name: "sonar-auth", ok: false, detail: "No Sonar token or admin credentials configured. Set KJ_SONAR_TOKEN, configure sonarqube.token in kj.config.yml, or save credentials in ~/.karajan/sonar-credentials.json." };
110
+ }
111
+
112
+ for (const password of passwords) {
113
+ const validateRes = await runCommand("curl", [
114
+ "-sS", "-u", `${adminUser}:${password}`,
115
+ `${host}/api/authentication/validate`
116
+ ]);
117
+ if (validateRes.exitCode !== 0) continue;
118
+ const parsed = parseJsonSafe(validateRes.stdout);
119
+ if (!parsed?.valid) continue;
120
+
121
+ // Generate a user token
122
+ const tokenName = `karajan-preflight-${Date.now()}`;
123
+ const tokenRes = await runCommand("curl", [
124
+ "-sS", "-u", `${adminUser}:${password}`,
125
+ "-X", "POST",
126
+ "--data-urlencode", `name=${tokenName}`,
127
+ `${host}/api/user_tokens/generate`
128
+ ]);
129
+ if (tokenRes.exitCode !== 0) continue;
130
+ const tokenParsed = parseJsonSafe(tokenRes.stdout);
131
+ if (tokenParsed?.token) {
132
+ // Persist the generated token for future sessions
133
+ try { await saveSonarToken(tokenParsed.token); } catch { /* non-blocking */ }
134
+ return { name: "sonar-auth", ok: true, detail: "Sonar token generated and saved", token: tokenParsed.token };
135
+ }
136
+ }
137
+
138
+ return { name: "sonar-auth", ok: false, detail: "Could not validate or generate Sonar token" };
139
+ }
140
+
141
+ /**
142
+ * KJC-BUG-0083 — run the real project-key resolver at preflight time so a
143
+ * repo Sonar cannot scan aborts BEFORE the first coder iteration instead
144
+ * of dying in sonar_repeat after burning tokens. Sonar stays mandatory
145
+ * for code tasks (v2.7.4 contract); this only moves the failure earlier.
146
+ */
147
+ async function checkSonarProjectKey(config) {
148
+ // No remote at all (fresh local project): the SonarStage already skips
149
+ // cleanly via canResolveSonarProjectKey, so preflight must not block.
150
+ // The hard-fail case is the inconsistent one: a remote EXISTS but the
151
+ // resolver cannot parse it — that's what looped into sonar_repeat.
152
+ if (!(await canResolveSonarProjectKey(config))) {
153
+ return { name: "sonar-project-key", ok: true, detail: "No git remote — Sonar stage will skip cleanly" };
154
+ }
155
+ try {
156
+ const key = await resolveSonarProjectKey(config);
157
+ return { name: "sonar-project-key", ok: true, detail: `Project key resolved: ${key}` };
158
+ } catch (err) {
159
+ return { name: "sonar-project-key", ok: false, detail: err.message };
160
+ }
161
+ }
162
+
163
+ async function checkSecurityAgent(config) {
164
+ const provider = config.roles?.security?.provider
165
+ || config.roles?.coder?.provider
166
+ || config.coder
167
+ || "claude";
168
+
169
+ const result = await checkBinary(provider);
170
+ return {
171
+ name: "security-agent",
172
+ ok: result.ok,
173
+ detail: result.ok ? `Security agent "${provider}" available (${result.version})` : `Security agent "${provider}" not found`,
174
+ provider,
175
+ };
176
+ }
177
+
178
+ /**
179
+ * Run preflight environment checks.
180
+ *
181
+ * SonarQube checks are BLOCKING: if SonarQube is enabled but not available,
182
+ * ok will be false and errors[] will contain actionable fix instructions.
183
+ * Security agent checks remain graceful (auto-disable via configOverrides).
184
+ *
185
+ * @param {object} opts
186
+ * @param {object} opts.config - Karajan config
187
+ * @param {object} opts.logger - Logger instance
188
+ * @param {object|null} opts.emitter - Event emitter
189
+ * @param {object} opts.eventBase - Base event data
190
+ * @param {object} opts.resolvedPolicies - Output from applyPolicies()
191
+ * @param {boolean} opts.securityEnabled - Whether security stage is enabled
192
+ * @returns {{ ok: boolean, checks: object[], remediations: string[], configOverrides: object, warnings: string[], errors: object[] }}
193
+ */
194
+ export async function runPreflightChecks({ config, logger, emitter, eventBase, resolvedPolicies, securityEnabled }) {
195
+ // Defensive test-harness resolution for direct callers that bypass loadConfig()
196
+ // (notably tests/preflight-checks.test.js and tests/sonar-token-flow.test.js
197
+ // which construct raw configs). Production callers go through loadConfig
198
+ // which already populates config.testHarness once via resolveTestHarness().
199
+ // Idempotent — no-op when already present.
200
+ if (config && !config.testHarness) {
201
+ config.testHarness = resolveTestHarness(config.testHarness);
202
+ }
203
+ // Sonar is intrinsic to Karajan for code tasks (sw/refactor/add-tests).
204
+ // Since v2.7.4 it is NOT toggleable via `config.sonarqube.enabled` —
205
+ // that field is ignored (deprecation warning emitted at config load).
206
+ // The taskType policy (resolved_policies.sonar from DEFAULT_POLICIES in
207
+ // src/guards/policy-resolver.js) is the single source of truth: sw /
208
+ // refactor / add-tests run Sonar, audit / doc / infra / analysis /
209
+ // no-code skip it. Solomon may decide to skip a single iteration via
210
+ // rule alerts — that's a runtime decision, not a config option.
211
+ //
212
+ // Test-harness escape hatch via config.testHarness.disableSonarStage
213
+ // — production code reads `config?.testHarness?.disableSonarStage`,
214
+ // never `globalThis.*`. The legacy `globalThis.__KJ_DISABLE_SONAR_STAGE`
215
+ // shape is documented (and exclusively read) in
216
+ // src/config/test-harness.js, where the loader translates it into
217
+ // the typed config slot above. ESLint rule (#557) blocks any
218
+ // re-introduction outside that one file.
219
+ const sonarStageDisabledForTest = config?.testHarness?.disableSonarStage === true;
220
+ const sonarEnabled = !sonarStageDisabledForTest && resolvedPolicies.sonar !== false;
221
+ const isExternalSonar = Boolean(config.sonarqube?.external);
222
+ const sonarHost = resolveSonarHost(config.sonarqube?.host);
223
+
224
+ const result = {
225
+ ok: true,
226
+ checks: [],
227
+ remediations: [],
228
+ configOverrides: {},
229
+ warnings: [],
230
+ errors: [],
231
+ };
232
+
233
+ // Resolve extended preflight opt-in early so the short-circuit below can see it.
234
+ // Post-v2.7.5 this no longer reads globalThis directly — config.testHarness
235
+ // is populated by the loader from the global or the default.
236
+ const extendedDefault = config?.testHarness?.defaultPreflightExtended ?? true;
237
+ const extendedEnabled = config?.preflight?.extended ?? extendedDefault;
238
+
239
+ // Preserve legacy short-circuit: if nothing at all needs checking, skip
240
+ // emitting the whole preflight bracket.
241
+ if (!sonarEnabled && !securityEnabled && !extendedEnabled) {
242
+ logger.info("Preflight: skipped (no sonar, no security, extended disabled)");
243
+ emitProgress(emitter, makeEvent("preflight:end", { ...eventBase, stage: "preflight" }, {
244
+ message: "Preflight skipped (no checks needed)",
245
+ detail: { ...result, executorType: "local" }
246
+ }));
247
+ return result;
248
+ }
249
+
250
+ emitProgress(emitter, makeEvent("preflight:start", { ...eventBase, stage: "preflight" }, {
251
+ message: "Running preflight environment checks",
252
+ detail: { sonarEnabled, securityEnabled, extendedEnabled, executorType: "local" }
253
+ }));
254
+
255
+ // --- 1. Docker (only if sonar enabled and not external) ---
256
+ if (sonarEnabled && !isExternalSonar) {
257
+ const dockerCheck = await checkDocker();
258
+ result.checks.push(dockerCheck);
259
+
260
+ emitProgress(emitter, makeEvent("preflight:check", { ...eventBase, stage: "preflight" }, {
261
+ status: dockerCheck.ok ? "ok" : "fail",
262
+ message: `Docker: ${dockerCheck.detail}`,
263
+ detail: dockerCheck
264
+ }));
265
+
266
+ if (!dockerCheck.ok) {
267
+ result.ok = false;
268
+ result.errors.push({
269
+ check: "docker",
270
+ message: "Docker not available but SonarQube is enabled.",
271
+ fix: withDocLink("Start Docker, or disable SonarQube: set sonarqube.enabled: false in kj.config.yml, or pass --no-sonar.", "sonar_docker")
272
+ });
273
+ logger.error("Preflight: Docker not found — SonarQube requires Docker");
274
+
275
+ // Skip remaining sonar checks, continue to security
276
+ if (!securityEnabled) {
277
+ emitProgress(emitter, makeEvent("preflight:end", { ...eventBase, stage: "preflight" }, {
278
+ status: "fail", message: "Preflight FAILED — environment not ready", detail: result
279
+ }));
280
+ return result;
281
+ }
282
+ }
283
+ }
284
+
285
+ // --- 2. SonarQube reachable ---
286
+ if (sonarEnabled && result.ok) {
287
+ const reachableCheck = await checkSonarReachable(sonarHost);
288
+ result.checks.push(reachableCheck);
289
+
290
+ if (reachableCheck.remediated) {
291
+ result.remediations.push("SonarQube auto-started via docker compose");
292
+ }
293
+
294
+ emitProgress(emitter, makeEvent("preflight:check", { ...eventBase, stage: "preflight" }, {
295
+ status: reachableCheck.ok ? "ok" : "fail",
296
+ message: `SonarQube reachability: ${reachableCheck.detail}`,
297
+ detail: reachableCheck
298
+ }));
299
+
300
+ if (!reachableCheck.ok) {
301
+ result.ok = false;
302
+ result.errors.push({
303
+ check: "sonar-reachable",
304
+ message: `SonarQube not reachable at ${sonarHost}.`,
305
+ fix: withDocLink("Start SonarQube: 'docker start karajan-sonarqube', or disable it: set sonarqube.enabled: false in kj.config.yml, or pass --no-sonar.", "sonar_docker")
306
+ });
307
+ logger.error("Preflight: SonarQube not reachable after remediation attempt");
308
+ }
309
+ }
310
+
311
+ // --- 3. SonarQube auth/token ---
312
+ if (sonarEnabled && result.ok) {
313
+ const authCheck = await checkSonarAuth(config);
314
+ result.checks.push(authCheck);
315
+
316
+ emitProgress(emitter, makeEvent("preflight:check", { ...eventBase, stage: "preflight" }, {
317
+ status: authCheck.ok ? "ok" : "fail",
318
+ message: `SonarQube auth: ${authCheck.detail}`,
319
+ detail: { name: authCheck.name, ok: authCheck.ok, detail: authCheck.detail }
320
+ }));
321
+
322
+ if (authCheck.ok && authCheck.token) {
323
+ process.env.KJ_SONAR_TOKEN = authCheck.token;
324
+ result.remediations.push("Sonar token resolved and cached in KJ_SONAR_TOKEN");
325
+ logger.info("Preflight: Sonar token resolved and cached");
326
+ } else if (!authCheck.ok) {
327
+ result.ok = false;
328
+ result.errors.push({
329
+ check: "sonar-auth",
330
+ message: "SonarQube is running but no authentication token is configured.",
331
+ fix: withDocLink("Fix: run 'kj init' to configure it, or set KJ_SONAR_TOKEN env var, or add sonarqube.token to ~/.karajan/kj.config.yml.", "sonar_token")
332
+ });
333
+ logger.error("Preflight: Sonar auth failed");
334
+ }
335
+ }
336
+
337
+ // --- 3b. Sonar project key derivable (KJC-BUG-0083) ---
338
+ // The scanner derives its project key from git remote.origin.url. With
339
+ // an unparseable remote (local-path bare, exotic URL) and no explicit
340
+ // sonarqube.project_key, every iteration's scan threw, the run burned
341
+ // coder tokens and died in sonar_repeat. Run the REAL resolver here —
342
+ // canResolveSonarProjectKey() is weaker (any non-empty remote passes) —
343
+ // so the run fails fast with the actionable message before iteration 1.
344
+ if (sonarEnabled && result.ok) {
345
+ const keyCheck = await checkSonarProjectKey(config);
346
+ result.checks.push(keyCheck);
347
+
348
+ emitProgress(emitter, makeEvent("preflight:check", { ...eventBase, stage: "preflight" }, {
349
+ status: keyCheck.ok ? "ok" : "fail",
350
+ message: `Sonar project key: ${keyCheck.detail}`,
351
+ detail: keyCheck
352
+ }));
353
+
354
+ if (!keyCheck.ok) {
355
+ result.ok = false;
356
+ result.errors.push({
357
+ check: "sonar-project-key",
358
+ message: "Sonar cannot scan this repository: no project key can be derived.",
359
+ fix: withDocLink("Set sonarqube.project_key in kj.config.yml, or point remote.origin.url at a valid SSH/HTTPS remote.", "sonar_docker")
360
+ });
361
+ logger.error("Preflight: Sonar project key not derivable — failing fast before burning iterations");
362
+ }
363
+ }
364
+
365
+ // --- 4. Security agent (graceful — only warning, not blocking) ---
366
+ if (securityEnabled) {
367
+ const secCheck = await checkSecurityAgent(config);
368
+ result.checks.push(secCheck);
369
+
370
+ emitProgress(emitter, makeEvent("preflight:check", { ...eventBase, stage: "preflight" }, {
371
+ status: secCheck.ok ? "ok" : "warn",
372
+ message: `Security agent: ${secCheck.detail}`,
373
+ detail: secCheck
374
+ }));
375
+
376
+ if (!secCheck.ok) {
377
+ result.configOverrides.securityDisabled = true;
378
+ result.warnings.push(`Security agent "${secCheck.provider}" not found — security stage auto-disabled`);
379
+ logger.warn(`Preflight: Security agent "${secCheck.provider}" not found, disabling security stage`);
380
+ }
381
+ }
382
+
383
+ // --- 5. Complementary doctor-style checks (Node version, ports, tokens, MCP
384
+ // health, ~/.karajan dirs, openskills). These are auto-remediated
385
+ // with yes:true because preflight runs non-interactively inside kj run.
386
+ // Opt-out via `config.preflight.extended: false`. Defaults to true
387
+ // in production; the test harness (tests/setup.js) defaults it off.
388
+ if (extendedEnabled) {
389
+ await runExtendedPreflight({ config, result, emitter, eventBase, logger });
390
+ }
391
+
392
+ const hasErrors = result.errors.length > 0;
393
+ const hasWarnings = result.warnings.length > 0;
394
+ const preflightLang = getLang(config);
395
+ emitProgress(emitter, makeEvent("preflight:end", { ...eventBase, stage: "preflight" }, {
396
+ status: hasErrors ? "fail" : hasWarnings ? "warn" : "ok",
397
+ message: hasErrors
398
+ ? `Preflight FAILED — ${result.errors.length} blocking issue(s)`
399
+ : hasWarnings
400
+ ? `Preflight completed with ${result.warnings.length} warning(s)`
401
+ : msg("preflight_passed", preflightLang),
402
+ detail: { ...result, executorType: "local" }
403
+ }));
404
+
405
+ return result;
406
+ }
407
+
408
+ /**
409
+ * Run the doctor-style complementary checks and merge their outcomes into
410
+ * the existing preflight result shape. Runs with yes:true (non-interactive)
411
+ * and auto-remediation enabled. FAIL/TIMEOUT are appended to errors (blocking),
412
+ * WARN are appended to warnings (non-blocking), FIXED status is recorded as a
413
+ * remediation, and runtime overrides from auto-fixes are merged into
414
+ * configOverrides.
415
+ */
416
+ async function runExtendedPreflight({ config, result, emitter, eventBase, logger }) {
417
+ const checks = [
418
+ ...getNodeChecks(),
419
+ ...getDirSetupChecks(),
420
+ ...getPortChecks(),
421
+ ...getTokenChecks(config),
422
+ ...getMcpHealthChecks(),
423
+ ...getSkillsChecks(),
424
+ // KJC-TSK-0393: project-aware checks (signal detection, write perms,
425
+ // tools per signal, .env consistency, gh remote access). Saltables con
426
+ // flag --no-project-checks en kj run.
427
+ ...(config?.flags?.noProjectChecks ? [] : getProjectChecks({ projectDir: config?.projectDir || process.cwd() })),
428
+ ];
429
+ let report;
430
+ try {
431
+ report = await runCheckPipeline(checks, { config }, { mode: "fix", yes: true, timeoutMs: 3000, logger });
432
+ } catch (err) {
433
+ logger.warn(`Preflight: extended checks failed to run (${err.message})`);
434
+ return;
435
+ }
436
+
437
+ for (const c of report.checks) {
438
+ result.checks.push({ name: c.name, ok: c.status === STATUS.OK || c.status === STATUS.FIXED || c.status === STATUS.SKIPPED, detail: c.detail });
439
+ const eventStatus = c.status === STATUS.FAIL || c.status === STATUS.TIMEOUT
440
+ ? "fail"
441
+ : c.status === STATUS.WARN
442
+ ? "warn"
443
+ : "ok";
444
+ emitProgress(emitter, makeEvent("preflight:check", { ...eventBase, stage: "preflight" }, {
445
+ status: eventStatus,
446
+ message: `${c.label}: ${c.detail}`,
447
+ detail: { name: c.name, status: c.status, detail: c.detail, fix: c.fix }
448
+ }));
449
+ if (c.status === STATUS.FIXED) {
450
+ result.remediations.push(`${c.label}: ${c.detail}`);
451
+ } else if (c.status === STATUS.FAIL || c.status === STATUS.TIMEOUT) {
452
+ result.ok = false;
453
+ result.errors.push({ check: c.name, message: `${c.label}: ${c.detail}`, fix: c.fix });
454
+ } else if (c.status === STATUS.WARN) {
455
+ result.warnings.push(`${c.label}: ${c.detail}`);
456
+ }
457
+ }
458
+
459
+ if (report.overrides && Object.keys(report.overrides).length > 0) {
460
+ Object.assign(result.configOverrides, report.overrides);
461
+ }
462
+ }
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Heuristics for classifying an acceptance-test failure as "possibly
3
+ * infeasible" — i.e. the test itself looks broken, not the code.
4
+ *
5
+ * Used by the HU sub-pipeline to decide when to invoke the Repairer
6
+ * role instead of feeding the failure back to the coder for ANOTHER
7
+ * iteration. Each iteration costs real money + time; classifying
8
+ * misroutes is the difference between a 3-minute repair and a
9
+ * 30-minute budget burn.
10
+ *
11
+ * The classifier is deliberately CONSERVATIVE: false negatives
12
+ * (treating a broken test as just-failed) cost an extra iteration;
13
+ * false positives (treating a real failure as infeasible) waste a
14
+ * Repairer call AND give the coder a spec change it shouldn't
15
+ * receive. We err toward false negatives.
16
+ */
17
+
18
+ /**
19
+ * Signatures that strongly suggest the TEST is broken, not the code.
20
+ * Each is a regex applied to the failing command's stderr+stdout.
21
+ */
22
+ const INFEASIBLE_SIGNATURES = [
23
+ // jq: `length as $n | .field` after a transform — the binding doesn't
24
+ // change the value flowing through, so `.field` is applied to the wrong
25
+ // thing. Real-world example from 2026-04-29: "Cannot index array with
26
+ // string \"filesOver300LOC\"".
27
+ { kind: "jq-as-binding-misuse", re: /Cannot index array with string/i },
28
+ // bash -n / shell parse errors before the command even runs.
29
+ { kind: "shell-parse-error", re: /syntax error|unexpected token|unexpected EOF/i },
30
+ // jq: invalid query syntax detected by jq itself.
31
+ { kind: "jq-syntax", re: /jq: error \(at .*\): (?!Cannot index)/i },
32
+ // command not found = test references a tool that doesn't exist in
33
+ // this environment. Could be a fixable typo or a real env mismatch.
34
+ { kind: "missing-tool", re: /command not found|: not found$|No such file or directory.*\.(sh|mjs|js|py)/im },
35
+ // jq fails to parse the JSON input — the input file is wrong, the
36
+ // path is wrong, or the assumed schema is off.
37
+ { kind: "jq-parse-input", re: /jq: error: Could not (open|parse)/i },
38
+ ];
39
+
40
+ /**
41
+ * Compute a stable signature for a single failing test outcome — the
42
+ * test command + a normalized error fingerprint. Used to detect when
43
+ * the SAME test is failing the SAME way across iterations; that's the
44
+ * pattern that argues for a Repairer call (vs. a coder retry).
45
+ *
46
+ * @param {string} cmd
47
+ * @param {string} errorOutput
48
+ * @returns {string}
49
+ */
50
+ export function failureSignature(cmd, errorOutput) {
51
+ const cmdNorm = String(cmd || "").trim().slice(0, 200);
52
+ const errNorm = String(errorOutput || "")
53
+ .replaceAll(/\s+/g, " ") // collapse whitespace
54
+ .replaceAll(/\d+/g, "N") // numbers tend to drift; line numbers, counts
55
+ .replaceAll(/\/[^\s]+/g, "/PATH") // absolute paths drift across runs
56
+ .trim()
57
+ .slice(0, 300);
58
+ return `${cmdNorm}|||${errNorm}`;
59
+ }
60
+
61
+ /**
62
+ * Classify a single test failure as `infeasible` or `regular`.
63
+ *
64
+ * @param {object} args
65
+ * @param {string} args.cmd — the command that ran
66
+ * @param {string} args.errorOutput — stdout + stderr from the failing run
67
+ * @param {number} args.consecutive — how many iterations in a row this
68
+ * same signature has failed
69
+ * @param {number} [args.threshold=2] — min consecutive failures before
70
+ * infeasibility is even considered.
71
+ * Below this, we always say "regular"
72
+ * (let the coder try once more).
73
+ * @returns {{infeasible: boolean, kind: string|null, signature: string}}
74
+ */
75
+ export function classifyFailure({ cmd, errorOutput, consecutive, threshold = 2 }) {
76
+ const signature = failureSignature(cmd, errorOutput);
77
+ if (!Number.isFinite(consecutive) || consecutive < threshold) {
78
+ return { infeasible: false, kind: null, signature };
79
+ }
80
+ for (const sig of INFEASIBLE_SIGNATURES) {
81
+ if (sig.re.test(errorOutput || "")) {
82
+ return { infeasible: true, kind: sig.kind, signature };
83
+ }
84
+ }
85
+ return { infeasible: false, kind: null, signature };
86
+ }
87
+
88
+ /**
89
+ * Track consecutive identical failures across iterations of the same HU.
90
+ * Caller passes the same instance across iterations; the tracker
91
+ * remembers the last signature per command.
92
+ */
93
+ export function createFailureTracker() {
94
+ // Map<cmd, { signature, count }>
95
+ const state = new Map();
96
+ return {
97
+ /**
98
+ * Record a failure and return how many consecutive iterations have
99
+ * produced the same signature for this cmd.
100
+ * @returns {number}
101
+ */
102
+ record(cmd, errorOutput) {
103
+ const signature = failureSignature(cmd, errorOutput);
104
+ const prev = state.get(cmd);
105
+ if (prev && prev.signature === signature) {
106
+ prev.count += 1;
107
+ return prev.count;
108
+ }
109
+ state.set(cmd, { signature, count: 1 });
110
+ return 1;
111
+ },
112
+ /** Reset tracker for a cmd that just passed (stops false positives). */
113
+ reset(cmd) { state.delete(cmd); },
114
+ /** Diagnostic: dump current state. */
115
+ snapshot() { return Object.fromEntries(state); },
116
+ };
117
+ }