@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,279 @@
1
+ import { runCommand } from "./process.js";
2
+ import { getRunContext } from "./run-context.js";
3
+
4
+ /**
5
+ * Module-scoped runner — legacy back-compat for callers outside a
6
+ * `withRunContext` scope (CLI bootstrap, checks/system.js). When running
7
+ * inside a pipeline, `getRunContext()?.runner` takes precedence and
8
+ * provides per-run isolation (TSK-0338). When neither is set we fall
9
+ * back to the bare `runCommand`.
10
+ *
11
+ * @type {((command: string, args?: string[], options?: object) => Promise<object>)|null}
12
+ */
13
+ let _runner = null;
14
+
15
+ /**
16
+ * Set the module-scope runner. Retained for back-compat: concurrent
17
+ * `runFlow` invocations should rely on `withRunContext` for isolation,
18
+ * not on this setter (the setter is process-wide and would cause the
19
+ * exact cross-run contamination TSK-0338 eliminates).
20
+ */
21
+ export function setRunner(runner) {
22
+ _runner = runner;
23
+ }
24
+
25
+ function run(command, args, ...rest) {
26
+ const ctxRunner = getRunContext()?.runner;
27
+ return (ctxRunner || _runner || runCommand)(command, args, ...rest);
28
+ }
29
+
30
+ function slugifyTask(task) {
31
+ return String(task)
32
+ .toLowerCase()
33
+ .replaceAll(/[^a-z0-9]+/g, "-")
34
+ .replaceAll(/(^-+)|(-+$)/g, "")
35
+ .slice(0, 40);
36
+ }
37
+
38
+ async function runGit(args, options = {}) {
39
+ const res = await run("git", args, options);
40
+ if (res.exitCode !== 0) {
41
+ throw new Error(`git ${args.join(" ")} failed: ${res.stderr || res.stdout}`);
42
+ }
43
+ return res.stdout.trim();
44
+ }
45
+
46
+ export async function ensureGitRepo() {
47
+ const res = await run("git", ["rev-parse", "--is-inside-work-tree"]);
48
+ return res.exitCode === 0 && res.stdout.trim() === "true";
49
+ }
50
+
51
+ export async function currentBranch() {
52
+ return runGit(["rev-parse", "--abbrev-ref", "HEAD"]);
53
+ }
54
+
55
+ export async function hasCommits() {
56
+ const res = await run("git", ["rev-parse", "HEAD"]);
57
+ return res.exitCode === 0;
58
+ }
59
+
60
+ export async function fetchBase(baseBranch) {
61
+ await runGit(["fetch", "origin", baseBranch]);
62
+ }
63
+
64
+ export async function revParse(ref) {
65
+ return runGit(["rev-parse", ref]);
66
+ }
67
+
68
+ /**
69
+ * List commits in the range `fromSha..toRef`. Used by the post-loop
70
+ * journal builder to enumerate every commit produced during a `kj run`
71
+ * — both the coder's own commits AND the post-loop scaffold commit —
72
+ * so the user-visible summary doesn't lose track of them. Pre-fix the
73
+ * summary only listed `gitResult.commits` (post-loop only), which made
74
+ * `kj run "..."` runs look like the coder hadn't committed.
75
+ *
76
+ * Returns oldest-first so the list reads in execution order.
77
+ *
78
+ * @param {string|null|undefined} fromSha The SHA right BEFORE the run started
79
+ * (typically `session.session_start_sha`). Empty/missing → returns [].
80
+ * @param {string} [toRef="HEAD"]
81
+ * @returns {Promise<Array<{hash: string, message: string}>>}
82
+ */
83
+ /**
84
+ * List the file paths changed in the range `fromSha..toRef`. Used by the
85
+ * plan-adherence metric (KJC-TSK-0376) to score whether the coder's
86
+ * file changes fall within any HU's declared scope.
87
+ *
88
+ * Returns a deduplicated array of file paths, oldest commit's files
89
+ * first. Defensive: returns [] on missing `fromSha`, non-zero git exit,
90
+ * or thrown error — consistent with `listCommitsBetween`'s contract.
91
+ *
92
+ * @param {string|null|undefined} fromSha
93
+ * @param {string} [toRef="HEAD"]
94
+ * @returns {Promise<string[]>}
95
+ */
96
+ export async function listFilesChangedSince(fromSha, toRef = "HEAD") {
97
+ if (!fromSha) return [];
98
+ const result = await run(
99
+ "git",
100
+ ["diff", "--name-only", `${fromSha}..${toRef}`],
101
+ ).catch(() => null);
102
+ if (!result || result.exitCode !== 0) return [];
103
+ const lines = String(result.stdout || "")
104
+ .split("\n")
105
+ .map((line) => line.trim())
106
+ .filter(Boolean);
107
+ return Array.from(new Set(lines));
108
+ }
109
+
110
+ export async function listCommitsBetween(fromSha, toRef = "HEAD") {
111
+ if (!fromSha) return [];
112
+ const result = await run(
113
+ "git",
114
+ ["log", "--reverse", "--format=%H%x09%s", `${fromSha}..${toRef}`],
115
+ ).catch(() => null);
116
+ if (!result || result.exitCode !== 0) return [];
117
+ return String(result.stdout || "")
118
+ .split("\n")
119
+ .map((line) => line.trimEnd())
120
+ .filter(Boolean)
121
+ .map((line) => {
122
+ const tabIdx = line.indexOf("\t");
123
+ // Defensive: if git emitted no tab (shouldn't happen with our format)
124
+ // treat the whole line as the hash and leave the message empty rather
125
+ // than throw — caller can still render the row.
126
+ if (tabIdx === -1) return { hash: line, message: "" };
127
+ return { hash: line.slice(0, tabIdx), message: line.slice(tabIdx + 1) };
128
+ });
129
+ }
130
+
131
+ export async function syncBaseBranch({ baseBranch, autoRebase }) {
132
+ const local = await revParse(baseBranch);
133
+ const remote = await revParse(`origin/${baseBranch}`);
134
+ if (local === remote) return { synced: true, rebased: false };
135
+
136
+ if (!autoRebase) {
137
+ throw new Error(
138
+ `Base branch '${baseBranch}' is behind origin/${baseBranch}. Re-run with auto-rebase enabled or rebase manually.`
139
+ );
140
+ }
141
+
142
+ await runGit(["rebase", `origin/${baseBranch}`]);
143
+ return { synced: true, rebased: true };
144
+ }
145
+
146
+ export async function ensureBranchUpToDateWithBase({ branch, baseBranch, autoRebase }) {
147
+ const mergeBase = await runGit(["merge-base", branch, `origin/${baseBranch}`]);
148
+ const remoteBase = await revParse(`origin/${baseBranch}`);
149
+ if (mergeBase === remoteBase) return { upToDate: true, rebased: false };
150
+
151
+ if (!autoRebase) {
152
+ throw new Error(
153
+ `Base branch '${baseBranch}' advanced during run. Re-run with auto-rebase enabled or rebase '${branch}' manually.`
154
+ );
155
+ }
156
+
157
+ await runGit(["rebase", `origin/${baseBranch}`]);
158
+ return { upToDate: true, rebased: true };
159
+ }
160
+
161
+ export async function createBranch(branchName) {
162
+ await runGit(["checkout", "-b", branchName]);
163
+ }
164
+
165
+ export function buildBranchName(prefix, task) {
166
+ const stamp = new Date().toISOString().replaceAll(/[:.]/g, "-").slice(0, 16);
167
+ return `${prefix}${slugifyTask(task) || "task"}-${stamp}`;
168
+ }
169
+
170
+ export async function hasChanges(cwd = null) {
171
+ const status = await runGit(["status", "--porcelain"], cwd ? { cwd } : {});
172
+ return status.length > 0;
173
+ }
174
+
175
+ /**
176
+ * Return the relative paths of every uncommitted change (modified,
177
+ * untracked, staged, etc.) in the working tree. Each path is the
178
+ * filename as `git status --porcelain` reports it (after the 2-char
179
+ * status code + space). Returns an empty array when the tree is clean.
180
+ *
181
+ * Used by `finalizeGitAutomation` to decide whether the changes
182
+ * pending at the end of a pipeline are exclusively Karajan
183
+ * scaffolding (and thus deserve a `chore:` commit message instead
184
+ * of inheriting the user task's `feat:`).
185
+ *
186
+ * NOTE: bypasses `runGit()` because that helper trims stdout, which
187
+ * eats the leading space of porcelain lines whose first status char
188
+ * is " " (e.g. " M .gitignore" → "M .gitignore"). The leading space
189
+ * is structural here — without it the slice(3) below would crop one
190
+ * character off the first path.
191
+ */
192
+ export async function listPendingPaths() {
193
+ const res = await run("git", ["status", "--porcelain"]);
194
+ if (res.exitCode !== 0) {
195
+ throw new Error(`git status --porcelain failed: ${res.stderr || res.stdout}`);
196
+ }
197
+ const stdout = res.stdout;
198
+ if (!stdout) return [];
199
+ const lines = stdout.split("\n").map((l) => l.replace(/\r$/, "")).filter(Boolean);
200
+ const out = [];
201
+ for (const line of lines) {
202
+ // Each line is "XY <path>" (XY = 2-char status, space, path).
203
+ // Renames look like "R old -> new"; we want the new path.
204
+ const after = line.slice(3);
205
+ const arrow = after.indexOf(" -> ");
206
+ out.push(arrow !== -1 ? after.slice(arrow + 4) : after);
207
+ }
208
+ return out;
209
+ }
210
+
211
+ // Locale-tolerant detection of "git commit refused because the working
212
+ // tree was already clean by the time we ran it". Observed in N4
213
+ // dogfooding (2026-05-07) — `hasChanges()` reported true after `add -A`
214
+ // but `git commit` then failed with the Spanish message "nada para hacer
215
+ // commit, el árbol de trabajo está limpio". The race window is real:
216
+ // post-loop journal writes can finish between hasChanges and commit, and
217
+ // some files come back from `add -A` with no diff vs HEAD even though
218
+ // they show up in `git status --porcelain`. We treat any of those as
219
+ // "no commit needed" rather than escalating to Solomon.
220
+ const NOTHING_TO_COMMIT_PATTERNS = [
221
+ /nothing to commit/i,
222
+ /nada para hacer commit/i, // git in es_ES locale
223
+ /no hay nada para confirmar/i, // git in es_ES alt phrasing
224
+ /aucune modification ajout[ée]e au commit/i, // fr_FR
225
+ /nichts zu committen/i, // de_DE
226
+ ];
227
+ function isNothingToCommit(message) {
228
+ const m = String(message || "");
229
+ return NOTHING_TO_COMMIT_PATTERNS.some((re) => re.test(m));
230
+ }
231
+
232
+ export async function commitAll(message, cwd = null, { beforeCommit = null } = {}) {
233
+ const opts = cwd ? { cwd } : {};
234
+ await runGit(["add", "-A"], opts);
235
+ const changed = await hasChanges(cwd);
236
+ if (!changed) return { committed: false };
237
+ // ENV-F1 (KJC-TSK-0643): runs between staging and committing — the only
238
+ // window where the staged diff is exactly what the commit will contain
239
+ // (used to stamp the pipeline's review verdict for the v4 gate).
240
+ if (beforeCommit) await beforeCommit();
241
+ try {
242
+ await runGit(["commit", "-m", message], opts);
243
+ } catch (err) {
244
+ // `git status --porcelain` and `git commit` disagreed about whether
245
+ // there was anything to commit. Don't escalate — the only outcome
246
+ // either way is "no new commit was created", which the caller
247
+ // already handles via committed=false.
248
+ if (isNothingToCommit(err?.message)) {
249
+ return { committed: false };
250
+ }
251
+ throw err;
252
+ }
253
+ const raw = await runGit(["log", "-1", "--pretty=format:%H%x1f%s"], opts);
254
+ const [hash, commitMessage] = raw.split("\x1f");
255
+ return { committed: true, commit: { hash, message: commitMessage } };
256
+ }
257
+
258
+ /**
259
+ * KJC-BUG-0112: whether the repo has an `origin` remote. The quickstart
260
+ * scenario (fresh folder + git init) has none — post-approval push/PR
261
+ * automation must skip instead of failing and escalating to Solomon.
262
+ */
263
+ export async function hasRemote(cwd = null) {
264
+ const res = await run("git", ["remote", "get-url", "origin"], cwd ? { cwd } : {});
265
+ return res.exitCode === 0;
266
+ }
267
+
268
+ export async function pushBranch(branch, cwd = null) {
269
+ await runGit(["push", "-u", "origin", branch], cwd ? { cwd } : {});
270
+ }
271
+
272
+ export async function createPullRequest({ baseBranch, branch, title, body, cwd = null }) {
273
+ const args = ["pr", "create", "--base", baseBranch, "--head", branch, "--title", title, "--body", body];
274
+ const res = await runCommand("gh", args, cwd ? { cwd } : {});
275
+ if (res.exitCode !== 0) {
276
+ throw new Error(`gh ${args.join(" ")} failed: ${res.stderr || res.stdout}`);
277
+ }
278
+ return res.stdout.trim();
279
+ }
@@ -0,0 +1,87 @@
1
+ // One-shot ~/.kj/ → ~/.karajan/ home consolidation (PR 2 of KJC-PCS-0047).
2
+ // Idempotent via `<target>/.kj-migrated.json`. Tarball backup under
3
+ // `<target>/backup/`. `plans/`, `standby/`, `worktrees/` are moved
4
+ // wholesale; `runs/` is merged with `.karajan/` winning on conflict.
5
+ // Cross-device safe. Non-fatal: CLI bootstrap wraps in try/catch.
6
+
7
+ import fs from "node:fs/promises";
8
+ import path from "node:path";
9
+ import os from "node:os";
10
+ import { execa } from "execa";
11
+
12
+ const MARKER = ".kj-migrated.json";
13
+ const MOVE_DIRS = ["plans", "standby", "worktrees"];
14
+
15
+ async function readdirOrNull(dir) {
16
+ try { return await fs.readdir(dir); } catch (err) {
17
+ if (err.code === "ENOENT") return null;
18
+ throw err;
19
+ }
20
+ }
21
+
22
+ async function moveChildren(src, dst, { mergeMode = false } = {}) {
23
+ const children = await readdirOrNull(src);
24
+ if (!children?.length) return 0;
25
+ await fs.mkdir(dst, { recursive: true });
26
+ let n = 0;
27
+ for (const c of children) {
28
+ const dstChild = path.join(dst, c);
29
+ if (mergeMode) {
30
+ try { await fs.access(dstChild); continue; } catch { /* no conflict */ }
31
+ }
32
+ const srcChild = path.join(src, c);
33
+ try { await fs.rename(srcChild, dstChild); } catch (err) {
34
+ if (err.code !== "EXDEV") throw err;
35
+ await fs.cp(srcChild, dstChild, { recursive: true });
36
+ await fs.rm(srcChild, { recursive: true, force: true });
37
+ }
38
+ n += 1;
39
+ }
40
+ await fs.rm(src, { recursive: true, force: true }).catch(() => {});
41
+ return n;
42
+ }
43
+
44
+ export async function migrateKjToKarajan({ dryRun = false, force = false } = {}) {
45
+ // VITEST guard — tests setting KJ_HOME would otherwise migrate against
46
+ // the developer's real HOME. Migrator's own tests pass `force: true`.
47
+ if (process.env.VITEST && !force) return { migrated: false, reason: "vitest-skip" };
48
+
49
+ const sourceDir = process.env.KJ_HOME || path.join(os.homedir(), ".kj");
50
+ const targetDir = process.env.KARAJAN_HOME || path.join(os.homedir(), ".karajan");
51
+
52
+ if (path.resolve(sourceDir) === path.resolve(targetDir)) {
53
+ return { migrated: false, reason: "same-path" };
54
+ }
55
+ const entries = await readdirOrNull(sourceDir);
56
+ if (!entries) return { migrated: false, reason: "source-missing" };
57
+ if (entries.length === 0) return { migrated: false, reason: "source-empty" };
58
+
59
+ await fs.mkdir(targetDir, { recursive: true });
60
+ const markerPath = path.join(targetDir, MARKER);
61
+ try { await fs.access(markerPath); return { migrated: false, reason: "already-migrated" }; }
62
+ catch { /* not present — proceed */ }
63
+
64
+ if (dryRun) return { migrated: false, reason: "dry-run", sourceDir, targetDir };
65
+
66
+ const backupDir = path.join(targetDir, "backup");
67
+ await fs.mkdir(backupDir, { recursive: true });
68
+ const ts = new Date().toISOString().replaceAll(/[:.]/g, "-");
69
+ const backupPath = path.join(backupDir, `kj-pre-migration-${ts}.tar.gz`);
70
+ await execa("tar", ["-czf", backupPath, "-C", path.dirname(sourceDir), path.basename(sourceDir)]);
71
+
72
+ const counts = {};
73
+ for (const sub of MOVE_DIRS) {
74
+ counts[sub] = await moveChildren(path.join(sourceDir, sub), path.join(targetDir, sub));
75
+ }
76
+ counts.runs = await moveChildren(path.join(sourceDir, "runs"), path.join(targetDir, "runs"), { mergeMode: true });
77
+
78
+ const marker = { version: 1, migrated_at: new Date().toISOString(), items_moved: counts, backup_path: backupPath, source_dir: sourceDir, target_dir: targetDir };
79
+ await fs.writeFile(markerPath, JSON.stringify(marker, null, 2));
80
+
81
+ const summary = Object.entries(counts).filter(([, n]) => n > 0).map(([k, n]) => `${n} ${k}`).join(" + ");
82
+ if (summary) {
83
+ // eslint-disable-next-line no-console
84
+ console.warn(`\x1b[33m[warn]\x1b[0m Migrated ${summary} from ${sourceDir} to ${targetDir} (backup: ${backupPath})`);
85
+ }
86
+ return { migrated: true, counts, backupPath, marker };
87
+ }
@@ -0,0 +1,186 @@
1
+ /**
2
+ * Prompt-injection guard for AI-reviewed diffs and PR content.
3
+ *
4
+ * Scans text for patterns commonly used to hijack LLM instructions:
5
+ * directive overrides, role reassignment, invisible Unicode, and
6
+ * suspiciously large comment blocks that could hide payloads.
7
+ *
8
+ * @module utils/injection-guard
9
+ */
10
+
11
+ /** Phrases that attempt to override system/reviewer instructions. */
12
+ const DIRECTIVE_PATTERNS = [
13
+ /ignore\s+(all\s+)?(previous|prior|above|earlier)\s+(instructions?|rules?|prompts?|guidelines?)/i,
14
+ /disregard\s+(all\s+)?(previous|prior|above|earlier)\s+(instructions?|rules?|prompts?)/i,
15
+ /forget\s+(all\s+)?(previous|prior|your)\s+(instructions?|rules?|context)/i,
16
+ /override\s+(the\s+)?(system|reviewer|review)\s+(prompt|instructions?|rules?)/i,
17
+ /do\s+not\s+follow\s+(the\s+)?(above|previous|system)\s+(instructions?|rules?)/i,
18
+ /new\s+instructions?\s*:/i,
19
+ /system\s*:\s*you\s+are/i,
20
+ /\bact\s+as\s+(a\s+)?(different|new|my|an?\s+)/i,
21
+ /you\s+are\s+now\s+(a\s+)?/i,
22
+ /from\s+now\s+on\s*(,|\s)?\s*you\s+(will|should|must|are)/i,
23
+ /pretend\s+(you\s+are|to\s+be)/i,
24
+ /respond\s+(only\s+)?with\s+["']?approved["']?/i,
25
+ /always\s+(return|respond|output)\s+.*approved/i,
26
+ /set\s+approved\s*[=:]\s*true/i,
27
+ /\bapproved["']?\s*:\s*true\b.*ignore/i,
28
+ /output\s+the\s+following\s+json/i,
29
+ /return\s+this\s+exact\s+(json|response|output)/i,
30
+ ];
31
+
32
+ /** Unicode categories that can hide or disguise content. */
33
+ const UNICODE_PATTERNS = [
34
+ /[\u200B-\u200F]/, // zero-width spaces, LTR/RTL marks
35
+ /[\u202A-\u202E]/, // bidi embedding/override
36
+ /[\u2066-\u2069]/, // bidi isolate
37
+ /[\uFEFF]/, // BOM mid-text
38
+ /[\u00AD]{3,}/, // repeated soft hyphens
39
+ /[\u2060-\u2064]/, // invisible operators
40
+ /[\u{E0000}-\u{E007F}]/u, // tag characters
41
+ ];
42
+
43
+ /** Maximum comment block size (chars) before flagging. */
44
+ const MAX_COMMENT_BLOCK = 2000;
45
+
46
+ /**
47
+ * Comment block patterns for common languages.
48
+ * Each regex captures the full block content.
49
+ */
50
+ const COMMENT_BLOCK_RE = [
51
+ /\/\*[\s\S]{0,20000}?\*\//g, // C-style /* ... */
52
+ /<!--[\s\S]{0,20000}?-->/g, // HTML <!-- ... -->
53
+ /"""\s*[\s\S]{0,20000}?\s*"""/g, // Python docstrings
54
+ /'''\s*[\s\S]{0,20000}?\s*'''/g, // Python docstrings (single)
55
+ /=begin[\s\S]{0,20000}?=end/g, // Ruby block comments
56
+ ];
57
+
58
+ /**
59
+ * @typedef {Object} InjectionFinding
60
+ * @property {"directive"|"unicode"|"comment_block"} type
61
+ * @property {string} pattern - short label of what matched
62
+ * @property {string} snippet - excerpt of the offending text (max 120 chars)
63
+ * @property {number} [line] - approximate line number (1-based)
64
+ */
65
+
66
+ /**
67
+ * @typedef {Object} GuardResult
68
+ * @property {boolean} clean - true if no threats detected
69
+ * @property {InjectionFinding[]} findings
70
+ * @property {string} summary - human-readable one-liner
71
+ */
72
+
73
+ /**
74
+ * Scan a text (diff, PR description, comment) for prompt-injection signals.
75
+ *
76
+ * @param {string} text - content to scan
77
+ * @param {Object} [opts]
78
+ * @param {number} [opts.maxCommentBlock=2000] - flag comment blocks larger than this
79
+ * @returns {GuardResult}
80
+ */
81
+ export function scanForInjection(text, opts = {}) {
82
+ if (!text || typeof text !== "string") {
83
+ return { clean: true, findings: [], summary: "Nothing to scan" };
84
+ }
85
+
86
+ const maxBlock = opts.maxCommentBlock ?? MAX_COMMENT_BLOCK;
87
+ /** @type {InjectionFinding[]} */
88
+ const findings = [];
89
+
90
+ // 1. Directive patterns
91
+ for (const re of DIRECTIVE_PATTERNS) {
92
+ const match = re.exec(text);
93
+ if (match) {
94
+ findings.push({
95
+ type: "directive",
96
+ pattern: re.source.slice(0, 60),
97
+ snippet: excerpt(text, match.index),
98
+ line: lineAt(text, match.index),
99
+ });
100
+ }
101
+ }
102
+
103
+ // 2. Invisible Unicode
104
+ for (const re of UNICODE_PATTERNS) {
105
+ const match = re.exec(text);
106
+ if (match) {
107
+ const charCode = match[0].codePointAt(0).toString(16).toUpperCase();
108
+ findings.push({
109
+ type: "unicode",
110
+ pattern: `U+${charCode}`,
111
+ snippet: excerpt(text, match.index),
112
+ line: lineAt(text, match.index),
113
+ });
114
+ }
115
+ }
116
+
117
+ // 3. Oversized comment blocks
118
+ for (const re of COMMENT_BLOCK_RE) {
119
+ let m;
120
+ while ((m = re.exec(text)) !== null) {
121
+ if (m[0].length > maxBlock) {
122
+ findings.push({
123
+ type: "comment_block",
124
+ pattern: `block ${m[0].length} chars (max ${maxBlock})`,
125
+ snippet: excerpt(text, m.index),
126
+ line: lineAt(text, m.index),
127
+ });
128
+ }
129
+ }
130
+ }
131
+
132
+ const clean = findings.length === 0;
133
+ const summary = clean
134
+ ? "No injection patterns detected"
135
+ : `${findings.length} potential injection(s): ${[...new Set(findings.map((f) => f.type))].join(", ")}`;
136
+
137
+ return { clean, findings, summary };
138
+ }
139
+
140
+ /**
141
+ * Scan a git diff, focusing only on added lines (lines starting with +).
142
+ * Removed lines cannot inject into the AI prompt.
143
+ *
144
+ * @param {string} diff - unified diff content
145
+ * @param {Object} [opts]
146
+ * @returns {GuardResult}
147
+ */
148
+ export function scanDiff(diff, opts = {}) {
149
+ if (!diff) return { clean: true, findings: [], summary: "Empty diff" };
150
+
151
+ // Split diff into per-file chunks to avoid false positives from
152
+ // concatenated added-lines across unrelated files.
153
+ const files = diff.split(/^diff --git /m).filter(Boolean);
154
+
155
+ const allFindings = [];
156
+ for (const fileChunk of files) {
157
+ const addedLines = fileChunk
158
+ .split("\n")
159
+ .filter((l) => l.startsWith("+") && !l.startsWith("+++"))
160
+ .map((l) => l.slice(1))
161
+ .join("\n");
162
+
163
+ if (!addedLines) continue;
164
+ const result = scanForInjection(addedLines, opts);
165
+ if (!result.clean) allFindings.push(...result.findings);
166
+ }
167
+
168
+ const clean = allFindings.length === 0;
169
+ return {
170
+ clean,
171
+ findings: allFindings,
172
+ summary: clean ? "No injection patterns detected" : `${allFindings.length} injection pattern(s) detected across diff`
173
+ };
174
+ }
175
+
176
+ // --- Helpers ---
177
+
178
+ function excerpt(text, index) {
179
+ const start = Math.max(0, index - 20);
180
+ const end = Math.min(text.length, index + 100);
181
+ return text.slice(start, end).replaceAll(/\n/g, "\\n").slice(0, 120);
182
+ }
183
+
184
+ function lineAt(text, index) {
185
+ return text.slice(0, index).split("\n").length;
186
+ }