@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,236 @@
1
+ /**
2
+ * Plan reviewer — third pass after `kj plan` (PR D of the v2.7.5
3
+ * tests-first roadmap). Asks the planner LLM five concrete
4
+ * questions about the plan it just produced. Returns structured
5
+ * findings, NOT free-form prose.
6
+ *
7
+ * The questions are intentionally closed-ended:
8
+ *
9
+ * 1. **Missing HUs** — sections of the SPEC the plan doesn't cover.
10
+ * (Catches "the planner forgot module X".)
11
+ * 2. **Missing dependencies** — pairs of HUs that should have a
12
+ * `blocked_by` edge but don't.
13
+ * (Catches "HU 4 needs the schema HU 2 produces".)
14
+ * 3. **Scope overlap** — pairs of HUs that touch the same scope.
15
+ * (Catches "the planner split one piece of work into two HUs
16
+ * that step on each other".)
17
+ * 4. **Parallelisable** — sets of HUs that have no inter-deps and
18
+ * could run side-by-side.
19
+ * (Surface for the user, not auto-applied — `kj run --plan`
20
+ * runs serially today.)
21
+ * 5. **Order issues** — HUs whose `blocked_by` chain is wrong or
22
+ * circular.
23
+ *
24
+ * The output is purely advisory. The reviewer NEVER edits the plan.
25
+ * It reports findings; the user decides whether to apply them via
26
+ * the board's edit modal or another `kj plan` pass.
27
+ *
28
+ * Free-form "could we add logging?" suggestions are explicitly out
29
+ * of scope to avoid scope-creep noise — see the prompt rules.
30
+ */
31
+
32
+ import { extractFirstJson } from "../utils/json-extract.js";
33
+ import { withBrainRecovery } from "../brain/with-brain-recovery.js";
34
+
35
+ /**
36
+ * Build the focused review prompt. Exported for unit-testing the
37
+ * shape without an LLM in the loop.
38
+ *
39
+ * @param {object} args
40
+ * @param {string} args.task
41
+ * @param {Array<object>} args.hus
42
+ * @returns {string}
43
+ */
44
+ export function buildReviewerPrompt({ task, hus }) {
45
+ const huSummary = hus.map((h, i) => {
46
+ const deps = Array.isArray(h.blocked_by) && h.blocked_by.length > 0
47
+ ? ` ← blocked_by: ${h.blocked_by.join(", ")}`
48
+ : "";
49
+ const spec = h.spec_section ? ` [§${h.spec_section}]` : "";
50
+ return `${i + 1}. ${h.id}${spec}: ${h.title || "(untitled)"}${deps}\n scope: ${h.scope || "(none)"}`;
51
+ }).join("\n\n");
52
+
53
+ return [
54
+ "You previously generated an implementation plan for the task below.",
55
+ "Your ONLY job in this call is to review it against five specific questions.",
56
+ "DO NOT propose new features, logging, monitoring, refactors, or anything",
57
+ "beyond what the SPEC explicitly requires. We're checking the plan for",
58
+ "completeness and correctness — NOT improving its scope.",
59
+ "",
60
+ "Output MUST be a JSON object with this exact shape:",
61
+ "",
62
+ "```json",
63
+ "{",
64
+ ' "missing_hus": [',
65
+ ' { "spec_section": "<section ref or short description>", "rationale": "<why it should exist>" }',
66
+ " ],",
67
+ ' "missing_dependencies": [',
68
+ ' { "from": "<huId that should depend on>", "on": "<huId>", "rationale": "<why>" }',
69
+ " ],",
70
+ ' "scope_overlaps": [',
71
+ ' { "between": ["<huId>", "<huId>"], "rationale": "<why they overlap>" }',
72
+ " ],",
73
+ ' "parallelisable_groups": [',
74
+ ' { "his": ["<huId>", "<huId>"], "rationale": "<why these can run side-by-side>" }',
75
+ " ],",
76
+ ' "order_issues": [',
77
+ ' { "hus": ["<huId>"], "issue": "<wrong order | circular | other>", "rationale": "<why>" }',
78
+ " ],",
79
+ ' "summary": "<one sentence overall verdict>"',
80
+ "}",
81
+ "```",
82
+ "",
83
+ "Rules:",
84
+ "- Each array can be empty if there's nothing to flag for that question.",
85
+ "- Reference HUs by their EXACT id from the list below.",
86
+ "- Suggest at MOST 5 entries per array — only the most important ones.",
87
+ "- DO NOT propose tests / acceptance criteria — those are handled by other roles.",
88
+ "- DO NOT suggest renames / cosmetic changes — only structural issues.",
89
+ "- Return ONLY the JSON — no prose, no markdown fences around it.",
90
+ "",
91
+ "## Original Task",
92
+ task,
93
+ "",
94
+ "## Plan to review",
95
+ "",
96
+ huSummary,
97
+ "",
98
+ ].join("\n");
99
+ }
100
+
101
+ /**
102
+ * Run the focused review pass.
103
+ *
104
+ * Pure-function side: parses the LLM JSON and normalises the shape
105
+ * (missing arrays default to `[]`, summary defaults to `""`). Junk
106
+ * entries (missing required fields) are dropped silently.
107
+ *
108
+ * @param {object} args
109
+ * @param {object} args.agent
110
+ * @param {string} args.task
111
+ * @param {Array<object>} args.hus
112
+ * @param {Function} [args.onOutput]
113
+ * @param {number} [args.silenceTimeoutMs]
114
+ * @param {number} [args.timeoutMs]
115
+ * @returns {Promise<{ ok: boolean, findings?: object, error?: string }>}
116
+ */
117
+ export async function reviewPlan({ agent, task, hus, onOutput, silenceTimeoutMs, timeoutMs, emitter, eventBase, logger }) {
118
+ if (!Array.isArray(hus) || hus.length === 0) {
119
+ return { ok: true, findings: emptyFindings("Plan has no HUs to review.") };
120
+ }
121
+ const prompt = buildReviewerPrompt({ task, hus });
122
+ const runArgs = { prompt, role: "planner" };
123
+ if (onOutput) runArgs.onOutput = onOutput;
124
+ if (silenceTimeoutMs) runArgs.silenceTimeoutMs = silenceTimeoutMs;
125
+ if (timeoutMs) runArgs.timeoutMs = timeoutMs;
126
+
127
+ // KJC-TSK-0413: el caso real del 2026-05-16 (plan-fix iter 2 "failed
128
+ // 219.3s" sin clase) entraba aquí. Ahora Brain clasifica el fallo y
129
+ // decide retry/standby/hibernate/abort.
130
+ const result = await withBrainRecovery({
131
+ agent, taskArgs: runArgs, role: "plan-reviewer",
132
+ emitter, eventBase, logger,
133
+ });
134
+ if (!result.ok) {
135
+ return { ok: false, error: result.error || `reviewer agent failed (${result.recovery?.class || "unknown"})`, recovery: result.recovery, action: result.action };
136
+ }
137
+ const parsed = extractFirstJson(result.output || "");
138
+ if (!parsed || typeof parsed !== "object") {
139
+ return { ok: false, error: "reviewer returned no JSON object" };
140
+ }
141
+ return { ok: true, findings: normaliseFindings(parsed) };
142
+ }
143
+
144
+ function emptyFindings(summary) {
145
+ return {
146
+ missing_hus: [],
147
+ missing_dependencies: [],
148
+ scope_overlaps: [],
149
+ parallelisable_groups: [],
150
+ order_issues: [],
151
+ summary: summary || "",
152
+ };
153
+ }
154
+
155
+ /**
156
+ * Coerce the raw LLM payload into the canonical shape. Each list is
157
+ * filtered to keep only entries with the required fields populated.
158
+ * @param {object} raw
159
+ */
160
+ function normaliseFindings(raw) {
161
+ const f = emptyFindings(typeof raw.summary === "string" ? raw.summary : "");
162
+ if (Array.isArray(raw.missing_hus)) {
163
+ f.missing_hus = raw.missing_hus
164
+ .filter((m) => m && (m.spec_section || m.section || m.title) && m.rationale)
165
+ .map((m) => ({
166
+ spec_section: String(m.spec_section || m.section || m.title),
167
+ rationale: String(m.rationale),
168
+ }));
169
+ }
170
+ if (Array.isArray(raw.missing_dependencies)) {
171
+ f.missing_dependencies = raw.missing_dependencies
172
+ .filter((d) => d && d.from && d.on && d.rationale)
173
+ .map((d) => ({ from: String(d.from), on: String(d.on), rationale: String(d.rationale) }));
174
+ }
175
+ if (Array.isArray(raw.scope_overlaps)) {
176
+ f.scope_overlaps = raw.scope_overlaps
177
+ .filter((o) => o && Array.isArray(o.between) && o.between.length >= 2 && o.rationale)
178
+ .map((o) => ({ between: o.between.map(String), rationale: String(o.rationale) }));
179
+ }
180
+ if (Array.isArray(raw.parallelisable_groups)) {
181
+ f.parallelisable_groups = raw.parallelisable_groups
182
+ .filter((g) => g && Array.isArray(g.hus) && g.hus.length >= 2)
183
+ .map((g) => ({ hus: g.hus.map(String), rationale: g.rationale ? String(g.rationale) : "" }));
184
+ }
185
+ if (Array.isArray(raw.order_issues)) {
186
+ f.order_issues = raw.order_issues
187
+ .filter((o) => o && Array.isArray(o.hus) && o.hus.length >= 1 && o.issue)
188
+ .map((o) => ({ hus: o.hus.map(String), issue: String(o.issue), rationale: o.rationale ? String(o.rationale) : "" }));
189
+ }
190
+ return f;
191
+ }
192
+
193
+ /**
194
+ * Flatten findings into a count of actionable items (for the CLI
195
+ * banner: "Reviewer found 3 issues.").
196
+ */
197
+ export function findingsCount(findings) {
198
+ if (!findings) return 0;
199
+ return (
200
+ (findings.missing_hus?.length || 0)
201
+ + (findings.missing_dependencies?.length || 0)
202
+ + (findings.scope_overlaps?.length || 0)
203
+ + (findings.order_issues?.length || 0)
204
+ // parallelisable_groups is informational, not an issue.
205
+ );
206
+ }
207
+
208
+ /**
209
+ * KJC-BUG-0054: count findings categorised por prioridad, para que
210
+ * el self-fix convergence guard pueda distinguir "regresión genuina"
211
+ * de "regresión por arreglar algo importante".
212
+ *
213
+ * Categorías:
214
+ * - priority: ciclos (order_issues con issue=='circular') + missing_hus.
215
+ * Estos NO pueden ignorarse — un ciclo deja el plan no ejecutable;
216
+ * una HU faltante es feature missing.
217
+ * - secondary: missing_dependencies + scope_overlaps + order_issues
218
+ * no-circulares. Importantes pero recuperables.
219
+ *
220
+ * @param {object} findings
221
+ * @returns {{ priority: number, secondary: number, total: number, cycles: number }}
222
+ */
223
+ export function findingsCountByType(findings) {
224
+ if (!findings) return { priority: 0, secondary: 0, total: 0, cycles: 0 };
225
+ const orderIssues = findings.order_issues || [];
226
+ const cycles = orderIssues.filter(
227
+ (i) => i && typeof i === "object" && i.issue === "circular"
228
+ ).length;
229
+ const orderNonCircular = orderIssues.length - cycles;
230
+ const missingHus = findings.missing_hus?.length || 0;
231
+ const missingDeps = findings.missing_dependencies?.length || 0;
232
+ const overlaps = findings.scope_overlaps?.length || 0;
233
+ const priority = cycles + missingHus;
234
+ const secondary = missingDeps + overlaps + orderNonCircular;
235
+ return { priority, secondary, total: priority + secondary, cycles };
236
+ }
@@ -0,0 +1,334 @@
1
+ /**
2
+ * Plan v2 schema: plans with embedded HUs.
3
+ * v1 = text-only plans (approach + steps + risks)
4
+ * v2 = plans + executable HUs with acceptance tests
5
+ */
6
+
7
+ import { generatePlanId } from "./plan-id.js";
8
+
9
+ const VALID_PLAN_STATUSES = new Set(["draft", "ready", "running", "done", "failed"]);
10
+ // KJC-TSK-0394 step 5: el modelo CANONICAL del lifecycle es
11
+ // {pending, running, done}. Los valores certified/coding/reviewing/
12
+ // failed/blocked/needs_context se mantienen como LEGACY (siguen
13
+ // aceptados por validatePlan para no romper plans existentes ni el
14
+ // runtime actual). El cleanup definitivo del runtime queda como
15
+ // follow-up; mientras tanto la UI puede usar canonicalStatus +
16
+ // effectiveResult para presentar el modelo de 3 estados sin tocar
17
+ // la persistencia.
18
+ //
19
+ // needs_context se PATCHeaba vía /api/stories/:id (dropdown libre del
20
+ // modal) sin que el enum lo aceptara → `kj plan validate` daba
21
+ // false-negative tras un set manual. Incluido aquí para alinear.
22
+ const VALID_HU_STATUSES = new Set([
23
+ // Canonical
24
+ "pending", "running", "done",
25
+ // Legacy
26
+ "certified", "coding", "reviewing", "failed", "blocked", "needs_context",
27
+ ]);
28
+ export const CANONICAL_HU_STATUSES = new Set(["pending", "running", "done"]);
29
+ // KJC-TSK-0394: nuevo campo `result` ortogonal a status. Reemplaza la
30
+ // sobrecarga semántica del status (certified=pass, failed=fail) por una
31
+ // distinción explícita entre lifecycle (status) y último resultado (result).
32
+ // Vacío `null` significa "nunca ejecutado". Migración no-breaking: status
33
+ // legacy sigue válido durante el período de transición.
34
+ // Nota: usamos `result` y NO `outcome` porque el campo `outcome` ya existe
35
+ // con otra semántica (blob JSON con iterations/duration/commits del run).
36
+ export const VALID_HU_RESULTS = new Set([null, "pass", "fail", "partial"]);
37
+ const VALID_TASK_TYPES = new Set(["sw", "infra", "doc", "add-tests", "refactor", "nocode"]);
38
+ const VALID_TEST_TYPES = new Set(["shell", "gherkin"]);
39
+
40
+ /**
41
+ * KJC-TSK-0394 step 4: deduce `result` de un HU legacy. Idempotente.
42
+ * Heurística: done→pass (si hubiera fallado estaría en failed),
43
+ * failed→fail, resto→null. NO toca status (eso es step 5).
44
+ */
45
+ export function inferResultFromLegacyStatus(hu) {
46
+ if (hu && hu.result != null) return hu.result;
47
+ if (hu?.status === "done") return "pass";
48
+ if (hu?.status === "failed") return "fail";
49
+ return null;
50
+ }
51
+
52
+ /**
53
+ * KJC-TSK-0394 step 5: mapea cualquier status (legacy o canonical) al
54
+ * modelo CANONICAL {pending, running, done}. Permite que la UI y los
55
+ * agregados (counts, kanban columns) trabajen contra un enum pequeño
56
+ * sin tener que conocer todas las variantes legacy.
57
+ *
58
+ * certified | blocked | needs_context | pending → pending
59
+ * coding | reviewing | running → running
60
+ * done | failed → done
61
+ *
62
+ * `failed` mapea a `done` porque conceptualmente es lifecycle terminal
63
+ * — el "falló" lo lleva el campo `result` ortogonal (step 1). Lo mismo
64
+ * para `certified`: no es un lifecycle, es "ready to run" que en el
65
+ * modelo canónico vive como `pending` + acceptance_tests no vacío.
66
+ */
67
+ export function canonicalStatus(status) {
68
+ switch (status) {
69
+ case "running":
70
+ case "coding":
71
+ case "reviewing":
72
+ return "running";
73
+ case "done":
74
+ case "failed":
75
+ return "done";
76
+ default:
77
+ return "pending";
78
+ }
79
+ }
80
+
81
+ /**
82
+ * KJC-TSK-0394 step 5: result "efectivo" para la UI. Si el HU tiene
83
+ * `result` poblado (plans migrados), lo usa directamente. Si no
84
+ * (plans legacy pre-migración), lo deduce del status — equivalente a
85
+ * inferResultFromLegacyStatus pero llamable directamente sobre cada
86
+ * HU al renderizar.
87
+ *
88
+ * Permite a la UI mostrar badges ✓/✗ en plans antiguos sin esperar a
89
+ * que el usuario corra `kj plan migrate-result`.
90
+ */
91
+ export function effectiveResult(hu) {
92
+ if (!hu) return null;
93
+ if (hu.result !== undefined && hu.result !== null) return hu.result;
94
+ return inferResultFromLegacyStatus(hu);
95
+ }
96
+
97
+ /**
98
+ * Map a legacy status to (newStatus, result) pair. Used by addHu() defaults
99
+ * and by the migration script in step 4. Idempotent: re-mapping a value that
100
+ * is already in the canonical {pending, running, done} set keeps it.
101
+ *
102
+ * @param {string|null|undefined} legacy
103
+ * @returns {{ status: string, result: string|null }}
104
+ */
105
+ export function mapLegacyStatusToResult(legacy) {
106
+ switch (legacy) {
107
+ case "pending":
108
+ case "blocked": // blocked es lifecycle no terminal → pending
109
+ case "needs_context": // ídem
110
+ case undefined:
111
+ case null:
112
+ return { status: "pending", result: null };
113
+ case "coding":
114
+ case "reviewing":
115
+ case "running":
116
+ return { status: "running", result: null };
117
+ case "certified":
118
+ return { status: "done", result: "pass" };
119
+ case "failed":
120
+ // KJC-TSK-0403: HU fallida vuelve a Pending con result=fail
121
+ // (no a Done) para que el usuario pueda relanzarla con el
122
+ // contexto del fallo previo (KJC-TSK-0404).
123
+ return { status: "pending", result: "fail" };
124
+ case "done":
125
+ return { status: "done", result: null }; // sin result conocido (raro)
126
+ default:
127
+ return { status: "pending", result: null };
128
+ }
129
+ }
130
+
131
+ /**
132
+ * Structured acceptance-test shape introduced in v2.7.5 (tests-first):
133
+ *
134
+ * { type: "shell", content: "<bash command>", file?: "<optional path>" }
135
+ * { type: "gherkin", content: "Given …\nWhen …\nThen …", file?: "<optional path>" }
136
+ *
137
+ * Legacy entries (plain strings) are accepted by validatePlan and get
138
+ * normalised to `{ type: "shell", content: <string> }` at read time by
139
+ * `normaliseAcceptanceTest`. New plans MUST emit the structured form.
140
+ *
141
+ * Why two types: shell tests are executable as-is (a bash command that
142
+ * exits 0 on pass); gherkin tests are human-readable specs that the
143
+ * tester role translates into real code tests during `kj run` — they
144
+ * are the contract the coder is expected to satisfy.
145
+ *
146
+ * @param {unknown} entry
147
+ * @returns {{ type: string, content: string, file?: string } | null}
148
+ */
149
+ export function normaliseAcceptanceTest(entry) {
150
+ if (entry == null) return null;
151
+ if (typeof entry === "string") {
152
+ const trimmed = entry.trim();
153
+ if (!trimmed) return null;
154
+ return { type: "shell", content: trimmed };
155
+ }
156
+ if (typeof entry === "object" && typeof entry.content === "string") {
157
+ const content = entry.content.trim();
158
+ if (!content) return null;
159
+ const type = VALID_TEST_TYPES.has(entry.type) ? entry.type : "shell";
160
+ const out = { type, content };
161
+ if (typeof entry.file === "string" && entry.file.trim()) out.file = entry.file.trim();
162
+ return out;
163
+ }
164
+ return null;
165
+ }
166
+
167
+ /**
168
+ * Normalise an array of raw acceptance_tests, dropping empties.
169
+ * @param {unknown[]} list
170
+ * @returns {{ type: string, content: string, file?: string }[]}
171
+ */
172
+ export function normaliseAcceptanceTests(list) {
173
+ if (!Array.isArray(list)) return [];
174
+ return list.map(normaliseAcceptanceTest).filter(Boolean);
175
+ }
176
+
177
+ /**
178
+ * Check if a plan uses v2 schema (has version field + hus array).
179
+ */
180
+ export function isPlanV2(plan) {
181
+ return plan?.version === 2 && Array.isArray(plan.hus);
182
+ }
183
+
184
+ /**
185
+ * Create an empty v2 plan.
186
+ * @param {string} task - original task description
187
+ * @param {object} [context] - research/architect/triage context
188
+ * @returns {object} v2 plan with empty hus array
189
+ */
190
+ export function createPlanV2(task, context = {}) {
191
+ const planId = generatePlanId();
192
+ return {
193
+ planId,
194
+ // KJC-TSK humanización IDs: alias legible (ej "greta-app"). Se
195
+ // asigna en savePlan a partir de plan.name. El planId sigue
196
+ // siendo la ID canónica interna (timestamp+random), pero la CLI
197
+ // y el board prefieren el alias para mostrar y aceptan ambos
198
+ // como referencia (--plan greta-app o --plan plan-XXX-XX).
199
+ alias: null,
200
+ version: 2,
201
+ task,
202
+ name: null, // set by caller via deriveProjectName or manually
203
+ status: "draft",
204
+ createdAt: new Date().toISOString(),
205
+ updatedAt: new Date().toISOString(),
206
+ createdBy: "planner",
207
+ context: {
208
+ researchContext: context.researchContext || null,
209
+ architectContext: context.architectContext || null,
210
+ triageLevel: context.triageLevel || null,
211
+ domain: context.domain || null
212
+ },
213
+ approach: null,
214
+ risks: [],
215
+ outOfScope: [],
216
+ hus: []
217
+ };
218
+ }
219
+
220
+ /**
221
+ * Migrate a v1 plan to v2 schema. Preserves all existing data.
222
+ * v1 plans have no HUs — they become v2 with empty hus array.
223
+ * @param {object} v1plan
224
+ * @returns {object} v2 plan
225
+ */
226
+ export function migratePlanV1toV2(v1plan) {
227
+ if (isPlanV2(v1plan)) return v1plan; // already v2
228
+ return {
229
+ planId: v1plan.planId,
230
+ version: 2,
231
+ task: v1plan.task || null,
232
+ name: null,
233
+ status: "draft",
234
+ createdAt: v1plan.createdAt || new Date().toISOString(),
235
+ updatedAt: new Date().toISOString(),
236
+ createdBy: "migrated",
237
+ context: {
238
+ researchContext: v1plan.researchContext || null,
239
+ architectContext: v1plan.architectContext || null,
240
+ triageLevel: null,
241
+ domain: null
242
+ },
243
+ approach: v1plan.plan?.approach || (typeof v1plan.plan === "string" ? v1plan.plan : null),
244
+ risks: v1plan.plan?.risks || [],
245
+ outOfScope: v1plan.plan?.outOfScope || [],
246
+ hus: [],
247
+ _v1: { raw: v1plan.raw, plan: v1plan.plan } // preserve original for reference
248
+ };
249
+ }
250
+
251
+ /**
252
+ * Validate a v2 plan. Returns { valid: true } or { valid: false, errors: string[] }.
253
+ */
254
+ export function validatePlan(plan) {
255
+ const errors = [];
256
+
257
+ if (!plan.planId) errors.push("Missing planId");
258
+ if (plan.version !== 2) errors.push(`Expected version 2, got ${plan.version}`);
259
+ if (!plan.task) errors.push("Missing task");
260
+ if (!VALID_PLAN_STATUSES.has(plan.status)) errors.push(`Invalid status: ${plan.status}`);
261
+ if (!Array.isArray(plan.hus)) errors.push("hus must be an array");
262
+
263
+ const huIds = new Set();
264
+ for (const hu of plan.hus || []) {
265
+ if (!hu.id) { errors.push("HU missing id"); continue; }
266
+ if (huIds.has(hu.id)) errors.push(`Duplicate HU id: ${hu.id}`);
267
+ huIds.add(hu.id);
268
+ if (!hu.title) errors.push(`HU ${hu.id}: missing title`);
269
+ if (!VALID_HU_STATUSES.has(hu.status)) errors.push(`HU ${hu.id}: invalid status ${hu.status}`);
270
+ // KJC-TSK-0394: result es opcional. Si está presente, debe ser pass/fail/partial.
271
+ if (hu.result !== undefined && hu.result !== null && !VALID_HU_RESULTS.has(hu.result)) {
272
+ errors.push(`HU ${hu.id}: invalid result ${hu.result} (expected pass|fail|partial|null)`);
273
+ }
274
+ if (hu.task_type && !VALID_TASK_TYPES.has(hu.task_type)) errors.push(`HU ${hu.id}: invalid task_type ${hu.task_type}`);
275
+ // acceptance_tests: may be absent (legacy) or an array of either
276
+ // plain strings (legacy shell) or { type, content, file? } objects.
277
+ if (hu.acceptance_tests !== undefined) {
278
+ if (!Array.isArray(hu.acceptance_tests)) {
279
+ errors.push(`HU ${hu.id}: acceptance_tests must be an array`);
280
+ } else {
281
+ hu.acceptance_tests.forEach((entry, idx) => {
282
+ if (typeof entry === "string") return; // legacy form — OK
283
+ if (!entry || typeof entry !== "object") {
284
+ errors.push(`HU ${hu.id}: acceptance_tests[${idx}] must be a string or { type, content } object`);
285
+ return;
286
+ }
287
+ if (entry.type && !VALID_TEST_TYPES.has(entry.type)) {
288
+ errors.push(`HU ${hu.id}: acceptance_tests[${idx}].type must be one of ${[...VALID_TEST_TYPES].join("|")}`);
289
+ }
290
+ if (typeof entry.content !== "string" || !entry.content.trim()) {
291
+ errors.push(`HU ${hu.id}: acceptance_tests[${idx}].content must be a non-empty string`);
292
+ }
293
+ });
294
+ }
295
+ }
296
+ // Check blocked_by references exist
297
+ for (const dep of hu.blocked_by || []) {
298
+ if (!huIds.has(dep) && !(plan.hus || []).some(h => h.id === dep)) {
299
+ errors.push(`HU ${hu.id}: blocked_by references unknown HU ${dep}`);
300
+ }
301
+ }
302
+ }
303
+
304
+ // Check for circular dependencies
305
+ try {
306
+ topoSort(plan.hus || []);
307
+ } catch {
308
+ errors.push("Circular dependency detected in HU blocked_by graph");
309
+ }
310
+
311
+ return errors.length === 0 ? { valid: true } : { valid: false, errors };
312
+ }
313
+
314
+ /** Simple topological sort for cycle detection. */
315
+ function topoSort(hus) {
316
+ const visited = new Set();
317
+ const visiting = new Set();
318
+ const order = [];
319
+ const map = new Map(hus.map(h => [h.id, h]));
320
+
321
+ function visit(id) {
322
+ if (visited.has(id)) return;
323
+ if (visiting.has(id)) throw new Error("cycle");
324
+ visiting.add(id);
325
+ const hu = map.get(id);
326
+ for (const dep of hu?.blocked_by || []) visit(dep);
327
+ visiting.delete(id);
328
+ visited.add(id);
329
+ order.push(id);
330
+ }
331
+
332
+ for (const hu of hus) visit(hu.id);
333
+ return order;
334
+ }