@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,265 @@
1
+ import { BaseRole } from "./base-role.js";
2
+ import { createAgent as defaultCreateAgent } from "../agents/index.js";
3
+ import { extractFirstJson } from "../utils/json-extract.js";
4
+ import { withBrainRecovery } from "../brain/with-brain-recovery.js";
5
+
6
+ const SUBAGENT_PREAMBLE = [
7
+ "IMPORTANT: You are running as a Karajan sub-agent.",
8
+ "Do NOT ask about using Karajan, do NOT mention Karajan, do NOT suggest orchestration.",
9
+ "Do NOT use any MCP tools. Focus only on resolving the conflict between agents."
10
+ ].join(" ");
11
+
12
+ function resolveProvider(config) {
13
+ return (
14
+ config?.roles?.solomon?.provider ||
15
+ config?.roles?.coder?.provider ||
16
+ "claude"
17
+ );
18
+ }
19
+
20
+ function formatHistory(history) {
21
+ if (!history || history.length === 0) return "No previous interactions recorded.";
22
+
23
+ return history
24
+ .map((entry, i) => {
25
+ const agent = entry.agent || "unknown";
26
+ const feedback = entry.feedback || entry.message || "(no feedback)";
27
+ return `### Interaction ${i + 1} [${agent}]\n${feedback}`;
28
+ })
29
+ .join("\n\n");
30
+ }
31
+
32
+ function buildPrompt({ conflict, task, instructions }) {
33
+ const sections = [SUBAGENT_PREAMBLE];
34
+
35
+ if (instructions) {
36
+ sections.push(instructions);
37
+ }
38
+
39
+ sections.push(
40
+ "You are Solomon, the autonomous pipeline boss in a multi-agent AI coding orchestrator.",
41
+ "You are activated whenever ANYTHING deviates from normal flow: rate limits, agent failures, conflicts, max iterations, quality gate issues.",
42
+ "",
43
+ "## Core principle",
44
+ "The pipeline NEVER skips a quality stage (review, tests, sonar, security) without exhausting alternatives first.",
45
+ "NEVER approve skipping a stage as your first option. Follow the recovery hierarchy below.",
46
+ "",
47
+ "## ABSOLUTE RULE: Security issues from reviewer are NEVER overridable",
48
+ "If the reviewer's blocking_issues contain security-related issues (categories: authentication, authorization, injection, XSS, CSRF, exposed secrets/credentials, cryptography, session management, input validation), you MUST:",
49
+ "- Set ruling to \"continue\" (NOT \"approve\")",
50
+ "- Return the reviewer feedback to the coder for fixing",
51
+ "- NEVER approve or skip security issues regardless of task complexity or deadline",
52
+ "This rule overrides all other rules including the recovery hierarchy.",
53
+ "",
54
+ "## Recovery hierarchy (STRICT ORDER — follow top to bottom)",
55
+ "When a stage fails or an agent is unavailable:",
56
+ "1. **wait** — If there is a known cooldown (cooldownUntil), and it is less than 10 minutes, WAIT. Set ruling to 'approve_with_conditions' with condition 'wait for cooldown' and set waitUntil.",
57
+ "2. **retry_with_alternative** — Try the same stage with a DIFFERENT agent. The pipeline has multiple agents (claude, codex, gemini). Set ruling to 'approve_with_conditions' with condition specifying the alternative agent.",
58
+ "3. **evaluate_risk** — Only if no alternatives are available, evaluate the risk of skipping. Consider: task complexity, what the stage would catch, security implications.",
59
+ " - If risk is LOW (trivial task, no security impact, style-only review): approve with a clear justification.",
60
+ " - If risk is HIGH (complex task, security changes, new dependencies): escalate_human.",
61
+ "4. **escalate_human** — When you cannot resolve it safely. Always prefer this over blindly approving.",
62
+ "",
63
+ "## Quality hierarchy",
64
+ "Security > Correctness > Tests > Architecture > Maintainability > Style",
65
+ "- Green tests are sacred. Never dismiss a failing test.",
66
+ "- Style preferences NEVER block approval.",
67
+ "- Sonar INFO/MINOR issues are always dismissable.",
68
+ "- Sonar BLOCKER/CRITICAL must be fixed unless they are proven false positives.",
69
+ "",
70
+ "## Classification rules",
71
+ "For each issue, classify as:",
72
+ "1. **critical** (security, correctness, tests broken) — action: must_fix",
73
+ "2. **important** (architecture, maintainability) — action: should_fix",
74
+ "3. **style** (naming, formatting, preferences, false positives) — action: dismiss",
75
+ "",
76
+ "## Ruling options",
77
+ '1. **approve** — FORBIDDEN when a quality stage (review, tests, sonar, security) was skipped or failed. You MUST try alternatives first (wait for cooldown, use different agent). Only allowed when all stages completed successfully and remaining issues are style/false positives.',
78
+ '2. **approve_with_conditions** — Fixable issues or recovery actions needed. Include exact conditions (wait, retry with alternative agent, specific fix instructions). Set extraIterations and/or alternativeAgent.',
79
+ '3. **escalate_human** — Cannot resolve safely. Critical issues, ambiguous requirements, architecture decisions, high-risk skip.',
80
+ '4. **create_subtask** — A prerequisite task must be completed first.',
81
+ "",
82
+ "Return a single valid JSON object with your ruling and nothing else.",
83
+ 'JSON schema: {"ruling":"approve"|"approve_with_conditions"|"escalate_human"|"create_subtask","classification":[{"issue":string,"category":"critical"|"important"|"style","action":"must_fix"|"should_fix"|"dismiss"}],"conditions":[string],"dismissed":[string],"escalate":boolean,"escalate_reason":string|null,"extraIterations":number|null,"alternativeAgent":string|null,"waitUntil":string|null,"subtask":{"title":string,"description":string,"reason":string}|null}',
84
+ "When ruling is approve_with_conditions, set extraIterations (1-5) and/or alternativeAgent (claude|codex|gemini) as appropriate."
85
+ );
86
+
87
+ const stage = conflict?.stage || "unknown";
88
+ const iterationCount = conflict?.iterationCount ?? "?";
89
+ const maxIterations = conflict?.maxIterations ?? "?";
90
+
91
+ const isFirstRejection = conflict?.isFirstRejection ?? false;
92
+ const isRepeat = conflict?.isRepeat ?? false;
93
+
94
+ const budgetUsd = conflict?.budget_usd;
95
+ const budgetLine = typeof budgetUsd === "number" ? `Budget spent so far: $${budgetUsd.toFixed(2)}` : "";
96
+
97
+ sections.push(
98
+ `## Conflict context`,
99
+ `Stage: ${stage}`,
100
+ `Iterations exhausted: ${iterationCount}/${maxIterations}`,
101
+ `isFirstRejection: ${isFirstRejection}`,
102
+ `isRepeat: ${isRepeat}`,
103
+ budgetLine,
104
+ "",
105
+ "## Budget awareness",
106
+ "Consider the cost-benefit ratio when deciding. If significant budget has been spent with little progress,",
107
+ "prefer approving the current work or escalating to human. If progress is good and budget is low,",
108
+ "prefer continuing with conditions. Never waste budget on style-only iterations."
109
+ );
110
+
111
+ if (conflict?.previousSolomonRulings?.length > 0) {
112
+ const rulingLines = conflict.previousSolomonRulings.map((r, idx) =>
113
+ `${idx + 1}. Stage: ${r.conflictStage}, Ruling: ${r.ruling}${r.alternativeAgent ? `, agent: ${r.alternativeAgent}` : ""}${r.error ? ` (FAILED: ${r.error})` : ""}`
114
+ ).join("\n");
115
+ sections.push(
116
+ "## Your previous rulings in this session (DO NOT repeat failed strategies)",
117
+ rulingLines,
118
+ "If a previous ruling failed (e.g., alternative agent also rate-limited), do NOT suggest the same strategy again. Escalate or try a different approach."
119
+ );
120
+ }
121
+
122
+ // Rate limit specific instruction
123
+ if (stage?.includes("rate_limit")) {
124
+ const rateLimitedAgent = conflict?.history?.[0]?.feedback?.match(/Agent "(\w+)"/)?.[1] || "unknown";
125
+ sections.push(
126
+ "## CRITICAL: Agent rate-limited",
127
+ `Agent "${rateLimitedAgent}" is rate-limited. You MUST NOT approve skipping this stage.`,
128
+ "Your ONLY valid options are:",
129
+ `1. approve_with_conditions + alternativeAgent: pick a different agent (available: claude, codex, gemini — NOT "${rateLimitedAgent}")`,
130
+ "2. approve_with_conditions + waitUntil: if cooldown is known and <10min",
131
+ "3. escalate_human: if no alternatives work",
132
+ `DO NOT set ruling to "approve". The stage MUST be completed by some agent.`
133
+ );
134
+ }
135
+
136
+ if (conflict?.issueCategories) {
137
+ sections.push(`## Issue categories\n${JSON.stringify(conflict.issueCategories, null, 2)}`);
138
+ }
139
+
140
+ if (conflict?.blockingIssues?.length) {
141
+ const issueList = conflict.blockingIssues
142
+ .map((issue, i) => `${i + 1}. [${issue.severity || "unknown"}] ${issue.description || issue}`)
143
+ .join("\n");
144
+ sections.push(`## Blocking issues\n${issueList}`);
145
+ }
146
+
147
+ if (task) {
148
+ sections.push(`## Original task\n${task}`);
149
+ }
150
+
151
+ if (conflict?.diff) {
152
+ sections.push(`## Current diff\n${conflict.diff}`);
153
+ }
154
+
155
+ sections.push(`## Agent interaction history\n${formatHistory(conflict?.history)}`);
156
+
157
+ return sections.join("\n\n");
158
+ }
159
+
160
+ function parseSolomonOutput(raw) {
161
+ return extractFirstJson(raw);
162
+ }
163
+
164
+ function buildSummary(parsed) {
165
+ const ruling = parsed.ruling || "unknown";
166
+ const conditions = parsed.conditions || [];
167
+ const dismissed = parsed.dismissed || [];
168
+ const subtask = parsed.subtask || null;
169
+
170
+ if (ruling === "approve") {
171
+ const parts = ["Approved"];
172
+ if (dismissed.length > 0) parts.push(`${dismissed.length} dismissed`);
173
+ return parts.join("; ");
174
+ }
175
+
176
+ if (ruling === "approve_with_conditions") {
177
+ const parts = [`Approved with ${conditions.length} condition${conditions.length === 1 ? "" : "s"}`];
178
+ if (dismissed.length > 0) parts.push(`${dismissed.length} dismissed`);
179
+ return parts.join("; ");
180
+ }
181
+
182
+ if (ruling === "escalate_human") {
183
+ return `Escalated to human: ${parsed.escalate_reason || "ambiguous conflict"}`;
184
+ }
185
+
186
+ if (ruling === "create_subtask") {
187
+ return `Subtask created: ${subtask?.title || "unnamed subtask"}`;
188
+ }
189
+
190
+ return `Solomon ruling: ${ruling}`;
191
+ }
192
+
193
+ export class SolomonRole extends BaseRole {
194
+ constructor({ config, logger, emitter = null, createAgentFn = null }) {
195
+ super({ name: "solomon", config, logger, emitter });
196
+ this._createAgent = createAgentFn || defaultCreateAgent;
197
+ }
198
+
199
+ async execute(input) {
200
+ const conflict = input?.conflict || {};
201
+
202
+ const provider = resolveProvider(this.config);
203
+ const agent = this._createAgent(provider, this.config, this.logger);
204
+
205
+ const prompt = buildPrompt({
206
+ conflict,
207
+ task: this.context?.task || "",
208
+ instructions: this.instructions
209
+ });
210
+
211
+ // KJC-TSK-0413 step C: Solomon es BaseRole (no AgentRole) — wrap explícito.
212
+ const result = await withBrainRecovery({
213
+ agent, taskArgs: { prompt, role: "solomon" }, role: "solomon", provider,
214
+ emitter: this.emitter, logger: this.logger,
215
+ });
216
+
217
+ if (!result.ok) {
218
+ const recoveryNote = result.recovery?.class ? ` [${result.recovery.class}]` : "";
219
+ return {
220
+ ok: false,
221
+ result: {
222
+ error: result.error || result.output || `Solomon arbitration failed${recoveryNote}`,
223
+ provider, recovery: result.recovery, action: result.action,
224
+ },
225
+ summary: `Solomon failed${recoveryNote}: ${result.recovery?.message || result.error || "unknown error"}`
226
+ };
227
+ }
228
+
229
+ try {
230
+ const parsed = parseSolomonOutput(result.output);
231
+ if (!parsed) {
232
+ return {
233
+ ok: false,
234
+ result: { error: "Failed to parse Solomon output: no JSON found", provider },
235
+ summary: "Solomon output parse error: no JSON found"
236
+ };
237
+ }
238
+
239
+ const ruling = parsed.ruling || "approve";
240
+ const escalate = Boolean(parsed.escalate);
241
+ const ok = ruling !== "escalate_human";
242
+
243
+ return {
244
+ ok,
245
+ result: {
246
+ ruling,
247
+ classification: parsed.classification || [],
248
+ conditions: parsed.conditions || [],
249
+ dismissed: parsed.dismissed || [],
250
+ escalate,
251
+ escalate_reason: parsed.escalate_reason || null,
252
+ subtask: parsed.subtask || null,
253
+ provider
254
+ },
255
+ summary: buildSummary(parsed)
256
+ };
257
+ } catch (err) {
258
+ return {
259
+ ok: false,
260
+ result: { error: `Failed to parse Solomon output: ${err.message}`, provider },
261
+ summary: `Solomon output parse error: ${err.message}`
262
+ };
263
+ }
264
+ }
265
+ }
@@ -0,0 +1,70 @@
1
+ import { BaseRole } from "./base-role.js";
2
+ import { runSonarScan } from "../sonar/scanner.js";
3
+ import { getQualityGateStatus, getOpenIssues } from "../sonar/api.js";
4
+ import { shouldBlockByProfile, summarizeIssues } from "../sonar/enforcer.js";
5
+
6
+ function normalizeIssues(rawIssues) {
7
+ return rawIssues.map((issue) => ({
8
+ severity: issue.severity || "UNKNOWN",
9
+ type: issue.type || "UNKNOWN",
10
+ file: issue.component || "",
11
+ line: issue.line || 0,
12
+ rule: issue.rule || "",
13
+ message: issue.message || ""
14
+ }));
15
+ }
16
+
17
+ export class SonarRole extends BaseRole {
18
+ constructor({ config, logger, emitter = null }) {
19
+ super({ name: "sonar", config, logger, emitter });
20
+ }
21
+
22
+ async execute(_input) {
23
+ const scan = await runSonarScan(this.config);
24
+
25
+ if (!scan.ok) {
26
+ return {
27
+ ok: false,
28
+ result: {
29
+ projectKey: scan.projectKey || null,
30
+ gateStatus: null,
31
+ issues: [],
32
+ openIssuesTotal: 0,
33
+ issuesSummary: "",
34
+ blocking: false,
35
+ error: scan.stderr || scan.stdout || "Scan failed"
36
+ },
37
+ summary: `Sonar scan failed: ${scan.stderr || scan.stdout || "unknown error"}`
38
+ };
39
+ }
40
+
41
+ const gate = await getQualityGateStatus(this.config, scan.projectKey);
42
+ const openIssues = await getOpenIssues(this.config, scan.projectKey);
43
+ const issues = normalizeIssues(openIssues.issues || []);
44
+ const issuesSummary = summarizeIssues(openIssues.issues || []);
45
+
46
+ const profile = this.config.sonarqube?.enforcement_profile || "pragmatic";
47
+ const blocking = shouldBlockByProfile({
48
+ gateStatus: gate.status,
49
+ profile
50
+ });
51
+
52
+ return {
53
+ ok: !blocking,
54
+ result: {
55
+ projectKey: scan.projectKey,
56
+ gateStatus: gate.status,
57
+ conditions: gate.conditions || [],
58
+ issues,
59
+ openIssuesTotal: openIssues.total || 0,
60
+ issuesSummary,
61
+ blocking
62
+ },
63
+ summary: (() => {
64
+ const issuesPart = issuesSummary ? ` (${issuesSummary})` : "";
65
+ const blockingPart = blocking ? " [BLOCKING]" : "";
66
+ return `Quality gate: ${gate.status}; Issues: ${openIssues.total || 0}${issuesPart}${blockingPart}`;
67
+ })()
68
+ };
69
+ }
70
+ }
@@ -0,0 +1,106 @@
1
+ // Spec Reviewer role (KJC-PCS-0048 PR 1). Runs BEFORE intent/triage/planner;
2
+ // audits the user's spec and returns structured findings. Does NOT execute.
3
+
4
+ import { AgentRole } from "./agent-role.js";
5
+ import { buildSpecReviewerPrompt, buildSpecRefinerPrompt, VALID_CATEGORIES } from "../prompts/spec-reviewer.js";
6
+ import { extractFirstJson } from "../utils/json-extract.js";
7
+ import { withBrainRecovery } from "../brain/with-brain-recovery.js";
8
+
9
+ const F_SEVS = new Set(["info", "warn", "fail"]);
10
+ const T_SEVS = new Set(["ok", "info", "warn", "fail"]);
11
+ const CATS = new Set(VALID_CATEGORIES);
12
+ const ORDER = { ok: 0, info: 1, warn: 2, fail: 3 };
13
+
14
+ function normalise(findings) {
15
+ if (!Array.isArray(findings)) return [];
16
+ return findings.map((f, i) => ({
17
+ id: typeof f?.id === "string" && f.id.trim() ? f.id.trim() : `F-${String(i + 1).padStart(3, "0")}`,
18
+ severity: F_SEVS.has(f?.severity) ? f.severity : "warn",
19
+ category: CATS.has(f?.category) ? f.category : "ambiguity",
20
+ message: String(f?.message || "").trim() || "(no description)",
21
+ suggestion: typeof f?.suggestion === "string" && f.suggestion.trim() ? f.suggestion.trim() : null,
22
+ }));
23
+ }
24
+
25
+ const worstOf = (findings) => findings.reduce((m, f) => (ORDER[f.severity] > ORDER[m] ? f.severity : m), "ok");
26
+
27
+ export class SpecReviewerRole extends AgentRole {
28
+ constructor(opts) { super({ ...opts, name: "spec-reviewer" }); }
29
+
30
+ extractInput(input) {
31
+ if (typeof input === "string") return { spec: input, onOutput: null };
32
+ return {
33
+ spec: input?.spec || input?.task || this.context?.task || "",
34
+ onOutput: input?.onOutput || null,
35
+ sessionState: input?.sessionState || null,
36
+ };
37
+ }
38
+
39
+ async buildPrompt({ spec }) {
40
+ return { prompt: buildSpecReviewerPrompt({ spec, instructions: this.instructions }) };
41
+ }
42
+
43
+ parseOutput(raw) { return extractFirstJson(raw); }
44
+
45
+ buildSuccessResult(parsed, provider) {
46
+ const findings = normalise(parsed?.findings);
47
+ const declared = T_SEVS.has(parsed?.severity) ? parsed.severity : null;
48
+ const derived = worstOf(findings);
49
+ // Trust the worse of declared vs derived — agents sometimes report
50
+ // `severity: "ok"` while still listing fail-level findings.
51
+ const severity = !declared || ORDER[derived] > ORDER[declared] ? derived : declared;
52
+ return { severity, findings, reasoning: String(parsed?.reasoning || "").trim() || null, provider };
53
+ }
54
+
55
+ buildSummary(parsed) {
56
+ const findings = normalise(parsed?.findings);
57
+ if (findings.length === 0) return "Spec OK (no findings)";
58
+ return `Spec ${worstOf(findings)}: ${findings.length} finding${findings.length === 1 ? "" : "s"}`;
59
+ }
60
+
61
+ // Parse failures degrade to a soft warning so the pipeline never blocks.
62
+ handleParseNull(r, p) { return this.#degraded(r, p, "parse-null", "LLM output was unstructured"); }
63
+ handleParseError(e, r, p) { return this.#degraded(r, p, "parse-error", e?.message || "unknown"); }
64
+
65
+ /**
66
+ * Refine mode (KJC-PCS-0048 PR 3). Bypasses the JSON-only `execute()`
67
+ * flow: returns the LLM output verbatim as the rewritten spec, so the
68
+ * refine loop can persist it as `spec-v2.md`.
69
+ * @returns {Promise<{ ok:boolean, refinedSpec?:string, error?:string, provider:string, usage?:object }>}
70
+ */
71
+ async refineSpec({ spec, findings }) {
72
+ if (!this._initialized) await this.init({ task: spec });
73
+ const provider = this.resolveProvider();
74
+ const agent = this.createAgentInstance(provider);
75
+ const prompt = buildSpecRefinerPrompt({ originalSpec: spec, findings, instructions: this.instructions });
76
+ const result = await withBrainRecovery({
77
+ agent: { runTask: (a) => agent.runTask(a), provider },
78
+ taskArgs: { prompt, role: this.name },
79
+ role: this.name, provider, emitter: this.emitter, logger: this.logger,
80
+ });
81
+ if (!result.ok) {
82
+ return { ok: false, error: result.error || "refine failed", provider, usage: result.usage };
83
+ }
84
+ const refinedSpec = String(result.output || "").replace(/^```[a-z]*\n?|```$/g, "").trim();
85
+ if (!refinedSpec) return { ok: false, error: "empty refined spec", provider, usage: result.usage };
86
+ return { ok: true, refinedSpec, provider, usage: result.usage };
87
+ }
88
+
89
+ #degraded(agentResult, provider, reason, detail) {
90
+ return {
91
+ ok: true,
92
+ result: {
93
+ severity: "warn",
94
+ findings: [{
95
+ id: "F-DEG", severity: "warn", category: "assumptions",
96
+ message: `[spec-reviewer] degraded (${reason}): ${detail}`,
97
+ suggestion: "Re-run with --skip-spec-review if this keeps failing.",
98
+ }],
99
+ reasoning: "Spec reviewer could not parse the LLM output; treating as a soft warning.",
100
+ provider, degraded: true,
101
+ },
102
+ summary: `Spec reviewer degraded: ${reason}`,
103
+ usage: agentResult?.usage,
104
+ };
105
+ }
106
+ }
@@ -0,0 +1,235 @@
1
+ import { AgentRole } from "./agent-role.js";
2
+ import { extractFirstJson } from "../utils/json-extract.js";
3
+ import { detectTestFramework } from "../utils/project-detect.js";
4
+ import { loadAvailableSkills, buildSkillSection } from "../skills/skill-loader.js";
5
+
6
+ const SUBAGENT_PREAMBLE = [
7
+ "IMPORTANT: You are running as a Karajan sub-agent.",
8
+ "Do NOT ask about using Karajan, do NOT mention Karajan, do NOT suggest orchestration.",
9
+ "Do NOT use any MCP tools. Focus only on evaluating test quality."
10
+ ].join(" ");
11
+
12
+ /**
13
+ * Map test framework to the command that runs tests with coverage.
14
+ */
15
+ const COVERAGE_COMMANDS = {
16
+ vitest: "npx vitest run --coverage --reporter=verbose 2>&1",
17
+ jest: "npx jest --coverage --verbose 2>&1",
18
+ mocha: "npx c8 mocha 2>&1",
19
+ playwright: "npx playwright test 2>&1",
20
+ pytest: "pytest --cov --tb=short 2>&1",
21
+ "go-test": "go test -cover -v ./... 2>&1",
22
+ "cargo-test": "cargo test --verbose 2>&1",
23
+ junit: "mvn test 2>&1",
24
+ rspec: "bundle exec rspec 2>&1",
25
+ phpunit: "vendor/bin/phpunit --coverage-text 2>&1",
26
+ "dotnet-test": "dotnet test --collect:\"XPlat Code Coverage\" 2>&1",
27
+ "dart-test": "dart test 2>&1",
28
+ // INF-B: the basic suite ALWAYS runs first; checkov is the additive deep
29
+ // scan. If checkov is missing this chain fails and the brief falls back to
30
+ // the basic suite alone (declared degradation, never green-by-omission).
31
+ "terraform-validate": "terraform init -backend=false -input=false 2>&1 && terraform validate 2>&1 && checkov -d . --compact --quiet 2>&1",
32
+ "helm-lint": "helm lint . 2>&1 && checkov -d . --compact --quiet 2>&1",
33
+ "kustomize-build": "kustomize build . > /dev/null && checkov -d . --compact --quiet 2>&1",
34
+ "ansible-lint": "ansible-lint 2>&1 && checkov -d . --compact --quiet 2>&1"
35
+ };
36
+
37
+ const TEST_COMMANDS = {
38
+ vitest: "npx vitest run --reporter=verbose 2>&1",
39
+ jest: "npx jest --verbose 2>&1",
40
+ mocha: "npx mocha 2>&1",
41
+ playwright: "npx playwright test 2>&1",
42
+ pytest: "pytest --tb=short 2>&1",
43
+ "go-test": "go test -v ./... 2>&1",
44
+ "cargo-test": "cargo test --verbose 2>&1",
45
+ junit: "mvn test 2>&1",
46
+ rspec: "bundle exec rspec 2>&1",
47
+ phpunit: "vendor/bin/phpunit 2>&1",
48
+ "dotnet-test": "dotnet test 2>&1",
49
+ "dart-test": "dart test 2>&1",
50
+ // INF-B (KJC-TSK-0759): infra suites — validity IS the test floor.
51
+ "terraform-validate": "terraform init -backend=false -input=false 2>&1 && terraform validate 2>&1",
52
+ "helm-lint": "helm lint . 2>&1",
53
+ "kustomize-build": "kustomize build . > /dev/null && echo kustomize build: OK",
54
+ "ansible-lint": "ansible-lint 2>&1"
55
+ };
56
+
57
+ export class TesterRole extends AgentRole {
58
+ constructor(opts) {
59
+ super({ ...opts, name: "tester" });
60
+ }
61
+
62
+ extractInput(input) {
63
+ if (typeof input === "string") return { task: input, diff: null, sonarIssues: null, pendingGherkinTests: null, shellTestResults: null };
64
+ return {
65
+ task: input?.task || this.context?.task || "",
66
+ diff: input?.diff || null,
67
+ sonarIssues: input?.sonarIssues || null,
68
+ // Tests-first Phase 3 (v2.7.5): the tester now has two extra inputs.
69
+ // - pendingGherkinTests: HU-declared Gherkin scenarios that need
70
+ // translation into executable code tests in the project's
71
+ // framework. The tester writes the test files and includes them
72
+ // in the suite run before computing verdict.
73
+ // - shellTestResults: results of running the HU's shell-type
74
+ // acceptance_tests (already run upstream, passed at this point).
75
+ // Passed for context so the tester doesn't re-run them redundantly.
76
+ pendingGherkinTests: input?.pendingGherkinTests || null,
77
+ shellTestResults: input?.shellTestResults || null,
78
+ onOutput: input?.onOutput || null
79
+ };
80
+ }
81
+
82
+ async buildPrompt({ task, diff, sonarIssues, pendingGherkinTests, shellTestResults }) {
83
+ const projectDir = this.config?.projectDir || process.cwd();
84
+ const detection = await detectTestFramework(projectDir);
85
+
86
+ const sections = [SUBAGENT_PREAMBLE];
87
+ if (this.instructions) sections.push(this.instructions);
88
+
89
+ sections.push(
90
+ "You are a test quality gate. Your job is to EXECUTE the test suite, measure REAL coverage, and evaluate quality.",
91
+ "You MUST run the actual test command — do NOT guess or estimate results."
92
+ );
93
+
94
+ if (detection.hasTests && detection.framework) {
95
+ const coverageCmd = COVERAGE_COMMANDS[detection.framework];
96
+ const testCmd = TEST_COMMANDS[detection.framework];
97
+ // INF-B: infra suites have no node_modules — the step-0 contract is
98
+ // "the tool exists or you SAY which one is missing", never a fake green.
99
+ const step0 = detection.language === "infra"
100
+ ? "**Step 0**: Verify the SUITE tool is installed (`which terraform`/`helm`/`kustomize`/`ansible-lint`). If the suite tool is MISSING, do NOT fake a green: report it in `failures` with the exact install command and set tests_pass: false. `checkov` (the deep scan below) is OPTIONAL: if it is missing, run the basic suite as the fallback and SAY the deep scan was skipped (degraded, never green-by-omission)."
101
+ : "**Step 0**: If node_modules/ does not exist, run `npm install` (or `pnpm install`) first.";
102
+ sections.push(
103
+ `## Detected test framework: ${detection.framework} (${detection.language})`,
104
+ step0,
105
+ `**Step 1**: Run the test suite with coverage:`,
106
+ "```bash",
107
+ coverageCmd || testCmd,
108
+ "```",
109
+ "If the coverage command fails (missing dependency), fall back to:",
110
+ "```bash",
111
+ testCmd,
112
+ "```",
113
+ "**Step 2**: Parse the output to extract: pass/fail count, coverage percentages, any failures.",
114
+ "**Step 3**: Return a single JSON object with REAL numbers from the test output."
115
+ );
116
+ } else {
117
+ sections.push(
118
+ "## No test framework detected",
119
+ "**Step 0**: If package.json exists but node_modules/ does not, run `npm install` first.",
120
+ "**Step 1**: Look at package.json or project files to find test scripts.",
121
+ "**Step 2**: Try running `npm test` or detect the framework from config files.",
122
+ "**Step 3**: If tests exist, run them. If no tests exist, report tests_pass: false with verdict: 'fail'.",
123
+ "**Step 4**: Return a JSON object with your findings."
124
+ );
125
+ }
126
+
127
+ // Tests-first Phase 3 (v2.7.5): include the upstream shell-test results
128
+ // so the tester knows which part of the contract is already green.
129
+ if (Array.isArray(shellTestResults) && shellTestResults.length > 0) {
130
+ const passedCount = shellTestResults.filter((r) => r.passed).length;
131
+ sections.push(
132
+ "## Acceptance gate — shell tests",
133
+ `The HU's shell-type acceptance_tests already ran upstream: ${passedCount}/${shellTestResults.length} passed.`,
134
+ "Do NOT re-run them. Use the coverage/translation steps below to decide your verdict."
135
+ );
136
+ }
137
+
138
+ // Gherkin translation block — only when the HU carries Gherkin
139
+ // scenarios. Tester must produce real test files (in the detected
140
+ // framework's language) that encode Given/When/Then. This is how
141
+ // behaviour-level specs become enforceable.
142
+ if (Array.isArray(pendingGherkinTests) && pendingGherkinTests.length > 0) {
143
+ sections.push(
144
+ "## Gherkin acceptance tests to translate",
145
+ "These Gherkin scenarios are the HU's behavioural contract. They are NOT yet",
146
+ "executable — your job is to turn each one into a concrete test case in the",
147
+ "project's test framework, WRITE the test files, and INCLUDE them in the suite",
148
+ "run that determines your verdict.",
149
+ "",
150
+ "For each scenario below:",
151
+ "1. Pick the appropriate test file (use `target` hint if present; otherwise",
152
+ " put the test next to the module it exercises).",
153
+ "2. Write a test that asserts the Given/When/Then as-is. Do NOT soften the",
154
+ " assertion — if it's ambiguous, pick the stricter reading.",
155
+ "3. Make sure the test runs as part of the normal suite (no separate invocation).",
156
+ "",
157
+ "If ANY translated test fails on the current code, return verdict: \"fail\" with",
158
+ "a failing_scenarios array listing the scenarios that didn't pass. The coder",
159
+ "will iterate.",
160
+ ""
161
+ );
162
+ pendingGherkinTests.forEach((entry, i) => {
163
+ const content = typeof entry === "string" ? entry : entry?.content || "";
164
+ const target = entry && entry.file ? ` · target: \`${entry.file}\`` : "";
165
+ sections.push(
166
+ `### Scenario ${i + 1}${target}`,
167
+ "```gherkin",
168
+ content,
169
+ "```",
170
+ ""
171
+ );
172
+ });
173
+ }
174
+
175
+ sections.push(
176
+ "",
177
+ "Return ONLY a single valid JSON object:",
178
+ '{"tests_pass":boolean,"coverage":{"overall":number,"services":number,"utilities":number},"missing_scenarios":[string],"quality_issues":[string],"failing_scenarios":[string],"translated_scenarios":[string],"verdict":"pass"|"fail"}',
179
+ "",
180
+ "- coverage.overall MUST be a real number from the test runner output, NOT an estimate",
181
+ "- If coverage tool is not available, set coverage.overall to null (not 0, not a guess)",
182
+ "- tests_pass must reflect whether the actual test run succeeded",
183
+ "- failing_scenarios: when Gherkin was given, list the scenarios your translated tests CAUGHT as failing",
184
+ "- translated_scenarios: when Gherkin was given, list the scenarios you successfully turned into passing tests",
185
+ "- verdict MUST be \"fail\" if any translated scenario still fails (even if coverage is green)",
186
+ `## Task\n${task}`
187
+ );
188
+ if (diff) sections.push(`## Git diff\n${diff}`);
189
+ if (sonarIssues) sections.push(`## Sonar test issues\n${sonarIssues}`);
190
+
191
+ // Inject test-relevant skills (filtered by role=tester to only include
192
+ // testing patterns like pytest-patterns, vitest-patterns, etc.)
193
+ const skills = await loadAvailableSkills(projectDir);
194
+ const skillSection = buildSkillSection(skills, {
195
+ provider: this._resolvedProvider || (typeof this.resolveProvider === "function" ? this.resolveProvider() : null),
196
+ role: "tester",
197
+ });
198
+ if (skillSection) sections.push(skillSection);
199
+
200
+ return { prompt: sections.join("\n\n") };
201
+ }
202
+
203
+ parseOutput(raw) { return extractFirstJson(raw); }
204
+
205
+ isSuccessful(parsed) {
206
+ const verdict = parsed.verdict || (parsed.tests_pass ? "pass" : "fail");
207
+ return verdict === "pass";
208
+ }
209
+
210
+ buildSuccessResult(parsed, provider) {
211
+ const verdict = parsed.verdict || (parsed.tests_pass ? "pass" : "fail");
212
+ return {
213
+ tests_pass: Boolean(parsed.tests_pass),
214
+ coverage: parsed.coverage || {},
215
+ missing_scenarios: parsed.missing_scenarios || [],
216
+ quality_issues: parsed.quality_issues || [],
217
+ // Tests-first Phase 3: Gherkin translation outcomes.
218
+ failing_scenarios: Array.isArray(parsed.failing_scenarios) ? parsed.failing_scenarios : [],
219
+ translated_scenarios: Array.isArray(parsed.translated_scenarios) ? parsed.translated_scenarios : [],
220
+ verdict,
221
+ provider
222
+ };
223
+ }
224
+
225
+ buildSummary(parsed) {
226
+ const verdict = parsed.verdict || (parsed.tests_pass ? "pass" : "fail");
227
+ const coverage = parsed.coverage || {};
228
+ const coverageStr = coverage.overall != null ? `${coverage.overall}%` : "not measured";
229
+ const missingPart = parsed.missing_scenarios?.length ? `; ${parsed.missing_scenarios.length} missing scenario(s)` : "";
230
+ const qualityPart = parsed.quality_issues?.length ? `; ${parsed.quality_issues.length} quality issue(s)` : "";
231
+ const failingPart = parsed.failing_scenarios?.length ? `; ${parsed.failing_scenarios.length} failing scenario(s)` : "";
232
+ const translatedPart = parsed.translated_scenarios?.length ? `; ${parsed.translated_scenarios.length} scenario(s) translated` : "";
233
+ return `Verdict: ${verdict}; Coverage: ${coverageStr}${translatedPart}${failingPart}${missingPart}${qualityPart}`;
234
+ }
235
+ }