@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,37 @@
1
+ import { runCommand } from "./process.js";
2
+ import { getInstallCommand } from "./os-detect.js";
3
+ import { detectSqueezr } from "./squeezr-detect.js";
4
+
5
+ /**
6
+ * Install Squeezr using the OS-appropriate command.
7
+ * @param {object} logger - Logger with info/warn methods
8
+ * @returns {Promise<{ ok: boolean, version: string|null, error: string|null }>}
9
+ */
10
+ export async function installSqueezr(logger) {
11
+ const command = getInstallCommand("squeezr");
12
+
13
+ logger.info("Installing Squeezr...");
14
+
15
+ try {
16
+ const result = await runCommand("sh", ["-c", command], { timeout: 120_000 });
17
+
18
+ if (result.exitCode !== 0) {
19
+ const error = (result.stderr || "").trim() || `exit code ${result.exitCode}`;
20
+ logger.warn(`Squeezr install failed: ${error}`);
21
+ return { ok: false, version: null, error };
22
+ }
23
+
24
+ const check = await detectSqueezr();
25
+ if (check.available) {
26
+ logger.info(`Squeezr ${check.version || ""} installed successfully.`);
27
+ return { ok: true, version: check.version, error: null };
28
+ }
29
+
30
+ logger.warn("Squeezr install command succeeded but squeezr binary not found in PATH.");
31
+ return { ok: false, version: null, error: "Binary not found after install" };
32
+ } catch (err) {
33
+ const error = err.message || String(err);
34
+ logger.warn(`Squeezr install failed: ${error}`);
35
+ return { ok: false, version: null, error };
36
+ }
37
+ }
@@ -0,0 +1,135 @@
1
+ /**
2
+ * Detects the project technology stack by scanning project files.
3
+ * Used by `kj init` to auto-configure roles, skills, and settings.
4
+ */
5
+
6
+ import fs from "node:fs/promises";
7
+ import path from "node:path";
8
+
9
+ /**
10
+ * Frameworks detectable from package.json dependencies.
11
+ * Maps dependency name -> { name, type } where type is "frontend" | "backend" | "fullstack".
12
+ */
13
+ const PKG_FRAMEWORKS = {
14
+ react: { name: "react", type: "frontend" },
15
+ "react-dom": { name: "react", type: "frontend" },
16
+ vue: { name: "vue", type: "frontend" },
17
+ svelte: { name: "svelte", type: "frontend" },
18
+ "@angular/core": { name: "angular", type: "frontend" },
19
+ astro: { name: "astro", type: "frontend" },
20
+ next: { name: "next", type: "fullstack" },
21
+ nuxt: { name: "nuxt", type: "fullstack" },
22
+ "solid-js": { name: "solid", type: "frontend" },
23
+ lit: { name: "lit", type: "frontend" },
24
+ express: { name: "express", type: "backend" },
25
+ fastify: { name: "fastify", type: "backend" },
26
+ "@nestjs/core": { name: "nestjs", type: "backend" },
27
+ hono: { name: "hono", type: "backend" },
28
+ koa: { name: "koa", type: "backend" },
29
+ };
30
+
31
+ /**
32
+ * Language markers: file presence -> { language, type }.
33
+ */
34
+ const LANGUAGE_FILE_MARKERS = [
35
+ { file: "go.mod", language: "go", type: "backend" },
36
+ { file: "Cargo.toml", language: "rust", type: "backend" },
37
+ { file: "pom.xml", language: "java", type: "backend" },
38
+ { file: "build.gradle", language: "java", type: "backend" },
39
+ { file: "build.gradle.kts", language: "kotlin", type: "backend" },
40
+ { file: "pyproject.toml", language: "python", type: "backend" },
41
+ { file: "setup.py", language: "python", type: "backend" },
42
+ { file: "requirements.txt", language: "python", type: "backend" },
43
+ { file: "Gemfile", language: "ruby", type: "backend" },
44
+ { file: "composer.json", language: "php", type: "backend" },
45
+ { file: "pubspec.yaml", language: "dart", type: "frontend" },
46
+ { file: "Package.swift", language: "swift", type: "backend" },
47
+ ];
48
+
49
+ /**
50
+ * Maps framework names to skill names for auto-install suggestions.
51
+ */
52
+ const FRAMEWORK_TO_SKILL = {
53
+ react: "react",
54
+ vue: "vue",
55
+ svelte: "svelte",
56
+ angular: "angular",
57
+ astro: "astro",
58
+ next: "nextjs",
59
+ nuxt: "vue",
60
+ solid: "solid",
61
+ lit: "lit",
62
+ express: "express",
63
+ fastify: "fastify",
64
+ nestjs: "nestjs",
65
+ };
66
+
67
+ /**
68
+ * Detect the project technology stack.
69
+ * @param {string} projectDir - Absolute path to project root.
70
+ * @returns {Promise<{frameworks: string[], language: string|null, isFrontend: boolean, isBackend: boolean, isFullstack: boolean, suggestions: {impeccable: boolean, skills: string[]}}>}
71
+ */
72
+ export async function detectProjectStack(projectDir) {
73
+ const frameworks = new Set();
74
+ let language = null;
75
+ let hasFrontend = false;
76
+ let hasBackend = false;
77
+
78
+ // 1. Scan package.json for known frameworks
79
+ try {
80
+ const pkgRaw = await fs.readFile(path.join(projectDir, "package.json"), "utf8");
81
+ const pkg = JSON.parse(pkgRaw);
82
+ const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
83
+
84
+ if (!language) language = "javascript";
85
+
86
+ // Check for TypeScript
87
+ if (allDeps.typescript || allDeps["ts-node"]) {
88
+ language = "typescript";
89
+ }
90
+
91
+ for (const [dep, info] of Object.entries(PKG_FRAMEWORKS)) {
92
+ if (allDeps[dep]) {
93
+ frameworks.add(info.name);
94
+ if (info.type === "frontend" || info.type === "fullstack") hasFrontend = true;
95
+ if (info.type === "backend" || info.type === "fullstack") hasBackend = true;
96
+ }
97
+ }
98
+ } catch { /* no package.json or parse error */ }
99
+
100
+ // 2. Check language file markers
101
+ for (const marker of LANGUAGE_FILE_MARKERS) {
102
+ try {
103
+ await fs.access(path.join(projectDir, marker.file));
104
+ if (!language || language === "javascript") {
105
+ language = marker.language;
106
+ }
107
+ if (marker.type === "frontend") hasFrontend = true;
108
+ if (marker.type === "backend") hasBackend = true;
109
+ } catch { /* file not found */ }
110
+ }
111
+
112
+ const frameworkList = Array.from(frameworks);
113
+ const isFullstack = hasFrontend && hasBackend;
114
+
115
+ // Build suggestions
116
+ const skills = [];
117
+ for (const fw of frameworkList) {
118
+ const skill = FRAMEWORK_TO_SKILL[fw];
119
+ if (skill && !skills.includes(skill)) {
120
+ skills.push(skill);
121
+ }
122
+ }
123
+
124
+ return {
125
+ frameworks: frameworkList,
126
+ language,
127
+ isFrontend: hasFrontend,
128
+ isBackend: hasBackend,
129
+ isFullstack,
130
+ suggestions: {
131
+ impeccable: hasFrontend,
132
+ skills,
133
+ },
134
+ };
135
+ }
@@ -0,0 +1,159 @@
1
+ /**
2
+ * Stall detector for agent execution.
3
+ *
4
+ * Wraps an onOutput callback to track activity and emit heartbeat / stall
5
+ * warnings when an agent stops producing output for too long.
6
+ *
7
+ * Usage:
8
+ * const detector = createStallDetector({ onOutput, emitter, eventBase, stage, provider, stallTimeoutMs });
9
+ * // pass detector.onOutput to the agent
10
+ * // when done: detector.stop();
11
+ */
12
+
13
+ import { emitProgress, makeEvent } from "./events.js";
14
+
15
+ const DEFAULT_HEARTBEAT_INTERVAL_MS = 30_000; // heartbeat every 30s
16
+ const DEFAULT_STALL_TIMEOUT_MS = 120_000; // warn after 2min silence
17
+ const DEFAULT_CRITICAL_TIMEOUT_MS = 300_000; // critical after 5min silence
18
+ const DEFAULT_STALL_REPEAT_MS = 60_000; // repeat stall notices every 60s
19
+
20
+ export function createStallDetector({
21
+ onOutput,
22
+ emitter,
23
+ eventBase,
24
+ stage,
25
+ provider,
26
+ heartbeatIntervalMs = DEFAULT_HEARTBEAT_INTERVAL_MS,
27
+ stallTimeoutMs = DEFAULT_STALL_TIMEOUT_MS,
28
+ criticalTimeoutMs = DEFAULT_CRITICAL_TIMEOUT_MS,
29
+ stallRepeatMs = DEFAULT_STALL_REPEAT_MS,
30
+ maxSilenceMs = null,
31
+ onMaxSilence = null
32
+ }) {
33
+ let lastActivityAt = Date.now();
34
+ let lineCount = 0;
35
+ let bytesReceived = 0;
36
+ let heartbeatTimer = null;
37
+ const startedAt = Date.now();
38
+ let lastStallWarnAt = 0;
39
+ let lastCriticalWarnAt = 0;
40
+ let maxSilenceTriggered = false;
41
+
42
+ function emitHeartbeat() {
43
+ const now = Date.now();
44
+ const silenceMs = now - lastActivityAt;
45
+ const elapsedMs = now - startedAt;
46
+ const shouldWarn = silenceMs >= stallTimeoutMs;
47
+ const shouldCritical = silenceMs >= criticalTimeoutMs;
48
+ const repeatWindow = Math.max(1000, Number(stallRepeatMs) || DEFAULT_STALL_REPEAT_MS);
49
+
50
+ if (shouldCritical && (now - lastCriticalWarnAt >= repeatWindow)) {
51
+ lastCriticalWarnAt = now;
52
+ emitProgress(emitter, makeEvent("agent:stall", { ...eventBase, stage }, {
53
+ status: "critical",
54
+ message: `[${stage}] Agent ${provider} unresponsive for ${Math.round(silenceMs / 1000)}s — may be hung`,
55
+ detail: {
56
+ provider,
57
+ silenceMs,
58
+ elapsedMs,
59
+ lineCount,
60
+ bytesReceived,
61
+ severity: "critical"
62
+ }
63
+ }));
64
+ } else if (shouldWarn && (now - lastStallWarnAt >= repeatWindow)) {
65
+ lastStallWarnAt = now;
66
+ emitProgress(emitter, makeEvent("agent:stall", { ...eventBase, stage }, {
67
+ status: "warning",
68
+ message: `[${stage}] Agent ${provider} silent for ${Math.round(silenceMs / 1000)}s — still waiting`,
69
+ detail: {
70
+ provider,
71
+ silenceMs,
72
+ elapsedMs,
73
+ lineCount,
74
+ bytesReceived,
75
+ severity: "warning"
76
+ }
77
+ }));
78
+ }
79
+
80
+ emitProgress(emitter, makeEvent("agent:heartbeat", { ...eventBase, stage }, {
81
+ message: silenceMs < stallTimeoutMs
82
+ ? `[${stage}] Agent ${provider} active — ${lineCount} lines, ${Math.round(elapsedMs / 1000)}s elapsed`
83
+ : `[${stage}] Agent ${provider} waiting — silent ${Math.round(silenceMs / 1000)}s, ${Math.round(elapsedMs / 1000)}s elapsed`,
84
+ detail: {
85
+ provider,
86
+ elapsedMs,
87
+ silenceMs,
88
+ lineCount,
89
+ bytesReceived,
90
+ status: silenceMs < stallTimeoutMs ? "active" : "waiting"
91
+ }
92
+ }));
93
+
94
+ const hardLimit = Number(maxSilenceMs);
95
+ if (!maxSilenceTriggered && Number.isFinite(hardLimit) && hardLimit > 0 && silenceMs >= hardLimit) {
96
+ maxSilenceTriggered = true;
97
+ emitProgress(emitter, makeEvent("agent:stall", { ...eventBase, stage }, {
98
+ status: "fail",
99
+ message: `[${stage}] Agent ${provider} exceeded max silence (${Math.round(hardLimit / 1000)}s)`,
100
+ detail: {
101
+ provider,
102
+ silenceMs,
103
+ elapsedMs,
104
+ lineCount,
105
+ bytesReceived,
106
+ severity: "fatal",
107
+ maxSilenceMs: hardLimit
108
+ }
109
+ }));
110
+ if (typeof onMaxSilence === "function") {
111
+ onMaxSilence({
112
+ provider,
113
+ stage,
114
+ silenceMs,
115
+ elapsedMs,
116
+ lineCount,
117
+ bytesReceived,
118
+ maxSilenceMs: hardLimit
119
+ });
120
+ }
121
+ }
122
+ }
123
+
124
+ // Start periodic heartbeat
125
+ heartbeatTimer = setInterval(emitHeartbeat, heartbeatIntervalMs);
126
+
127
+ function wrappedOnOutput(data) {
128
+ lastActivityAt = Date.now();
129
+ lineCount++;
130
+ bytesReceived += data.line?.length || 0;
131
+
132
+ // Forward to the original callback
133
+ if (onOutput) {
134
+ onOutput(data);
135
+ }
136
+ }
137
+
138
+ function stop() {
139
+ if (heartbeatTimer) {
140
+ clearInterval(heartbeatTimer);
141
+ heartbeatTimer = null;
142
+ }
143
+ }
144
+
145
+ function stats() {
146
+ return {
147
+ lineCount,
148
+ bytesReceived,
149
+ elapsedMs: Date.now() - startedAt,
150
+ lastActivityMs: Date.now() - lastActivityAt
151
+ };
152
+ }
153
+
154
+ return {
155
+ onOutput: wrappedOnOutput,
156
+ stop,
157
+ stats
158
+ };
159
+ }
@@ -0,0 +1,254 @@
1
+ /**
2
+ * Status dashboard formatter.
3
+ * Builds a structured terminal dashboard from session data and run-log lines.
4
+ */
5
+
6
+ import { HU_STATUS } from "../hu/store.js";
7
+
8
+ /**
9
+ * Status label mapping with visual indicators for terminal output.
10
+ * @type {Record<string, string>}
11
+ */
12
+ const STATUS_LABELS = {
13
+ [HU_STATUS.PENDING]: "pending",
14
+ [HU_STATUS.CODING]: "coding",
15
+ [HU_STATUS.REVIEWING]: "reviewing",
16
+ [HU_STATUS.DONE]: "done",
17
+ [HU_STATUS.FAILED]: "failed",
18
+ [HU_STATUS.BLOCKED]: "blocked",
19
+ [HU_STATUS.CERTIFIED]: "certified",
20
+ [HU_STATUS.NEEDS_CONTEXT]: "needs_ctx",
21
+ };
22
+
23
+ /**
24
+ * Format a millisecond duration into a human-readable string (e.g. "3m 42s").
25
+ * @param {number} ms
26
+ * @returns {string}
27
+ */
28
+ export function formatDuration(ms) {
29
+ if (!ms || ms < 0) return "0s";
30
+ const totalSec = Math.floor(ms / 1000);
31
+ const hours = Math.floor(totalSec / 3600);
32
+ const minutes = Math.floor((totalSec % 3600) / 60);
33
+ const seconds = totalSec % 60;
34
+
35
+ const parts = [];
36
+ if (hours > 0) parts.push(`${hours}h`);
37
+ if (minutes > 0) parts.push(`${minutes}m`);
38
+ if (seconds > 0 || parts.length === 0) parts.push(`${seconds}s`);
39
+ return parts.join(" ");
40
+ }
41
+
42
+ /**
43
+ * Parse the current pipeline stage from log lines.
44
+ * @param {string[]} lines - Raw log lines.
45
+ * @returns {{ currentStage: string|null, lastEvent: string|null }}
46
+ */
47
+ export function parseStageFromLog(lines) {
48
+ let currentStage = null;
49
+ let lastEvent = null;
50
+
51
+ for (const line of lines) {
52
+ const stageStart = /\[(\w+):start\]/.exec(line);
53
+ if (stageStart) currentStage = stageStart[1];
54
+
55
+ const stageDone = /\[(\w+):done\]|\[(\w+)\] finished/.exec(line);
56
+ if (stageDone) {
57
+ const doneName = stageDone[1] || stageDone[2];
58
+ if (doneName === currentStage) currentStage = "idle";
59
+ }
60
+
61
+ if (line.includes("[standby]") || line.includes("standby")) {
62
+ currentStage = "standby";
63
+ }
64
+
65
+ if (line.trim()) lastEvent = line.trim();
66
+ }
67
+
68
+ return { currentStage, lastEvent };
69
+ }
70
+
71
+ /**
72
+ * Format a single HU line for the dashboard.
73
+ * @param {object} story - HU story object.
74
+ * @param {boolean} isCurrent - Whether this is the currently active HU.
75
+ * @returns {string}
76
+ */
77
+ function formatHuLine(story, isCurrent) {
78
+ const id = (story.id || "???").padEnd(12);
79
+ const rawStatus = story.status || "pending";
80
+ const label = STATUS_LABELS[rawStatus] || rawStatus;
81
+ const statusStr = `[${label}]`.padEnd(13);
82
+ const title = story.title || story.original?.text || "(untitled)";
83
+ const truncTitle = title.length > 40 ? title.slice(0, 37) + "..." : title;
84
+
85
+ let timing = "";
86
+ if (story.duration_ms) {
87
+ timing = formatDuration(story.duration_ms);
88
+ }
89
+
90
+ const blockedInfo = story.blocked_by?.length
91
+ ? ` (needs ${story.blocked_by.join(", ")})`
92
+ : "";
93
+
94
+ const marker = isCurrent ? " <-- current" : "";
95
+ const timingStr = timing ? ` ${timing}` : "";
96
+
97
+ return ` ${id} ${statusStr} ${truncTitle}${blockedInfo}${timingStr}${marker}`;
98
+ }
99
+
100
+ /**
101
+ * Build a terminal dashboard string from session data and log lines.
102
+ *
103
+ * @param {object|null} sessionData - Session JSON (from session-store) or null.
104
+ * @param {string[]} logLines - Raw run-log lines.
105
+ * @param {object} [options] - Optional overrides.
106
+ * @param {object[]|null} [options.stories] - HU stories array (from hu batch).
107
+ * @returns {string}
108
+ */
109
+ export function buildDashboard(sessionData, logLines, options = {}) {
110
+ if (!sessionData) {
111
+ return "No active pipeline";
112
+ }
113
+
114
+ const lines = [];
115
+ const config = sessionData.config_snapshot || {};
116
+ const maxIter = config.max_iterations ?? "?";
117
+ const status = sessionData.status || "unknown";
118
+
119
+ // Parse log for current stage info
120
+ const logInfo = parseStageFromLog(logLines || []);
121
+
122
+ // Determine iteration from session or log
123
+ const iteration = sessionData.reviewer_retry_count != null
124
+ ? sessionData.reviewer_retry_count + 1
125
+ : null;
126
+ const iterFromLog = parseIterationFromLog(logLines || []);
127
+ const displayIter = iterFromLog || iteration || "?";
128
+
129
+ // Pipeline header
130
+ const statusUpper = status.toUpperCase();
131
+ lines.push(`Pipeline: ${statusUpper} (iteration ${displayIter}/${maxIter})`);
132
+
133
+ // Duration
134
+ const duration = computeDuration(sessionData);
135
+ lines.push(`Duration: ${formatDuration(duration)}`);
136
+
137
+ // Agent info
138
+ const coderProvider = config.coder?.provider || config.roles?.coder?.provider || "?";
139
+ const reviewerProvider = config.reviewer?.provider || config.roles?.reviewer?.provider || "?";
140
+ lines.push(`Agent: ${coderProvider} (coder) / ${reviewerProvider} (reviewer)`);
141
+
142
+ // HU stories section
143
+ const stories = options.stories || [];
144
+ if (stories.length > 0) {
145
+ lines.push("");
146
+ lines.push("HUs:");
147
+
148
+ // Determine which story is currently being worked on
149
+ const currentStory = stories.find(s =>
150
+ s.status === HU_STATUS.CODING || s.status === HU_STATUS.REVIEWING
151
+ );
152
+
153
+ for (const story of stories) {
154
+ const isCurrent = currentStory && story.id === currentStory.id;
155
+ lines.push(formatHuLine(story, isCurrent));
156
+ }
157
+ }
158
+
159
+ // Current stage and last event
160
+ lines.push("");
161
+ const stage = logInfo.currentStage || "idle";
162
+ const iterSuffix = displayIter !== "?" ? ` (iteration ${displayIter})` : "";
163
+ lines.push(`Current stage: ${stage}${iterSuffix}`);
164
+
165
+ if (logInfo.lastEvent) {
166
+ // Truncate last event for display
167
+ const maxLen = 120;
168
+ const event = logInfo.lastEvent.length > maxLen
169
+ ? logInfo.lastEvent.slice(0, maxLen - 3) + "..."
170
+ : logInfo.lastEvent;
171
+ lines.push(`Last event: ${event}`);
172
+ }
173
+
174
+ // Errors
175
+ if (sessionData.deferred_issues?.length) {
176
+ lines.push("");
177
+ lines.push(`Deferred issues: ${sessionData.deferred_issues.length}`);
178
+ }
179
+
180
+ return lines.join("\n");
181
+ }
182
+
183
+ /**
184
+ * Build a structured JSON response for MCP consumers.
185
+ *
186
+ * @param {object|null} sessionData - Session JSON or null.
187
+ * @param {string[]} logLines - Raw run-log lines.
188
+ * @param {object} [options] - Optional overrides.
189
+ * @param {object[]|null} [options.stories] - HU stories array.
190
+ * @returns {object}
191
+ */
192
+ export function buildDashboardJson(sessionData, logLines, options = {}) {
193
+ if (!sessionData) {
194
+ return { ok: false, message: "No active pipeline" };
195
+ }
196
+
197
+ const config = sessionData.config_snapshot || {};
198
+ const logInfo = parseStageFromLog(logLines || []);
199
+ const iterFromLog = parseIterationFromLog(logLines || []);
200
+ const iteration = iterFromLog
201
+ || (sessionData.reviewer_retry_count != null ? sessionData.reviewer_retry_count + 1 : null);
202
+
203
+ const stories = (options.stories || []).map(s => ({
204
+ id: s.id,
205
+ status: s.status || "pending",
206
+ title: s.title || s.original?.text || null,
207
+ blocked_by: s.blocked_by || [],
208
+ duration_ms: s.duration_ms || null,
209
+ }));
210
+
211
+ return {
212
+ ok: true,
213
+ pipeline: {
214
+ status: sessionData.status || "unknown",
215
+ iteration: iteration || null,
216
+ maxIterations: config.max_iterations ?? null,
217
+ duration_ms: computeDuration(sessionData),
218
+ coder: config.coder?.provider || config.roles?.coder?.provider || null,
219
+ reviewer: config.reviewer?.provider || config.roles?.reviewer?.provider || null,
220
+ },
221
+ hus: stories,
222
+ currentStage: logInfo.currentStage || "idle",
223
+ lastEvent: logInfo.lastEvent || null,
224
+ };
225
+ }
226
+
227
+ /**
228
+ * Parse iteration number from log lines.
229
+ * @param {string[]} lines
230
+ * @returns {number|null}
231
+ */
232
+ function parseIterationFromLog(lines) {
233
+ let iteration = null;
234
+ for (const line of lines) {
235
+ const m = /[Ii]teration\s+(\d+)/.exec(line);
236
+ if (m) iteration = Number.parseInt(m[1], 10);
237
+ }
238
+ return iteration;
239
+ }
240
+
241
+ /**
242
+ * Compute pipeline duration in milliseconds from session timestamps.
243
+ * @param {object} sessionData
244
+ * @returns {number}
245
+ */
246
+ function computeDuration(sessionData) {
247
+ const created = sessionData.created_at;
248
+ if (!created) return 0;
249
+ const start = new Date(created).getTime();
250
+ const now = sessionData.updated_at
251
+ ? new Date(sessionData.updated_at).getTime()
252
+ : Date.now();
253
+ return Math.max(0, now - start);
254
+ }
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Load a task description from a file (.md / .txt / .markdown / any plain text).
3
+ *
4
+ * Motivation: for anything beyond a one-line task, writing a `kj run "long
5
+ * multi-paragraph prompt ..."` becomes painful — escaping quotes, losing
6
+ * markdown formatting, no history. `kj run --task-file my-task.md` reads the
7
+ * file's contents and uses them as the task description. Same for `kj plan`,
8
+ * `kj audit`, `kj code`, and their MCP counterparts (via the `taskFile`
9
+ * argument).
10
+ *
11
+ * Behaviour:
12
+ * - `taskFile` may be relative (resolved against `process.cwd()` by default,
13
+ * or against `projectDir` if supplied) or absolute.
14
+ * - Accepts any text file; markdown is the expected common case but we do
15
+ * not require a specific extension.
16
+ * - Trimmed of leading/trailing whitespace so agents don't get empty lines
17
+ * around the task.
18
+ * - `maxBytes` (default 256 KiB) guards against accidentally passing a huge
19
+ * file (log dumps, PDFs). Agents choke on very long prompts anyway.
20
+ * - Precedence with the positional `task` arg is decided by the caller:
21
+ * this helper only loads, never merges. Convention used across commands:
22
+ * when BOTH are provided, the positional task wins and the file is a
23
+ * fallback — with a log warning so the user notices.
24
+ */
25
+
26
+ import fs from "node:fs/promises";
27
+ import path from "node:path";
28
+
29
+ export const DEFAULT_TASK_FILE_MAX_BYTES = 256 * 1024;
30
+
31
+ /**
32
+ * @param {string} filePath - relative or absolute
33
+ * @param {Object} [opts]
34
+ * @param {string} [opts.projectDir] - base dir for relative paths; defaults to process.cwd()
35
+ * @param {number} [opts.maxBytes] - size cap; default 256 KiB
36
+ * @returns {Promise<string>} - the trimmed file contents (task text)
37
+ * @throws - Error with a user-readable message when the file is
38
+ * missing, unreadable, empty, or over the size cap.
39
+ */
40
+ export async function readTaskFile(filePath, opts = {}) {
41
+ if (!filePath || typeof filePath !== "string") {
42
+ throw new Error("readTaskFile: path must be a non-empty string");
43
+ }
44
+ const { projectDir, maxBytes = DEFAULT_TASK_FILE_MAX_BYTES } = opts;
45
+ const base = projectDir || process.cwd();
46
+ const resolved = path.isAbsolute(filePath) ? filePath : path.resolve(base, filePath);
47
+
48
+ let stat;
49
+ try {
50
+ stat = await fs.stat(resolved);
51
+ } catch (err) {
52
+ throw new Error(`Task file not found: ${resolved} (${err.code || err.message})`, { cause: err });
53
+ }
54
+ if (!stat.isFile()) {
55
+ throw new Error(`Task file is not a regular file: ${resolved}`);
56
+ }
57
+ if (stat.size > maxBytes) {
58
+ const kb = Math.round(stat.size / 1024);
59
+ const capKb = Math.round(maxBytes / 1024);
60
+ throw new Error(
61
+ `Task file is too large: ${resolved} (${kb} KiB > ${capKb} KiB cap). ` +
62
+ `Summarise the task or raise the limit with the caller's maxBytes option.`
63
+ );
64
+ }
65
+
66
+ const raw = await fs.readFile(resolved, "utf8");
67
+ const trimmed = raw.trim();
68
+ if (!trimmed) {
69
+ throw new Error(`Task file is empty (or whitespace-only): ${resolved}`);
70
+ }
71
+ return trimmed;
72
+ }
73
+
74
+ /**
75
+ * Resolve the task text a command should use, given both positional `task`
76
+ * and an optional `taskFile`. Single source of truth for precedence across
77
+ * CLI and MCP entry points.
78
+ *
79
+ * Rules:
80
+ * - Neither provided → throw (caller decides the UX; typically propagates).
81
+ * - Only `task` → returns it, untouched.
82
+ * - Only `taskFile` → reads and returns it.
83
+ * - Both → `task` wins; emits a warning through `logger.warn` (if given).
84
+ *
85
+ * @param {Object} args
86
+ * @param {string|undefined} args.task
87
+ * @param {string|undefined} args.taskFile
88
+ * @param {string} [args.projectDir]
89
+ * @param {Object} [args.logger] - optional; uses `logger.warn(msg)` only
90
+ * @returns {Promise<string>}
91
+ */
92
+ export async function resolveTaskInput({ task, taskFile, projectDir, logger } = {}) {
93
+ const hasTask = typeof task === "string" && task.trim().length > 0;
94
+ const hasFile = typeof taskFile === "string" && taskFile.trim().length > 0;
95
+
96
+ if (!hasTask && !hasFile) {
97
+ throw new Error("No task provided. Pass a task argument or --task-file <path>.");
98
+ }
99
+ if (hasTask && hasFile) {
100
+ logger?.warn?.(
101
+ `Both task and --task-file given; using the positional task and ignoring file: ${taskFile}`
102
+ );
103
+ return task.trim();
104
+ }
105
+ if (hasFile) {
106
+ return readTaskFile(taskFile, { projectDir });
107
+ }
108
+ return task.trim();
109
+ }