@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,320 @@
1
+ /**
2
+ * Executive session summary (`summary.md`) — the entry point to the journal
3
+ * directory. Pulls together every useful signal from the session into a
4
+ * single scannable Markdown page with links to the rest of the journal.
5
+ *
6
+ * Acceptance criterion (KJC-TSK-0289):
7
+ * summary.md contains: task, result (approved/rejected/paused), iterations,
8
+ * duration, budget, stages + status, list of journal files, commits.
9
+ */
10
+
11
+ import fs from "node:fs/promises";
12
+ import path from "node:path";
13
+
14
+ /**
15
+ * @typedef {Object} SummaryInput
16
+ * @property {string} sessionId
17
+ * @property {string} task
18
+ * @property {"APPROVED"|"REJECTED"|"PAUSED"|"FAILED"|string} result
19
+ * @property {number} iterations
20
+ * @property {number} durationMs
21
+ * @property {{ total_cost_usd?: number, total_tokens?: number, total_cached_tokens?: number, breakdown_by_role?: Object }} [budget]
22
+ * @property {Record<string, { ok?: boolean, summary?: string }>} [stages]
23
+ * @property {Array<{ hash?: string, message?: string, date?: string, author?: string }>} [commits]
24
+ * @property {string[]} [files] - names of other journal files in the same dir
25
+ * @property {string} [startedAt] - ISO timestamp (optional, auto-derived if absent)
26
+ * @property {string} [finishedAt] - ISO timestamp (optional)
27
+ * @property {number} [solomonInvocations]
28
+ * @property {number} [brainDecisions]
29
+ * @property {Object} [skills] - skill sources used this session (KJC-TSK-0327)
30
+ * @property {Object} [skills.addyosmani] - { available, action, resolvedSlugs, reason }
31
+ * @property {string[]} [skills.installed] - OpenSkills installed this run (session.autoInstalledSkills)
32
+ * @property {string[]} [skills.recommended] - wouldHaveUsed when OpenSkills CLI missing
33
+ */
34
+
35
+ function esc(text) {
36
+ return String(text ?? "").replaceAll(/\|/g, "\\|");
37
+ }
38
+
39
+ function formatDuration(ms) {
40
+ if (!Number.isFinite(ms) || ms < 0) return "—";
41
+ if (ms < 1000) return `${ms}ms`;
42
+ const s = Math.round(ms / 1000);
43
+ if (s < 60) return `${s}s`;
44
+ const m = Math.floor(s / 60);
45
+ const rs = s % 60;
46
+ if (m < 60) return `${m}m ${rs}s`;
47
+ const h = Math.floor(m / 60);
48
+ const rm = m % 60;
49
+ return `${h}h ${rm}m ${rs}s`;
50
+ }
51
+
52
+ function formatBudget(budget) {
53
+ if (!budget) return "—";
54
+ const cost = Number(budget.total_cost_usd ?? 0);
55
+ const tokens = Number(budget.total_tokens ?? 0);
56
+ const costStr = `$${cost.toFixed(2)}`;
57
+ const tokStr = tokens > 0 ? `${tokens.toLocaleString("en-US")} tokens` : "—";
58
+ return `${costStr} · ${tokStr}`;
59
+ }
60
+
61
+ function resultBadge(result) {
62
+ const r = String(result || "").toUpperCase();
63
+ const map = {
64
+ APPROVED: "✅ APPROVED",
65
+ REJECTED: "❌ REJECTED",
66
+ PAUSED: "⏸ PAUSED",
67
+ FAILED: "❌ FAILED",
68
+ };
69
+ return map[r] || r;
70
+ }
71
+
72
+ function renderStagesTable(stages) {
73
+ if (!stages || Object.keys(stages).length === 0) return "_No stages recorded._";
74
+ const header = "| Stage | Status | Summary |\n|---|---|---|";
75
+ const rows = Object.entries(stages).map(([name, stageResult]) => {
76
+ const ok = stageResult?.ok !== false;
77
+ const status = ok ? "✅ pass" : "❌ fail";
78
+ const summary = esc(stageResult?.summary || "").slice(0, 120);
79
+ return `| \`${esc(name)}\` | ${status} | ${summary} |`;
80
+ });
81
+ return [header, ...rows].join("\n");
82
+ }
83
+
84
+ function renderCommits(commits) {
85
+ if (!Array.isArray(commits) || commits.length === 0) return "_No commits in this session._";
86
+ return commits
87
+ .map((c) => {
88
+ const hash = (c.hash || "").slice(0, 7) || "?";
89
+ return `- \`${hash}\` ${esc(c.message || "(no message)")}`;
90
+ })
91
+ .join("\n");
92
+ }
93
+
94
+ function renderBreakdownByRole(breakdown) {
95
+ if (!breakdown || typeof breakdown !== "object") return null;
96
+ const entries = Object.entries(breakdown)
97
+ .map(([role, m]) => ({
98
+ role,
99
+ tokens: Number(m?.total_tokens || 0),
100
+ cost: Number(m?.total_cost_usd || 0),
101
+ }))
102
+ .filter((e) => e.tokens > 0 || e.cost > 0);
103
+ if (entries.length === 0) return null;
104
+ const rows = entries
105
+ .sort((a, b) => b.cost - a.cost)
106
+ .map((e) => `| \`${esc(e.role)}\` | ${e.tokens.toLocaleString("en-US")} | $${e.cost.toFixed(4)} |`);
107
+ return ["| Role | Tokens | Cost |", "|---|---|---|", ...rows].join("\n");
108
+ }
109
+
110
+ /**
111
+ * Render the Cache hits section (Φ0-F, KJC-TSK-0524). Shows how many input
112
+ * tokens were served from provider-side prompt caches, per role, plus a
113
+ * conservative dollar savings estimate.
114
+ *
115
+ * Savings formula: cached tokens are billed at ~10% of the input rate (the
116
+ * Anthropic/OpenAI convention). Per role:
117
+ * savings_usd ≈ cost_usd * (cached_tokens / tokens_in) * 0.9
118
+ * The estimate is approximate (output tokens also contribute to cost_usd)
119
+ * and labelled with `~$` so users don't read it as exact.
120
+ *
121
+ * Returns:
122
+ * - null when no budget data is available
123
+ * - "cold run" placeholder when cached == 0 across all roles
124
+ * - Markdown table sorted by cached tokens desc when there is cache activity
125
+ */
126
+ function renderCacheHits(budget) {
127
+ if (!budget) return null;
128
+ const totalCached = Number(budget.total_cached_tokens ?? 0);
129
+ const breakdown = budget.breakdown_by_role || {};
130
+ const entries = Object.entries(breakdown)
131
+ .map(([role, m]) => ({
132
+ role,
133
+ cached: Number(m?.cached_tokens || 0),
134
+ tokens_in: Number(m?.tokens_in || 0),
135
+ cost: Number(m?.total_cost_usd || 0),
136
+ }))
137
+ .filter((e) => e.cached > 0);
138
+
139
+ if (totalCached === 0 && entries.length === 0) {
140
+ return "_Cache hits: 0 tokens (cold run)._";
141
+ }
142
+
143
+ const rows = entries
144
+ .sort((a, b) => b.cached - a.cached)
145
+ .map((e) => {
146
+ const ratio = e.tokens_in > 0 ? (e.cached / e.tokens_in) * 100 : 0;
147
+ const savings = e.tokens_in > 0 ? e.cost * (e.cached / e.tokens_in) * 0.9 : 0;
148
+ return `| \`${esc(e.role)}\` | ${e.cached.toLocaleString("en-US")} | ${ratio.toFixed(1)}% | ~$${savings.toFixed(4)} |`;
149
+ });
150
+ const header = "| Role | Cached tokens | Ratio (cached/in) | Est. savings |\n|---|---|---|---|";
151
+ return [
152
+ `**Total cached**: ${totalCached.toLocaleString("en-US")} tokens`,
153
+ "",
154
+ header,
155
+ ...rows,
156
+ ].join("\n");
157
+ }
158
+
159
+ /**
160
+ * Render the Skills section: which process skills (addyosmani) were resolved
161
+ * for the task, which OpenSkills were installed, and which skills would have
162
+ * helped but couldn't be installed (graceful-degradation path).
163
+ *
164
+ * Returns null when no skill activity happened (no addyosmani, no installs,
165
+ * no recommendations) so the section is elided.
166
+ */
167
+ function renderSkills(skills) {
168
+ if (!skills || typeof skills !== "object") return null;
169
+ const addy = skills.addyosmani;
170
+ const installed = Array.isArray(skills.installed) ? skills.installed : [];
171
+ const recommended = Array.isArray(skills.recommended) ? skills.recommended : [];
172
+
173
+ const hasAddy = addy && (addy.available === true || addy.available === false);
174
+ if (!hasAddy && installed.length === 0 && recommended.length === 0) return null;
175
+
176
+ const lines = [];
177
+
178
+ if (hasAddy) {
179
+ if (addy.available) {
180
+ const action = addy.action || "ready";
181
+ const slugs = Array.isArray(addy.resolvedSlugs) ? addy.resolvedSlugs : [];
182
+ lines.push(`- **addyosmani/agent-skills** (process, 1st source): ${esc(action)}` +
183
+ (slugs.length > 0 ? ` — resolved slugs: ${slugs.map((s) => `\`${esc(s)}\``).join(", ")}` : " — no role/task-specific slugs resolved"));
184
+ } else {
185
+ const reason = addy.reason ? ` — ${esc(addy.reason)}` : "";
186
+ lines.push(`- **addyosmani/agent-skills**: unavailable${reason}`);
187
+ }
188
+ }
189
+
190
+ if (installed.length > 0) {
191
+ lines.push(`- **OpenSkills installed**: ${installed.map((s) => `\`${esc(s)}\``).join(", ")}`);
192
+ }
193
+
194
+ if (recommended.length > 0) {
195
+ lines.push(`- **OpenSkills recommended** (CLI missing, would-have-used): ${recommended.map((s) => `\`${esc(s)}\``).join(", ")}`);
196
+ }
197
+
198
+ return lines.join("\n");
199
+ }
200
+
201
+ function renderJournalLinks(files) {
202
+ if (!Array.isArray(files) || files.length === 0) return "_No additional journal files._";
203
+ return files.map((f) => `- [${esc(f)}](./${f})`).join("\n");
204
+ }
205
+
206
+ /**
207
+ * Build the summary.md content.
208
+ *
209
+ * @param {SummaryInput} input
210
+ * @returns {string}
211
+ */
212
+ export function buildSummaryMarkdown(input) {
213
+ const sessionId = input.sessionId || "(unknown)";
214
+ const result = resultBadge(input.result);
215
+ const startedAt = input.startedAt || "(unknown)";
216
+ const finishedAt = input.finishedAt || new Date().toISOString();
217
+
218
+ const sections = [
219
+ `# Session summary — ${sessionId}`,
220
+ "",
221
+ `- **Result**: ${result}`,
222
+ `- **Task**: ${esc(input.task || "(no task)")}`,
223
+ `- **Iterations**: ${input.iterations ?? 0}`,
224
+ `- **Duration**: ${formatDuration(input.durationMs)}`,
225
+ `- **Budget**: ${formatBudget(input.budget)}`,
226
+ `- **Started**: ${startedAt}`,
227
+ `- **Finished**: ${finishedAt}`,
228
+ ];
229
+
230
+ if (Number.isFinite(input.brainDecisions) && input.brainDecisions > 0) {
231
+ sections.push(`- **Brain decisions**: ${input.brainDecisions}`);
232
+ }
233
+ if (Number.isFinite(input.solomonInvocations) && input.solomonInvocations > 0) {
234
+ sections.push(`- **Solomon invocations**: ${input.solomonInvocations}`);
235
+ }
236
+
237
+ sections.push("", "---", "", "## Stages", "", renderStagesTable(input.stages));
238
+
239
+ const breakdown = renderBreakdownByRole(input.budget?.breakdown_by_role);
240
+ if (breakdown) {
241
+ sections.push("", "## Budget breakdown (by role)", "", breakdown);
242
+ }
243
+
244
+ const cacheHitsSection = renderCacheHits(input.budget);
245
+ if (cacheHitsSection) {
246
+ sections.push("", "## Cache hits", "", cacheHitsSection);
247
+ }
248
+
249
+ const skillsSection = renderSkills(input.skills);
250
+ if (skillsSection) {
251
+ sections.push("", "## Skills Used", "", skillsSection);
252
+ }
253
+
254
+ sections.push("", "## Commits", "", renderCommits(input.commits));
255
+
256
+ // KJC-TSK-0376 — plan adherence metric (deepeval-inspired). Only
257
+ // rendered when the run executed against a known plan and the
258
+ // calculation produced a non-null score (a run with no commits or
259
+ // no files changed yields nulls everywhere → omit the section).
260
+ const planAdherenceSection = renderPlanAdherence(input.planAdherence);
261
+ if (planAdherenceSection) {
262
+ sections.push("", "## Plan adherence", "", planAdherenceSection);
263
+ }
264
+
265
+ sections.push("", "## Journal files", "", renderJournalLinks(input.files));
266
+
267
+ return sections.join("\n") + "\n";
268
+ }
269
+
270
+ function renderPlanAdherence(planAdherence) {
271
+ if (!planAdherence || typeof planAdherence !== "object") return "";
272
+ if (planAdherence.score === null || planAdherence.score === undefined) return "";
273
+ const lines = [`**Score**: ${planAdherence.score}/100`, ""];
274
+ const breakdown = planAdherence.breakdown || {};
275
+ lines.push("| Component | Score | Weight |");
276
+ lines.push("| --- | --- | --- |");
277
+ const rows = [
278
+ ["Commit attribution", breakdown.commit_attribution, "40%"],
279
+ ["Acceptance tests", breakdown.acceptance_tests, "30%"],
280
+ ["Scope discipline", breakdown.scope_discipline, "20%"],
281
+ ["Dependency order", breakdown.dependency_order, "10%"],
282
+ ];
283
+ for (const [label, value, weight] of rows) {
284
+ const cell = value === null || value === undefined ? "n/a" : `${value}/100`;
285
+ lines.push(`| ${label} | ${cell} | ${weight} |`);
286
+ }
287
+ const huScores = Array.isArray(planAdherence.hu_scores) ? planAdherence.hu_scores : [];
288
+ if (huScores.length > 0) {
289
+ const unattributed = huScores.filter((h) => !h.attributed);
290
+ if (unattributed.length > 0) {
291
+ lines.push("", `_${unattributed.length} HU(s) without an attributed commit:_`);
292
+ for (const h of unattributed) {
293
+ lines.push(`- \`${h.huId}\``);
294
+ }
295
+ }
296
+ }
297
+ return lines.join("\n");
298
+ }
299
+
300
+ /**
301
+ * Write summary.md to the given journal directory. Always writes (the file
302
+ * is the entry point; even a barebones session should have one).
303
+ *
304
+ * @param {string} journalDir
305
+ * @param {SummaryInput} input
306
+ * @param {{ logger?: Object }} [options]
307
+ * @returns {Promise<{ written: boolean, path: string|null }>}
308
+ */
309
+ export async function writeSummaryJournal(journalDir, input, options = {}) {
310
+ const filePath = path.join(journalDir, "summary.md");
311
+ try {
312
+ await fs.mkdir(journalDir, { recursive: true });
313
+ await fs.writeFile(filePath, buildSummaryMarkdown(input), "utf8");
314
+ options.logger?.info?.(`Wrote session summary: ${filePath}`);
315
+ return { written: true, path: filePath };
316
+ } catch (err) {
317
+ options.logger?.warn?.(`Failed to write session summary (non-blocking): ${err.message}`);
318
+ return { written: false, path: null };
319
+ }
320
+ }
@@ -0,0 +1,164 @@
1
+ /**
2
+ * Build a directory-grouped tree view of files affected during the session,
3
+ * rendered as `.reviews/{sessionId}/tree.txt`.
4
+ *
5
+ * Acceptance criterion (KJC-TSK-0288):
6
+ * - Given a kj run that modifies files, when the session finishes, then
7
+ * tree.txt contains the tree of affected files (modified/added/deleted)
8
+ * grouped by directory, generated from `git diff --name-status` against
9
+ * the base ref.
10
+ */
11
+
12
+ import fs from "node:fs/promises";
13
+ import path from "node:path";
14
+ import { runCommand } from "../../utils/process.js";
15
+
16
+ const STATUS_LABELS = {
17
+ M: "modified",
18
+ A: "added",
19
+ D: "deleted",
20
+ R: "renamed",
21
+ C: "copied",
22
+ T: "typechange",
23
+ U: "unmerged",
24
+ };
25
+
26
+ /**
27
+ * @typedef {Object} DiffEntry
28
+ * @property {string} file - path relative to repo root
29
+ * @property {string} status - "modified" | "added" | "deleted" | ...
30
+ */
31
+
32
+ /**
33
+ * Parse `git diff --name-status` output into structured entries.
34
+ *
35
+ * @param {string} rawDiff
36
+ * @returns {DiffEntry[]}
37
+ */
38
+ export function parseNameStatus(rawDiff) {
39
+ if (!rawDiff || !rawDiff.trim()) return [];
40
+ const entries = [];
41
+ for (const line of rawDiff.split("\n")) {
42
+ if (!line.trim()) continue;
43
+ const parts = line.split("\t");
44
+ const status = parts[0];
45
+ // Renames and copies report "R<score>\told\tnew". Take the new path.
46
+ const file = parts.length >= 3 ? parts[2] : parts[1];
47
+ if (!status || !file) continue;
48
+ const key = status[0];
49
+ const label = STATUS_LABELS[key] || "other";
50
+ entries.push({ file, status: label });
51
+ }
52
+ return entries;
53
+ }
54
+
55
+ /**
56
+ * Group entries into a nested directory tree.
57
+ * Each node is { name, children: Map<string, node>, entries: DiffEntry[] }.
58
+ *
59
+ * @param {DiffEntry[]} entries
60
+ * @returns {{name:string, children:Map<string, any>, files:DiffEntry[]}}
61
+ */
62
+ export function buildTree(entries) {
63
+ const root = { name: "", children: new Map(), files: [] };
64
+ for (const entry of entries) {
65
+ const parts = entry.file.split("/");
66
+ let node = root;
67
+ for (let i = 0; i < parts.length - 1; i++) {
68
+ const dir = parts[i];
69
+ if (!node.children.has(dir)) {
70
+ node.children.set(dir, { name: dir, children: new Map(), files: [] });
71
+ }
72
+ node = node.children.get(dir);
73
+ }
74
+ node.files.push({ file: parts.at(-1), status: entry.status });
75
+ }
76
+ return root;
77
+ }
78
+
79
+ /**
80
+ * Render a tree node as indented text. Directories come before files at each
81
+ * level; both are sorted alphabetically (case-insensitive).
82
+ */
83
+ function renderNode(node, depth, lines) {
84
+ const indent = " ".repeat(depth);
85
+ const dirs = Array.from(node.children.values()).sort((a, b) => a.name.localeCompare(b.name, undefined, { sensitivity: "base" }));
86
+ for (const dir of dirs) {
87
+ lines.push(`${indent}${dir.name}/`);
88
+ renderNode(dir, depth + 1, lines);
89
+ }
90
+ const files = [...node.files].sort((a, b) => a.file.localeCompare(b.file, undefined, { sensitivity: "base" }));
91
+ for (const f of files) {
92
+ lines.push(`${indent}${f.file} [${f.status}]`);
93
+ }
94
+ }
95
+
96
+ /**
97
+ * Render the tree as a self-describing text document.
98
+ * Returns null when there are no entries.
99
+ *
100
+ * @param {DiffEntry[]} entries
101
+ * @returns {string|null}
102
+ */
103
+ export function renderTree(entries) {
104
+ if (!entries || entries.length === 0) return null;
105
+ const tree = buildTree(entries);
106
+ const lines = ["# Affected files (grouped by directory)", ""];
107
+ renderNode(tree, 0, lines);
108
+ lines.push("");
109
+
110
+ // Summary counts at the bottom for quick scanning.
111
+ const counts = entries.reduce((acc, e) => {
112
+ acc[e.status] = (acc[e.status] || 0) + 1;
113
+ return acc;
114
+ }, {});
115
+ const summary = Object.entries(counts)
116
+ .sort(([a], [b]) => a.localeCompare(b))
117
+ .map(([status, n]) => `${n} ${status}`)
118
+ .join(", ");
119
+ lines.push(`Total: ${entries.length} file${entries.length === 1 ? "" : "s"} — ${summary}`);
120
+ return lines.join("\n");
121
+ }
122
+
123
+ /**
124
+ * Run `git diff --name-status <baseRef>...HEAD` and return structured entries.
125
+ * Returns [] if git exits with an error or produces no output.
126
+ *
127
+ * @param {string} baseRef
128
+ * @returns {Promise<DiffEntry[]>}
129
+ */
130
+ export async function collectAffectedFiles(baseRef) {
131
+ if (!baseRef) return [];
132
+ try {
133
+ const result = await runCommand("git", ["diff", "--name-status", `${baseRef}...HEAD`]);
134
+ if (result.exitCode !== 0) return [];
135
+ return parseNameStatus(result.stdout || "");
136
+ } catch {
137
+ return [];
138
+ }
139
+ }
140
+
141
+ /**
142
+ * High-level: generate the tree content and persist it to `tree.txt` under
143
+ * the given journal directory. Returns `{ written, path }`.
144
+ *
145
+ * @param {string} journalDir
146
+ * @param {string} baseRef
147
+ * @param {{ logger?: Object }} [options]
148
+ * @returns {Promise<{ written: boolean, path: string|null }>}
149
+ */
150
+ export async function writeTreeJournal(journalDir, baseRef, options = {}) {
151
+ const entries = await collectAffectedFiles(baseRef);
152
+ const content = renderTree(entries);
153
+ if (!content) return { written: false, path: null };
154
+ const filePath = path.join(journalDir, "tree.txt");
155
+ try {
156
+ await fs.mkdir(journalDir, { recursive: true });
157
+ await fs.writeFile(filePath, content + "\n", "utf8");
158
+ options.logger?.info?.(`Wrote file tree journal: ${filePath}`);
159
+ return { written: true, path: filePath };
160
+ } catch (err) {
161
+ options.logger?.warn?.(`Failed to write tree journal (non-blocking): ${err.message}`);
162
+ return { written: false, path: null };
163
+ }
164
+ }
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Session-journal writer shared by every terminal path (KJC-BUG-0084).
3
+ *
4
+ * Pre-fix, the iterations/decisions/tree/summary block lived inline in
5
+ * finalizeApprovedSession(), so a run that died on a stage error
6
+ * (sonar_repeat, gh pr create failure, thrown stage) left only triage.md
7
+ * behind — the Cache hits table, the budget breakdown and the commit list
8
+ * vanished exactly on the runs where they matter most. This module is the
9
+ * single writer; the approved path calls it with its enriched extras and
10
+ * flow-runner's `finally` calls it best-effort for every other ending.
11
+ *
12
+ * Never throws: a journal failure must not mask the run's real result.
13
+ */
14
+
15
+ import { writeIterationsJournal } from "../../orchestrator/session-journal.js";
16
+ import { listCommitsBetween } from "../../utils/git.js";
17
+ import { writeDecisionsJournal } from "./decisions-writer.js";
18
+ import { writeTreeJournal } from "./tree-writer.js";
19
+ import { writeSummaryJournal } from "./summary-writer.js";
20
+
21
+ /**
22
+ * Write iterations.md, decisions.md, tree.txt and summary.md for a session.
23
+ *
24
+ * @param {object} args
25
+ * @param {object} args.session - live session (needs _journalDir to write)
26
+ * @param {{info?: Function, warn?: Function}} [args.logger]
27
+ * @param {string} [args.result] - summary badge: APPROVED | FAILED | STOPPED…
28
+ * @param {number} [args.iterations]
29
+ * @param {object|null} [args.budget] - budgetSummary() snapshot
30
+ * @param {object} [args.stages] - stageResults map
31
+ * @param {Array} [args.commits] - precomputed commit list; computed from
32
+ * session_start_sha when omitted
33
+ * @param {object|null} [args.planAdherence]
34
+ * @returns {Promise<{written: boolean, reason?: string}>}
35
+ */
36
+ export async function writeSessionJournal({ session, logger, result = "APPROVED", iterations = 0, budget = null, stages = {}, commits = null, planAdherence = null }) {
37
+ const journalDir = session?._journalDir;
38
+ if (!journalDir) return { written: false, reason: "no journal dir" };
39
+
40
+ try {
41
+ await writeIterationsJournal(journalDir, session._journalIterations || []);
42
+ const decisionsResult = await writeDecisionsJournal(session, { journalDir, logger });
43
+ const treeResult = await writeTreeJournal(journalDir, session.session_start_sha, { logger });
44
+
45
+ const journalFiles = [...(session._journalFiles || [])];
46
+ if (session._journalIterations?.length) journalFiles.push("iterations.md");
47
+ if (decisionsResult.written) journalFiles.push("decisions.md");
48
+ if (treeResult.written) journalFiles.push("tree.txt");
49
+
50
+ // Commit range from session start so the summary shows every commit
51
+ // the run produced, not just the post-loop scaffold (2026-05-07
52
+ // dogfooding). try/catch tolerates promise rejection AND a sync
53
+ // undefined return from a resetAllMocks-stripped test mock.
54
+ let summaryCommits = Array.isArray(commits) ? commits : null;
55
+ if (!summaryCommits) {
56
+ try { summaryCommits = (await listCommitsBetween(session.head_at_start || session.session_start_sha)) || []; }
57
+ catch { summaryCommits = []; }
58
+ }
59
+
60
+ const startedAt = session._startedAt ? new Date(session._startedAt).toISOString() : undefined;
61
+ await writeSummaryJournal(journalDir, {
62
+ task: session.task,
63
+ result,
64
+ sessionId: session.id,
65
+ iterations,
66
+ durationMs: Date.now() - (session._startedAt || Date.now()),
67
+ budget,
68
+ stages,
69
+ commits: summaryCommits,
70
+ files: journalFiles,
71
+ startedAt,
72
+ finishedAt: new Date().toISOString(),
73
+ brainDecisions: Array.isArray(session.brainDecisions) ? session.brainDecisions.length : 0,
74
+ solomonInvocations: Array.isArray(session.solomonRulings) ? session.solomonRulings.length : 0,
75
+ skills: {
76
+ addyosmani: session.addyosmaniSkills,
77
+ installed: session.autoInstalledSkills,
78
+ recommended: session.skillsRecommended,
79
+ },
80
+ planAdherence,
81
+ }, { logger });
82
+ session._journalWritten = true;
83
+ logger?.info?.(`Session journal written to ${journalDir}`);
84
+ return { written: true };
85
+ } catch (err) {
86
+ logger?.warn?.(`Journal write failed (non-blocking): ${err.message}`);
87
+ return { written: false, reason: err.message };
88
+ }
89
+ }