karajan-code 4.70.4 → 5.0.1

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 (390) hide show
  1. package/README.md +2 -2
  2. package/package.json +6 -14
  3. package/packages/hu-board/package.json +1 -1
  4. package/packages/hu-board/public/app.js +4 -18
  5. package/packages/hu-board/public/index.html +5 -2
  6. package/packages/hu-board/public/styles.css +26 -0
  7. package/packages/hu-board/public/utils/api.js +0 -74
  8. package/packages/hu-board/public/utils/board-tour.js +62 -0
  9. package/packages/hu-board/public/utils/board-view.js +49 -144
  10. package/packages/hu-board/public/utils/command-launcher.js +8 -70
  11. package/packages/hu-board/public/utils/formatters.js +10 -0
  12. package/packages/hu-board/public/utils/governance-view.js +13 -1
  13. package/packages/hu-board/public/utils/hu-actions.js +17 -68
  14. package/packages/hu-board/public/utils/init-listeners.js +7 -8
  15. package/packages/hu-board/public/utils/log-panel.js +3 -16
  16. package/packages/hu-board/public/utils/maggle-mode.js +2 -12
  17. package/packages/hu-board/public/utils/modals.js +7 -0
  18. package/packages/hu-board/public/utils/project-picker-view.js +1 -1
  19. package/packages/hu-board/public/utils/server-push.js +3 -22
  20. package/packages/hu-board/public/utils/shared-board-notice.js +33 -0
  21. package/packages/hu-board/public/utils/story-detail-view.js +5 -19
  22. package/packages/hu-board/src/cleanup-zombies.js +0 -1
  23. package/packages/hu-board/src/command-runner.js +36 -25
  24. package/packages/hu-board/src/db-connection.js +282 -0
  25. package/packages/hu-board/src/db-paths.js +113 -0
  26. package/packages/hu-board/src/db-queries.js +188 -0
  27. package/packages/hu-board/src/db-tombstones.js +51 -0
  28. package/packages/hu-board/src/db.js +28 -619
  29. package/packages/hu-board/src/ephemeral-cleaner.js +2 -3
  30. package/packages/hu-board/src/hu-zombie-reaper.js +5 -1
  31. package/packages/hu-board/src/plan-mutations.js +3 -153
  32. package/packages/hu-board/src/plans-service.js +55 -0
  33. package/packages/hu-board/src/routes/api/commands.js +122 -0
  34. package/packages/hu-board/src/routes/api/plans.js +55 -0
  35. package/packages/hu-board/src/routes/api/projects.js +267 -0
  36. package/packages/hu-board/src/routes/api/prompts.js +135 -0
  37. package/packages/hu-board/src/routes/api/sessions.js +95 -0
  38. package/packages/hu-board/src/routes/api/stories.js +183 -0
  39. package/packages/hu-board/src/routes/api/system.js +241 -0
  40. package/packages/hu-board/src/routes/api/tombstones.js +38 -0
  41. package/packages/hu-board/src/routes/api.js +24 -1371
  42. package/packages/hu-board/src/routes/governance.js +23 -1
  43. package/packages/hu-board/src/routes/lanes.js +40 -0
  44. package/packages/hu-board/src/routes/rag.js +4 -3
  45. package/packages/hu-board/src/server.js +20 -34
  46. package/packages/hu-board/src/sync-files.js +318 -0
  47. package/packages/hu-board/src/sync-project.js +99 -0
  48. package/packages/hu-board/src/sync.js +22 -566
  49. package/packages/hu-board/src/zombie-reaper.js +1 -1
  50. package/scripts/dual-publish.mjs +19 -3
  51. package/scripts/postinstall.js +15 -2
  52. package/scripts/verify-pack-mcp.mjs +11 -7
  53. package/scripts/verify-pack.mjs +4 -4
  54. package/src/audit/audit-history.js +3 -2
  55. package/src/audit/dead-exports.js +68 -59
  56. package/src/audit/deterministic-summary.js +33 -13
  57. package/src/audit/npm-signatures.js +41 -0
  58. package/src/audit/sbom.js +35 -0
  59. package/src/checks/agent-token.js +112 -0
  60. package/src/checks/dir-setup.js +34 -1
  61. package/src/checks/native-build.js +21 -39
  62. package/src/checks/runner.js +128 -142
  63. package/src/cli/advanced-commands.js +6 -6
  64. package/src/cli/register-meta.js +42 -82
  65. package/src/cli/register-pipeline.js +8 -143
  66. package/src/cli/register-plan.js +9 -100
  67. package/src/cli/register-roles-skills.js +1 -1
  68. package/src/cli/retired-commands.js +49 -0
  69. package/src/cli.js +18 -5
  70. package/src/commands/agent-run.js +40 -26
  71. package/src/commands/audit.js +127 -124
  72. package/src/commands/board.js +5 -9
  73. package/src/commands/check.js +29 -16
  74. package/src/commands/doctor.js +2 -0
  75. package/src/commands/env.js +176 -150
  76. package/src/commands/go.js +71 -53
  77. package/src/commands/harden.js +90 -81
  78. package/src/commands/hu-start.js +52 -0
  79. package/src/commands/hu.js +288 -221
  80. package/src/commands/identity.js +111 -78
  81. package/src/commands/init-atril.js +47 -0
  82. package/src/commands/init.js +11 -40
  83. package/src/commands/install-tools.js +70 -85
  84. package/src/commands/main-guard.js +78 -0
  85. package/src/commands/policy.js +226 -184
  86. package/src/commands/qmd.js +27 -21
  87. package/src/commands/rag.js +121 -55
  88. package/src/commands/review-gate.js +421 -341
  89. package/src/commands/skills.js +4 -1
  90. package/src/commands/start.js +4 -5
  91. package/src/commands/steward.js +96 -47
  92. package/src/commands/tournament.js +46 -37
  93. package/src/commands/worktree.js +107 -26
  94. package/src/config/defaults.js +1 -0
  95. package/src/config/loader.js +34 -17
  96. package/src/config/role-resolver.js +1 -0
  97. package/src/config/schema.js +1 -0
  98. package/src/config/secrets.js +36 -0
  99. package/src/config.js +1 -0
  100. package/src/environment/adr.js +16 -2
  101. package/src/git/karajan-label.js +20 -8
  102. package/src/guards/main-guard.js +54 -0
  103. package/src/harden/hook-templates.js +16 -1
  104. package/src/harden/sentinel/posttooluse.mjs +18 -6
  105. package/src/harden/sentinel/pretooluse-sentinel.mjs +64 -36
  106. package/src/harden/sentinel/sentinel-lib.mjs +129 -26
  107. package/src/harden/sentinel/sentinel-shell.mjs +5 -16
  108. package/src/harden/sentinel/sessionstart.mjs +3 -2
  109. package/src/harden/sentinel/stop.mjs +5 -4
  110. package/src/harden/workflow-templates.js +1 -1
  111. package/src/hu/board-lookup.js +29 -0
  112. package/src/hu/gh-identity.js +23 -0
  113. package/src/hu/github-board.js +4 -2
  114. package/src/hu/lane-prune.js +83 -13
  115. package/src/hu/lane-setup.js +65 -0
  116. package/src/hu/lanes.js +66 -0
  117. package/src/hu/team-board-mirror.js +3 -2
  118. package/src/infrastructure/command-runner.js +1 -1
  119. package/src/infrastructure/file-system-service.js +1 -1
  120. package/src/mcp/handlers/direct-handlers.js +2 -292
  121. package/src/mcp/handlers/hu-handlers.js +1 -35
  122. package/src/mcp/handlers/management-handlers.js +2 -42
  123. package/src/mcp/handlers/rag-handler.js +9 -1
  124. package/src/mcp/server-handlers.js +16 -22
  125. package/src/mcp/tools.js +1 -196
  126. package/src/plan/lane-plans.js +54 -0
  127. package/src/plan/plan-store.js +7 -4
  128. package/src/policy/add.js +26 -12
  129. package/src/policy/adr-number-check.js +31 -0
  130. package/src/prompts/audit.js +299 -339
  131. package/src/prompts/card-context.js +10 -5
  132. package/src/prompts/reviewer.js +5 -2
  133. package/src/rag/auto-update.js +71 -44
  134. package/src/rag/bootstrap-index.js +46 -54
  135. package/src/rag/indexer.js +9 -4
  136. package/src/rag/migrate.js +1 -1
  137. package/src/rag/onnx-fallback.js +2 -2
  138. package/src/rag/pid-lease.js +181 -0
  139. package/src/rag/project-store.js +2 -12
  140. package/src/review/card-first.js +57 -46
  141. package/src/review/gate-gitignore.js +23 -4
  142. package/src/review/gate-hook.js +12 -4
  143. package/src/review/one-shot-review.js +45 -35
  144. package/src/review/publish-pr.js +14 -2
  145. package/src/review/repo-docs.js +73 -0
  146. package/src/review/repo-stack.js +59 -0
  147. package/src/review/reviewer-fallback.js +19 -4
  148. package/src/review/seal-commit.js +29 -0
  149. package/src/review/sonar-pregate.js +59 -44
  150. package/src/review/third-party-review.js +90 -16
  151. package/src/review/third-party-size.js +43 -0
  152. package/src/review/third-party-skills.js +54 -0
  153. package/src/review/verify-pr.js +1 -24
  154. package/src/roles/audit-role.js +106 -125
  155. package/src/skills/atril-cli.js +19 -1
  156. package/src/skills/atril-skills.js +5 -4
  157. package/src/skills/skills-search.js +72 -0
  158. package/src/skills/translate.js +62 -0
  159. package/src/sonar/scanner.js +116 -101
  160. package/src/steward/invariants.js +5 -4
  161. package/src/steward/phantom-sweep.js +66 -0
  162. package/src/tournament/judge.js +60 -53
  163. package/src/utils/gh-account.js +37 -0
  164. package/src/utils/git.js +0 -13
  165. package/src/utils/home-migration.js +7 -1
  166. package/src/utils/main-checkout.js +53 -0
  167. package/src/utils/qmd-collection.js +3 -1
  168. package/src/utils/welcome.js +3 -3
  169. package/templates/{skills → atril/commands}/kj-architect.md +5 -0
  170. package/templates/{skills → atril/commands}/kj-audit.md +5 -0
  171. package/templates/{skills → atril/commands}/kj-board.md +5 -0
  172. package/templates/{skills → atril/commands}/kj-code.md +5 -0
  173. package/templates/{skills → atril/commands}/kj-csv-transform.md +5 -0
  174. package/templates/{skills → atril/commands}/kj-data-report.md +5 -0
  175. package/templates/{skills → atril/commands}/kj-discover.md +5 -0
  176. package/templates/{skills → atril/commands}/kj-rag-query.md +5 -0
  177. package/templates/{skills → atril/commands}/kj-review.md +5 -0
  178. package/templates/{skills → atril/commands}/kj-security.md +5 -0
  179. package/templates/{skills → atril/commands}/kj-sonar.md +5 -0
  180. package/templates/{skills → atril/commands}/kj-sql-analysis.md +5 -0
  181. package/templates/{skills → atril/commands}/kj-test.md +5 -0
  182. package/packages/hu-board/public/utils/run-launcher.js +0 -169
  183. package/packages/hu-board/src/run-tracker.js +0 -121
  184. package/src/activity-log.js +0 -59
  185. package/src/agents/host-agent.js +0 -38
  186. package/src/agents/model-registry.js +0 -142
  187. package/src/audit/plan-adherence.js +0 -224
  188. package/src/autonomy/arbiter-role.js +0 -71
  189. package/src/autonomy/arbiter.js +0 -22
  190. package/src/autonomy/decider.js +0 -18
  191. package/src/autonomy/decision-resolver.js +0 -58
  192. package/src/autonomy/outcome-report.js +0 -55
  193. package/src/autonomy/stage-ask.js +0 -30
  194. package/src/brain/decision-tracker.js +0 -125
  195. package/src/brain/decisor.js +0 -243
  196. package/src/brain/solomon-consult.js +0 -171
  197. package/src/brain/standby-scheduler.js +0 -8
  198. package/src/budget/comparison.js +0 -96
  199. package/src/canvas/parse-md.js +0 -238
  200. package/src/canvas/schema.js +0 -101
  201. package/src/canvas/to-flat.js +0 -85
  202. package/src/canvas/validate.js +0 -163
  203. package/src/ci/dispatch.js +0 -99
  204. package/src/ci/index.js +0 -3
  205. package/src/ci/pr-diff.js +0 -26
  206. package/src/cli/register-standby.js +0 -26
  207. package/src/commands/architect.js +0 -111
  208. package/src/commands/autorun.js +0 -49
  209. package/src/commands/researcher.js +0 -54
  210. package/src/commands/resume.js +0 -72
  211. package/src/commands/review.js +0 -89
  212. package/src/commands/run.js +0 -185
  213. package/src/commands/standby.js +0 -117
  214. package/src/commands/status.js +0 -36
  215. package/src/commands/triage.js +0 -78
  216. package/src/commands/undo.js +0 -62
  217. package/src/domains/domain-loader.js +0 -245
  218. package/src/domains/domain-registry.js +0 -140
  219. package/src/domains/domain-synthesizer.js +0 -129
  220. package/src/git/automation.js +0 -433
  221. package/src/git/coder-commit-guard.js +0 -40
  222. package/src/git/hu-automation.js +0 -243
  223. package/src/git/hu-snapshot.js +0 -10
  224. package/src/git/symlink-targets.js +0 -57
  225. package/src/golden/asserter.js +0 -92
  226. package/src/golden/loader.js +0 -52
  227. package/src/golden/runner.js +0 -92
  228. package/src/golden/schema.js +0 -41
  229. package/src/guards/duplicate-members.js +0 -86
  230. package/src/guards/intent-guard.js +0 -161
  231. package/src/guards/perf-guard.js +0 -126
  232. package/src/guards/policy-guard.js +0 -90
  233. package/src/guards/policy-resolver.js +0 -85
  234. package/src/guards/secret-redactor.js +0 -71
  235. package/src/hu/acceptance-runner.js +0 -138
  236. package/src/hu/lazy-planner.js +0 -109
  237. package/src/hu/parallel-executor.js +0 -94
  238. package/src/hu/routing-metrics.js +0 -17
  239. package/src/hu/split-validator.js +0 -143
  240. package/src/hu/splitting-detector.js +0 -158
  241. package/src/hu/splitting-generator.js +0 -175
  242. package/src/hu/store.js +0 -394
  243. package/src/infrastructure/mocks.js +0 -182
  244. package/src/mcp/handlers/run-handler.js +0 -318
  245. package/src/mcp/sovereignty-guard.js +0 -113
  246. package/src/mcp/tool-arg-normalizers.js +0 -16
  247. package/src/mutate/reviewer-signal.js +0 -76
  248. package/src/orchestrator/agent-fallback.js +0 -81
  249. package/src/orchestrator/brain-coordinator.js +0 -186
  250. package/src/orchestrator/ci-integration.js +0 -139
  251. package/src/orchestrator/config-init.js +0 -426
  252. package/src/orchestrator/direct-actions.js +0 -217
  253. package/src/orchestrator/drivers/error-recovery.js +0 -287
  254. package/src/orchestrator/drivers/init-context.js +0 -238
  255. package/src/orchestrator/drivers/iteration-loop.js +0 -382
  256. package/src/orchestrator/drivers/iteration-phases/coder-and-refactorer.js +0 -69
  257. package/src/orchestrator/drivers/iteration-phases/guards.js +0 -91
  258. package/src/orchestrator/drivers/iteration-phases/handle-approved.js +0 -29
  259. package/src/orchestrator/drivers/iteration-phases/quality-gates.js +0 -125
  260. package/src/orchestrator/drivers/iteration-phases/reviewer-gate.js +0 -62
  261. package/src/orchestrator/drivers/post-loop.js +0 -404
  262. package/src/orchestrator/drivers/pre-loop-phases/auto-hu-batch.js +0 -137
  263. package/src/orchestrator/drivers/pre-loop-phases/config-deprecations.js +0 -47
  264. package/src/orchestrator/drivers/pre-loop-phases/ensure-addyosmani-skills.js +0 -84
  265. package/src/orchestrator/drivers/pre-loop-phases/inject-loaded-plan.js +0 -393
  266. package/src/orchestrator/drivers/pre-loop.js +0 -524
  267. package/src/orchestrator/drivers/run-hu-batch.js +0 -468
  268. package/src/orchestrator/feedback-enrichment.js +0 -140
  269. package/src/orchestrator/feedback-queue.js +0 -151
  270. package/src/orchestrator/flow-control.js +0 -170
  271. package/src/orchestrator/flow-runner.js +0 -365
  272. package/src/orchestrator/fs-leak-detector.js +0 -228
  273. package/src/orchestrator/hu-scheduler.js +0 -114
  274. package/src/orchestrator/hu-sub-pipeline.js +0 -642
  275. package/src/orchestrator/iteration-gate.js +0 -73
  276. package/src/orchestrator/iteration-stages.js +0 -9
  277. package/src/orchestrator/parallel-limiter.js +0 -74
  278. package/src/orchestrator/pipeline-context.js +0 -72
  279. package/src/orchestrator/post-loop-stages.js +0 -468
  280. package/src/orchestrator/pre-loop-stages.js +0 -11
  281. package/src/orchestrator/preflight-checks.js +0 -487
  282. package/src/orchestrator/repair/repair-detector.js +0 -117
  283. package/src/orchestrator/repair/repair-runner.js +0 -142
  284. package/src/orchestrator/reviewer-fallback.js +0 -45
  285. package/src/orchestrator/role-output-compressor.js +0 -189
  286. package/src/orchestrator/session-journal.js +0 -308
  287. package/src/orchestrator/solomon-escalation.js +0 -331
  288. package/src/orchestrator/solomon-rules.js +0 -212
  289. package/src/orchestrator/stages/acceptance-coverage-stage.js +0 -47
  290. package/src/orchestrator/stages/architect-stage.js +0 -172
  291. package/src/orchestrator/stages/coder-stage.js +0 -506
  292. package/src/orchestrator/stages/domain-curator-stage.js +0 -82
  293. package/src/orchestrator/stages/format-stage.js +0 -61
  294. package/src/orchestrator/stages/hu-reviewer-phases/detect-and-apply-splits.js +0 -127
  295. package/src/orchestrator/stages/hu-reviewer-stage.js +0 -419
  296. package/src/orchestrator/stages/perf-stage.js +0 -140
  297. package/src/orchestrator/stages/planner-stage.js +0 -85
  298. package/src/orchestrator/stages/rag-context-stage.js +0 -80
  299. package/src/orchestrator/stages/rag-preload-decisor.js +0 -58
  300. package/src/orchestrator/stages/research-stage.js +0 -69
  301. package/src/orchestrator/stages/reviewer-stage.js +0 -431
  302. package/src/orchestrator/stages/sonar-stage.js +0 -439
  303. package/src/orchestrator/stages/stage-classes.js +0 -84
  304. package/src/orchestrator/stages/stage-executor.js +0 -155
  305. package/src/orchestrator/stages/suite-green-stage.js +0 -62
  306. package/src/orchestrator/stages/tdd-discipline-stage.js +0 -56
  307. package/src/orchestrator/stages/tool-judge-stage.js +0 -53
  308. package/src/orchestrator/stages/triage-stage.js +0 -172
  309. package/src/orchestrator/standby.js +0 -71
  310. package/src/orchestrator/verification-gate.js +0 -183
  311. package/src/orchestrator.js +0 -22
  312. package/src/plan/adr-generator.js +0 -170
  313. package/src/plan/adr-loader.js +0 -60
  314. package/src/plan/plan-executor.js +0 -100
  315. package/src/plan/plan-validation.js +0 -4
  316. package/src/prompts/acceptance-coverage.js +0 -32
  317. package/src/prompts/arbiter.js +0 -38
  318. package/src/prompts/architect.js +0 -103
  319. package/src/prompts/hu-reviewer.js +0 -244
  320. package/src/prompts/tool-correctness-judge.js +0 -31
  321. package/src/prompts/triage.js +0 -57
  322. package/src/rag/embedder.js +0 -2
  323. package/src/rag/embedders/_cloud-base.js +0 -2
  324. package/src/rag/embedders/cohere.js +0 -2
  325. package/src/rag/embedders/mistral.js +0 -2
  326. package/src/rag/embedders/onnx.js +0 -2
  327. package/src/rag/embedders/openai.js +0 -2
  328. package/src/rag/embedders/voyage.js +0 -2
  329. package/src/rag/rerank.js +0 -4
  330. package/src/rag/where-parser.js +0 -4
  331. package/src/repeat-detector.js +0 -88
  332. package/src/review/diff-generator.js +0 -112
  333. package/src/review/git-stash-helper.js +0 -104
  334. package/src/review/schema.js +0 -31
  335. package/src/review/scope-filter.js +0 -152
  336. package/src/review/snapshot-diff.js +0 -122
  337. package/src/review/tdd-discipline.js +0 -90
  338. package/src/review/tdd-policy.js +0 -69
  339. package/src/roles/acceptance-coverage-role.js +0 -78
  340. package/src/roles/architect-role.js +0 -77
  341. package/src/roles/coder-role.js +0 -113
  342. package/src/roles/commiter-role.js +0 -113
  343. package/src/roles/domain-curator-role.js +0 -134
  344. package/src/roles/hu-reviewer-role.js +0 -64
  345. package/src/roles/impeccable-role.js +0 -85
  346. package/src/roles/index.js +0 -18
  347. package/src/roles/karajan-brain-role.js +0 -134
  348. package/src/roles/perf-role.js +0 -122
  349. package/src/roles/planner-role.js +0 -151
  350. package/src/roles/refactorer-role.js +0 -30
  351. package/src/roles/repairer-role.js +0 -181
  352. package/src/roles/researcher-role.js +0 -70
  353. package/src/roles/reviewer-role.js +0 -115
  354. package/src/roles/security-role.js +0 -73
  355. package/src/roles/solomon-role.js +0 -271
  356. package/src/roles/sonar-role.js +0 -72
  357. package/src/roles/tester-role.js +0 -235
  358. package/src/roles/tool-correctness-judge-role.js +0 -78
  359. package/src/roles/triage-role.js +0 -99
  360. package/src/session/journal/decisions-writer.js +0 -200
  361. package/src/session/journal/iteration-logger.js +0 -194
  362. package/src/session/journal/summary-writer.js +0 -320
  363. package/src/session/journal/tree-writer.js +0 -164
  364. package/src/session/journal/write-all.js +0 -89
  365. package/src/session-cleanup.js +0 -116
  366. package/src/skills/semantic-detector.js +0 -167
  367. package/src/skills/skill-detector.js +0 -385
  368. package/src/sonar/cloud-scanner.js +0 -78
  369. package/src/tracker-bootstrap.js +0 -44
  370. package/src/types/index.js +0 -38
  371. package/src/types/policy.js +0 -43
  372. package/src/types/solomon.js +0 -87
  373. package/src/utils/async-lock.js +0 -31
  374. package/src/utils/budget.js +0 -229
  375. package/src/utils/cwd-confirm.js +0 -39
  376. package/src/utils/display/event-handlers.js +0 -403
  377. package/src/utils/display/formatters.js +0 -132
  378. package/src/utils/display/header.js +0 -47
  379. package/src/utils/display/session-summary.js +0 -118
  380. package/src/utils/display/solomon.js +0 -42
  381. package/src/utils/pricing.js +0 -29
  382. package/src/utils/quota-simulator.js +0 -56
  383. package/src/utils/role-assigner.js +0 -137
  384. package/src/utils/rtk-wrapper.js +0 -87
  385. package/src/utils/run-registry.js +0 -9
  386. package/src/utils/status-dashboard.js +0 -254
  387. package/src/utils/tool-call-extractor.js +0 -56
  388. package/src/webperf/devtools-detect.js +0 -112
  389. package/src/webperf/webperf-role-integration.js +0 -66
  390. package/templates/skills/kj-run.md +0 -73
@@ -1,132 +0,0 @@
1
- export const ANSI = {
2
- reset: "\x1b[0m",
3
- bold: "\x1b[1m",
4
- dim: "\x1b[2m",
5
- cyan: "\x1b[36m",
6
- green: "\x1b[32m",
7
- yellow: "\x1b[33m",
8
- red: "\x1b[31m",
9
- gray: "\x1b[90m",
10
- white: "\x1b[37m",
11
- magenta: "\x1b[35m"
12
- };
13
-
14
- export const ICONS = {
15
- "session:start": "\u25b6",
16
- "planner:start": "\ud83e\udde0",
17
- "planner:end": "\ud83e\udde0",
18
- "researcher:start": "\ud83d\udd2c",
19
- "researcher:end": "\ud83d\udd2c",
20
- "iteration:start": "\u25b6",
21
- "coder:start": "\ud83d\udd28",
22
- "coder:end": "\ud83d\udd28",
23
- "refactorer:start": "\u267b\ufe0f",
24
- "refactorer:end": "\u267b\ufe0f",
25
- "tdd:result": "\ud83d\udccb",
26
- "sonar:start": "\ud83d\udd0d",
27
- "sonar:end": "\ud83d\udd0d",
28
- "reviewer:start": "\ud83d\udc41\ufe0f",
29
- "reviewer:end": "\ud83d\udc41\ufe0f",
30
- "tester:start": "\ud83e\uddea",
31
- "tester:end": "\ud83e\uddea",
32
- "security:start": "\ud83d\udd12",
33
- "security:end": "\ud83d\udd12",
34
- "solomon:start": "\u2696\ufe0f",
35
- "solomon:end": "\u2696\ufe0f",
36
- "solomon:escalate": "\u26a0\ufe0f",
37
- "agent:heartbeat": "\u23f3",
38
- "coder:standby": "\u23f3",
39
- "coder:standby_heartbeat": "\u23f3",
40
- "coder:standby_resume": "\u25b6\ufe0f",
41
- "budget:update": "\ud83d\udcb8",
42
- "iteration:end": "\u23f1\ufe0f",
43
- "session:end": "\ud83c\udfc1",
44
- "discover:start": "\ud83d\udd0e",
45
- "discover:end": "\ud83d\udd0e",
46
- "architect:start": "\ud83c\udfdb\ufe0f",
47
- "architect:end": "\ud83c\udfdb\ufe0f",
48
- "hu-reviewer:start": "\ud83d\udcdd",
49
- "hu-reviewer:end": "\ud83d\udcdd",
50
- "impeccable:start": "\ud83c\udfa8",
51
- "impeccable:end": "\ud83c\udfa8",
52
- "audit:start": "\ud83d\udccb",
53
- "audit:end": "\ud83d\udccb",
54
- "sonarcloud:start": "\u2601\ufe0f",
55
- "sonarcloud:end": "\u2601\ufe0f",
56
- "preflight:start": "\ud83d\udee1\ufe0f",
57
- "preflight:end": "\ud83d\udee1\ufe0f",
58
- question: "\u2753"
59
- };
60
-
61
- export const STATUS_ICON = {
62
- ok: `${ANSI.green}\u2705${ANSI.reset}`,
63
- fail: `${ANSI.red}\u274c${ANSI.reset}`,
64
- paused: `${ANSI.yellow}\u23f8\ufe0f${ANSI.reset}`,
65
- running: `${ANSI.cyan}\u25b6${ANSI.reset}`
66
- };
67
-
68
- export const TRACKER_STATUS = {
69
- done: { icon: "\u2713", color: ANSI.green },
70
- running: { icon: "\u25b6", color: ANSI.cyan },
71
- failed: { icon: "\u2717", color: ANSI.red }
72
- };
73
-
74
- export const TRACKER_DEFAULT = { icon: "\u00b7", color: ANSI.dim };
75
-
76
- /**
77
- * Format milliseconds into MM:SS string
78
- * @param {number} ms
79
- * @returns {string}
80
- */
81
- export function formatElapsed(ms) {
82
- const totalSec = Math.floor((ms || 0) / 1000);
83
- const min = String(Math.floor(totalSec / 60)).padStart(2, "0");
84
- const sec = String(totalSec % 60).padStart(2, "0");
85
- return `${min}:${sec}`;
86
- }
87
-
88
- /**
89
- * Format executor details into a display string
90
- * @param {Object} detail
91
- * @returns {string}
92
- */
93
- export function formatExecutor(detail) {
94
- if (!detail) return '';
95
- const provider = detail.provider || '';
96
- const type = detail.executorType || '';
97
- if (provider) return ` ${ANSI.dim}${provider}${ANSI.reset}`;
98
- if (type === 'local') return ` ${ANSI.dim}local${ANSI.reset}`;
99
- if (type === 'system') return ` ${ANSI.dim}system${ANSI.reset}`;
100
- return '';
101
- }
102
-
103
- /**
104
- * Calculate budget ANSI color based on usage
105
- * @param {number} max
106
- * @param {number} pct
107
- * @param {number} warn
108
- * @returns {string}
109
- */
110
- export function budgetColor(max, pct, warn) {
111
- if (max > 0 && pct >= 100) return ANSI.red;
112
- if (max > 0 && pct >= warn) return ANSI.yellow;
113
- return ANSI.green;
114
- }
115
-
116
- export function roleStart(icon, label, provider) {
117
- console.log(` \u251c\u2500 ${icon} ${label} (${provider || "?"}) running...`);
118
- }
119
-
120
- export function roleEnd(status, label, elapsed, executor) {
121
- console.log(` \u251c\u2500 ${status} ${label} completed${executor || ''} ${elapsed}`);
122
- }
123
-
124
- export function passFailStage(detail, label, failDefault, elapsed) {
125
- const executor = formatExecutor(detail);
126
- if (detail?.ok === false) {
127
- const summary = detail?.summary || failDefault;
128
- console.log(` \u251c\u2500 ${ANSI.red}\u274c ${label}: ${summary}${ANSI.reset}${executor} ${elapsed}`);
129
- } else {
130
- console.log(` \u251c\u2500 ${ANSI.green}\u2705 ${label}: passed${ANSI.reset}${executor} ${elapsed}`);
131
- }
132
- }
@@ -1,47 +0,0 @@
1
- import path from "node:path";
2
- import { readFileSync } from "node:fs";
3
- import { fileURLToPath } from "node:url";
4
- import { printBanner } from "../banner.js";
5
- import { ANSI } from "./formatters.js";
6
-
7
- const DISPLAY_PKG_PATH = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../../../package.json");
8
- const DISPLAY_VERSION = JSON.parse(readFileSync(DISPLAY_PKG_PATH, "utf8")).version;
9
-
10
- const BAR = `${ANSI.dim}\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500${ANSI.reset}`;
11
-
12
- /**
13
- * Print task, configuration and pipeline header
14
- * @param {Object} params
15
- * @param {string} params.task
16
- * @param {Object} params.config
17
- */
18
- export function printHeader({ task, config }) {
19
- const version = DISPLAY_VERSION;
20
- // Force banner: caller already gates on !jsonMode, so if we're here it's a human-readable run
21
- printBanner(version, { force: true });
22
- console.log(`${ANSI.bold}Task:${ANSI.reset} ${task}`);
23
- console.log(
24
- `${ANSI.bold}Coder:${ANSI.reset} ${config.roles?.coder?.provider || config.coder} ${ANSI.dim}|${ANSI.reset} ${ANSI.bold}Reviewer:${ANSI.reset} ${config.roles?.reviewer?.provider || config.reviewer}`
25
- );
26
- console.log(
27
- `${ANSI.bold}Max iterations:${ANSI.reset} ${config.max_iterations} ${ANSI.dim}|${ANSI.reset} ${ANSI.bold}Timeout:${ANSI.reset} ${config.session.max_total_minutes}min`
28
- );
29
-
30
- const pipeline = config.pipeline || {};
31
- const activeRoles = [];
32
- if (pipeline.planner?.enabled) activeRoles.push(`Planner (${config.roles?.planner?.provider || "?"})`);
33
- if (pipeline.researcher?.enabled) activeRoles.push(`Researcher (${config.roles?.researcher?.provider || "?"})`);
34
- if (pipeline.tester?.enabled) activeRoles.push("Tester");
35
- if (pipeline.security?.enabled) activeRoles.push("Security");
36
- if (pipeline.solomon?.enabled) {
37
- const solomonProvider = config.roles?.solomon?.provider;
38
- activeRoles.push(solomonProvider ? `Solomon (${solomonProvider})` : "Solomon");
39
- }
40
- if (activeRoles.length > 0) {
41
- const separator = ` ${ANSI.dim}|${ANSI.reset} `;
42
- console.log(`${ANSI.bold}Pipeline:${ANSI.reset} ${activeRoles.join(separator)}`);
43
- }
44
-
45
- console.log(BAR);
46
- console.log();
47
- }
@@ -1,118 +0,0 @@
1
- import { ANSI } from "./formatters.js";
2
-
3
- export function printSessionStages(stages) {
4
- if (!stages) return;
5
- if (stages.researcher?.summary) {
6
- console.log(` ${ANSI.dim}\ud83d\udd2c Research: ${stages.researcher.summary}${ANSI.reset}`);
7
- }
8
- printSessionPlanner(stages.planner);
9
- if (stages.tester?.summary) {
10
- console.log(` ${ANSI.dim}\ud83e\uddea Tester: ${stages.tester.summary}${ANSI.reset}`);
11
- }
12
- if (stages.security?.summary) {
13
- console.log(` ${ANSI.dim}\ud83d\udd12 Security: ${stages.security.summary}${ANSI.reset}`);
14
- }
15
- printSessionSonar(stages.sonar);
16
- }
17
-
18
- function printSessionPlanner(planner) {
19
- if (!planner?.title && !planner?.approach && !planner?.completedSteps?.length) return;
20
- const planParts = [];
21
- if (planner.title) planParts.push(planner.title);
22
- if (planner.approach) planParts.push(`approach: ${planner.approach}`);
23
- console.log(` ${ANSI.dim}\ud83d\uddfa Plan: ${planParts.join(" | ")}${ANSI.reset}`);
24
- for (const step of planner.completedSteps || []) {
25
- console.log(` ${ANSI.dim} \u2713 ${step}${ANSI.reset}`);
26
- }
27
- }
28
-
29
- export function printSessionSonar(sonar) {
30
- if (!sonar) return;
31
- // Three buckets so the banner reads correctly:
32
- // - OK \u2192 green (real pass).
33
- // - SKIPPED / PENDING \u2192 gray (informational; sonar
34
- // wasn't gated against, this is NOT a fail). Pre-2026-05-07 N4
35
- // dogfooding these were rendered red, which made a clean run
36
- // look like a sonar failure during the live demo.
37
- // - everything else (ERROR, WARN, ...) \u2192 red (real fail).
38
- let gateLabel;
39
- if (sonar.gateStatus === "OK") gateLabel = ANSI.green;
40
- else if (sonar.gateStatus === "SKIPPED" || sonar.gateStatus === "PENDING") gateLabel = ANSI.gray;
41
- else gateLabel = ANSI.red;
42
- console.log(` ${ANSI.dim}\ud83d\udd0d Sonar: ${gateLabel}${sonar.gateStatus}${ANSI.reset}${ANSI.dim} (${sonar.openIssues ?? 0} issues)${ANSI.reset}`);
43
- if (typeof sonar.issuesInitial === "number" || typeof sonar.issuesResolved === "number") {
44
- const issuesInitial = sonar.issuesInitial ?? sonar.openIssues ?? 0;
45
- const issuesFinal = sonar.issuesFinal ?? sonar.openIssues ?? 0;
46
- const issuesResolved = sonar.issuesResolved ?? Math.max(issuesInitial - issuesFinal, 0);
47
- console.log(` ${ANSI.dim}\ud83d\udee0 Issues: ${issuesInitial} detected, ${issuesFinal} open, ${issuesResolved} resolved${ANSI.reset}`);
48
- }
49
- }
50
-
51
- export function printSessionGit(git) {
52
- if (!git?.branch) return;
53
- const parts = [`branch: ${git.branch}`];
54
- if (git.committed) parts.push("committed");
55
- if (git.pushed) parts.push("pushed");
56
- if (git.pr || git.prUrl) parts.push(`PR: ${git.pr || git.prUrl}`);
57
- console.log(` ${ANSI.dim}\ud83d\udcce Git: ${parts.join(", ")}${ANSI.reset}`);
58
- if (Array.isArray(git.commits) && git.commits.length > 0) {
59
- console.log(` ${ANSI.dim}\ud83e\uddfe Commits:${ANSI.reset}`);
60
- for (const commit of git.commits) {
61
- const shortHash = (commit.hash || "").slice(0, 7) || "unknown";
62
- const message = commit.message || "";
63
- console.log(` ${ANSI.dim} - ${shortHash} ${message}${ANSI.reset}`);
64
- }
65
- }
66
- }
67
-
68
- function isBudgetUnavailable(budget) {
69
- return budget.usage_available === false ||
70
- (budget.total_tokens === 0 && budget.total_cost_usd === 0 && Object.keys(budget.breakdown_by_role || {}).length > 0);
71
- }
72
-
73
- export function printSessionRtkSavings(rtkSavings) {
74
- if (!rtkSavings || !rtkSavings.callCount) return;
75
- const tokens = rtkSavings.estimatedTokensSaved ?? 0;
76
- const ratio = rtkSavings.savedPct ?? 0;
77
- const commands = rtkSavings.callCount ?? 0;
78
- const original = rtkSavings.originalBytes ?? 0;
79
- const compressed = rtkSavings.rtkBytes ?? 0;
80
-
81
- if (tokens === 0 || ratio === 0) {
82
- console.log(` ${ANSI.dim}⚡ RTK: ${commands} commands wrapped, 0% savings — output was already minimal (${original} bytes in, ${compressed} bytes out)${ANSI.reset}`);
83
- } else {
84
- console.log(` ${ANSI.dim}⚡ RTK: saved ~${tokens.toLocaleString()} tokens (${ratio}% compression, ${commands} commands, ${original.toLocaleString()} → ${compressed.toLocaleString()} bytes)${ANSI.reset}`);
85
- }
86
- }
87
-
88
- export function printSessionBudget(budget) {
89
- if (!budget) return;
90
- if (isBudgetUnavailable(budget)) {
91
- console.log(` ${ANSI.dim}\ud83d\udcb0 Budget: N/A (provider does not report usage)${ANSI.reset}`);
92
- return;
93
- }
94
- const estPrefix = budget.includes_estimates ? "~" : "";
95
- const estNote = budget.includes_estimates ? " (includes estimates)" : "";
96
- const fmtTokens = (n) => Number(n || 0).toLocaleString("en-US");
97
- console.log(` ${ANSI.dim}\ud83d\udcb0 Total tokens: ${estPrefix}${fmtTokens(budget.total_tokens)}${estNote}${ANSI.reset}`);
98
- console.log(` ${ANSI.dim}\ud83d\udcb0 Total cost: ${estPrefix}$${Number(budget.total_cost_usd || 0).toFixed(2)}${ANSI.reset}`);
99
- // KJC-TSK-0274: KJ-vs-non-KJ comparison line when compression data exists.
100
- const cmp = budget.kj_comparison;
101
- if (cmp?.hasCompression) {
102
- const wkCost = `$${Number(cmp.withKj?.cost || 0).toFixed(2)}`;
103
- const wkTok = fmtTokens(Number(cmp.withKj?.tokens || 0));
104
- const wnCost = `$${Number(cmp.withoutKj?.cost || 0).toFixed(2)}`;
105
- const wnTok = fmtTokens(Number(cmp.withoutKj?.tokens || 0));
106
- const pct = Math.round(Number(cmp.savedPct || 0));
107
- console.log(` ${ANSI.dim} \u2937 With KJ: ${wkCost} / ${wkTok} tokens${ANSI.reset}`);
108
- console.log(` ${ANSI.dim} \u2937 Without KJ: ~${wnCost} / ~${wnTok} tokens (-${pct}%)${ANSI.reset}`);
109
- }
110
- for (const [role, metrics] of Object.entries(budget.breakdown_by_role || {})) {
111
- const tokens = Number(metrics.total_tokens || 0);
112
- const cost = Number(metrics.total_cost_usd || 0);
113
- if (tokens === 0 && cost === 0) continue; // skip roles with no usage
114
- console.log(
115
- ` ${ANSI.dim} - ${role}: ${estPrefix}${fmtTokens(tokens)} tokens, ${estPrefix}$${cost.toFixed(2)}${ANSI.reset}`
116
- );
117
- }
118
- }
@@ -1,42 +0,0 @@
1
- import { ANSI } from "./formatters.js";
2
-
3
- const SOLOMON_RULING_HANDLERS = {
4
- approve(detail, elapsed) {
5
- const dismissedCount = detail?.dismissed?.length || 0;
6
- const dismissedSuffix = dismissedCount > 0 ? ` (${dismissedCount} dismissed)` : "";
7
- console.log(` \u251c\u2500 ${ANSI.green}\u2696\ufe0f Solomon: APPROVE${dismissedSuffix}${ANSI.reset} ${elapsed}`);
8
- },
9
- approve_with_conditions(detail, elapsed) {
10
- const condCount = detail?.conditions?.length || 0;
11
- console.log(` \u251c\u2500 ${ANSI.yellow}\u2696\ufe0f Solomon: ${condCount} condition${condCount === 1 ? "" : "s"}${ANSI.reset} ${elapsed}`);
12
- if (detail?.conditions) {
13
- for (const cond of detail.conditions) {
14
- console.log(` \u2502 ${ANSI.dim}${cond}${ANSI.reset}`);
15
- }
16
- }
17
- },
18
- escalate_human(detail, elapsed) {
19
- const reason = detail?.escalate_reason || "unknown reason";
20
- console.log(` \u251c\u2500 ${ANSI.red}\u2696\ufe0f Solomon: ESCALATE \u2014 ${reason}${ANSI.reset} ${elapsed}`);
21
- },
22
- create_subtask(detail, elapsed) {
23
- const subtaskTitle = detail?.subtask?.title || "untitled";
24
- console.log(` \u251c\u2500 ${ANSI.magenta}\u2696\ufe0f Solomon: SUBTASK \u2014 ${subtaskTitle}${ANSI.reset} ${elapsed}`);
25
- }
26
- };
27
-
28
- /**
29
- * Print Solomon ruling details
30
- * @param {Object} detail
31
- * @param {string} elapsed
32
- */
33
- export function printSolomonRuling(detail, elapsed) {
34
- const ruling = detail?.ruling || "unknown";
35
- const handler = SOLOMON_RULING_HANDLERS[ruling];
36
- if (handler) {
37
- handler(detail, elapsed);
38
- } else {
39
- const rulingUpper = ruling.toUpperCase().replaceAll("_", " ");
40
- console.log(` \u251c\u2500 \u2696\ufe0f Solomon: ${rulingUpper} ${elapsed}`);
41
- }
42
- }
@@ -1,29 +0,0 @@
1
- import { buildDefaultPricingTable } from "../agents/model-registry.js";
2
-
3
- export const DEFAULT_MODEL_PRICING = buildDefaultPricingTable();
4
-
5
- export function calculateUsageCostUsd({ provider, model, tokens_in, tokens_out, pricing }) {
6
- const table = pricing || DEFAULT_MODEL_PRICING;
7
-
8
- let entry = table[model];
9
-
10
- if (!entry && provider && model) {
11
- entry = table[`${provider}/${model}`];
12
- }
13
-
14
- if (!entry && model && model.includes("/")) {
15
- const [, actualModel] = model.split("/");
16
- entry = table[actualModel];
17
- }
18
-
19
- if (!entry) return 0;
20
-
21
- const inputCost = (tokens_in * entry.input_per_million) / 1_000_000;
22
- const outputCost = (tokens_out * entry.output_per_million) / 1_000_000;
23
- return inputCost + outputCost;
24
- }
25
-
26
- export function mergePricing(defaults, overrides) {
27
- if (!overrides || typeof overrides !== "object") return { ...defaults };
28
- return { ...defaults, ...overrides };
29
- }
@@ -1,56 +0,0 @@
1
- // KJ_SIMULATE_QUOTA — testing hook for the standby flow. See
2
- // docs/quota-simulation.md. KJC-TSK-0493.
3
-
4
- let _warned = false;
5
-
6
- export function parseQuotaSimulationConfig(env = process.env) {
7
- const trigger = env.KJ_SIMULATE_QUOTA;
8
- if (!trigger) return null;
9
- const m = /^after-iter-(\d+)$/i.exec(String(trigger).trim());
10
- if (!m) {
11
- if (!_warned) {
12
- // eslint-disable-next-line no-console
13
- console.warn(`[KJ_SIMULATE_QUOTA] Ignoring malformed value "${trigger}". Expected "after-iter-<N>".`);
14
- _warned = true;
15
- }
16
- return null;
17
- }
18
- return {
19
- afterIter: Number.parseInt(m[1], 10),
20
- resetIso: env.KJ_SIMULATE_QUOTA_RESET || new Date(Date.now() + 3600_000).toISOString(),
21
- agent: String(env.KJ_SIMULATE_QUOTA_AGENT || "claude").toLowerCase(),
22
- };
23
- }
24
-
25
- const SYNTHETIC_MSG = {
26
- claude: (iso) => `[KJ_SIMULATE_QUOTA] Claude Pro usage limit reached. weekly limit. resets at ${iso}`,
27
- codex: () => `[KJ_SIMULATE_QUOTA] You have exceeded your current quota. retry after 60 seconds`,
28
- gemini: () => `[KJ_SIMULATE_QUOTA] Resource exhausted: quota exceeded. retry after 60 seconds`,
29
- };
30
-
31
- export function buildSyntheticQuotaMessage(agent, resetIso) {
32
- return (SYNTHETIC_MSG[agent] || SYNTHETIC_MSG.claude)(resetIso);
33
- }
34
-
35
- export function shouldSimulateQuota({ iteration, agent }, env = process.env) {
36
- const cfg = parseQuotaSimulationConfig(env);
37
- if (!cfg) return null;
38
- if (Number(iteration) < cfg.afterIter) return null;
39
- const a = String(agent || "").toLowerCase();
40
- if (cfg.agent !== "any" && cfg.agent !== a) return null;
41
- return { resetIso: cfg.resetIso, agent: a || cfg.agent };
42
- }
43
-
44
- // Mutates execResult: forces ok=false and prepends the synthetic quota
45
- // line to result.error so the existing detectRateLimit branch fires.
46
- export function applyQuotaSimulation(execResult, { iteration, agent }, env = process.env) {
47
- const fire = shouldSimulateQuota({ iteration, agent }, env);
48
- if (!fire || !execResult || typeof execResult !== "object") return false;
49
- if (!execResult.result || typeof execResult.result !== "object") execResult.result = {};
50
- execResult.result.error = `${buildSyntheticQuotaMessage(fire.agent, fire.resetIso)}\n${execResult.result.error || ""}`;
51
- execResult.ok = false;
52
- return true;
53
- }
54
-
55
- // Test seam — reset the one-shot warning between unit tests.
56
- export function _resetSimulatorWarning() { _warned = false; }
@@ -1,137 +0,0 @@
1
- // Smart role assignment based on available AI agents.
2
- // Used by both kj init (interactive) and auto-init (non-interactive).
3
-
4
- import { detectAvailableAgents } from "./agent-detect.js";
5
-
6
- // Agent capability tiers (higher = more capable for complex reasoning)
7
- const CAPABILITY_TIERS = {
8
- claude: 5, // Best for reasoning, orchestration, complex tasks
9
- codex: 4, // Strong coder, good reviewer
10
- gemini: 3, // Good general purpose
11
- aider: 2, // Good coder, limited reasoning
12
- opencode: 2 // Similar to aider
13
- };
14
-
15
- // Role requirements: what capability level is ideal for each role
16
- const ROLE_PREFERENCES = {
17
- brain: { minTier: 4, prefer: "claude", description: "Karajan Brain (orchestrator)" },
18
- // KJC-BUG-0113: Solomon preferred gemini, but Google retired the Gemini
19
- // Code Assist CLI for individuals — a binary that answers --version yet
20
- // dies with IneligibleTierError on every real call. Any machine with the
21
- // stale CLI on PATH got a judge that could never rule. Claude matches
22
- // the brain default; diversifyReviewer still picks a different agent
23
- // when more than one healthy option exists.
24
- solomon: { minTier: 3, prefer: "claude", description: "Solomon (judge/arbiter)" },
25
- coder: { minTier: 2, prefer: "claude", description: "Coder" },
26
- reviewer: { minTier: 3, prefer: "codex", description: "Reviewer" },
27
- planner: { minTier: 4, prefer: "claude", description: "Planner" },
28
- researcher: { minTier: 3, prefer: "claude", description: "Researcher" },
29
- architect: { minTier: 4, prefer: "claude", description: "Architect" },
30
- tester: { minTier: 3, prefer: "claude", description: "Tester" },
31
- security: { minTier: 3, prefer: "claude", description: "Security" },
32
- triage: { minTier: 3, prefer: "claude", description: "Triage" }
33
- };
34
-
35
- /**
36
- * Assign the best available agent to a role.
37
- * Prefers the role's preferred agent if available, then falls back by capability tier.
38
- */
39
- function assignRole(roleName, availableAgents) {
40
- const pref = ROLE_PREFERENCES[roleName];
41
- if (!pref) return availableAgents[0]?.name || "claude";
42
-
43
- // Preferred agent available?
44
- if (availableAgents.find(a => a.name === pref.prefer)) {
45
- return pref.prefer;
46
- }
47
-
48
- // Sort by capability tier (descending) and pick the best available
49
- const sorted = [...availableAgents].sort(
50
- (a, b) => (CAPABILITY_TIERS[b.name] || 1) - (CAPABILITY_TIERS[a.name] || 1)
51
- );
52
-
53
- return sorted[0]?.name || "claude";
54
- }
55
-
56
- /**
57
- * Try to diversify: if possible, use a different agent for reviewer than coder.
58
- */
59
- function diversifyReviewer(coderAgent, availableAgents) {
60
- const alternatives = availableAgents.filter(a => a.name !== coderAgent);
61
- if (alternatives.length === 0) return coderAgent;
62
-
63
- const sorted = [...alternatives].sort(
64
- (a, b) => (CAPABILITY_TIERS[b.name] || 1) - (CAPABILITY_TIERS[a.name] || 1)
65
- );
66
- return sorted[0].name;
67
- }
68
-
69
- /**
70
- * Auto-assign all roles based on detected agents. Non-interactive.
71
- * Returns a config-ready object with role assignments.
72
- */
73
- export async function autoAssignRoles(logger) {
74
- const agents = await detectAvailableAgents();
75
- const available = agents.filter(a => a.available);
76
-
77
- if (available.length === 0) {
78
- logger?.warn?.("No AI agents detected. Using claude as default for all roles.");
79
- return { assignments: getDefaultAssignments("claude"), agents, available: [] };
80
- }
81
-
82
- logger?.info?.(`Detected ${available.length} AI agent(s): ${available.map(a => `${a.name} (${a.version})`).join(", ")}`);
83
-
84
- const coder = assignRole("coder", available);
85
- const reviewer = available.length > 1 ? diversifyReviewer(coder, available) : coder;
86
- const brain = assignRole("brain", available);
87
- const solomon = available.length > 1 ? diversifyReviewer(brain, available) : brain;
88
-
89
- const assignments = {
90
- brain,
91
- solomon,
92
- coder,
93
- reviewer,
94
- planner: assignRole("planner", available),
95
- researcher: assignRole("researcher", available),
96
- architect: assignRole("architect", available),
97
- tester: assignRole("tester", available),
98
- security: assignRole("security", available),
99
- triage: assignRole("triage", available)
100
- };
101
-
102
- logger?.info?.(`Role assignments: Brain=${brain}, Solomon=${solomon}, Coder=${coder}, Reviewer=${reviewer}`);
103
-
104
- return { assignments, agents, available };
105
- }
106
-
107
- function getDefaultAssignments(agent) {
108
- return {
109
- brain: agent, solomon: agent, coder: agent, reviewer: agent,
110
- planner: agent, researcher: agent, architect: agent,
111
- tester: agent, security: agent, triage: agent
112
- };
113
- }
114
-
115
- /**
116
- * Apply role assignments to a Karajan config object.
117
- */
118
- export function applyRoleAssignments(config, assignments) {
119
- config.coder = assignments.coder;
120
- config.reviewer = assignments.reviewer;
121
-
122
- const roleNames = ["coder", "reviewer", "planner", "researcher", "architect",
123
- "tester", "security", "triage", "solomon"];
124
-
125
- for (const role of roleNames) {
126
- config.roles = config.roles || {};
127
- config.roles[role] = config.roles[role] || {};
128
- config.roles[role].provider = assignments[role] || assignments.coder;
129
- }
130
-
131
- // Brain is a new top-level config (not in roles yet — will be when KarajanBrainRole is implemented)
132
- config.brain = { provider: assignments.brain };
133
-
134
- return config;
135
- }
136
-
137
- export { CAPABILITY_TIERS };
@@ -1,87 +0,0 @@
1
- import { runCommand } from "./process.js";
2
-
3
- /**
4
- * Commands that RTK can safely wrap for token-optimized output.
5
- */
6
- export const RTK_SUPPORTED_COMMANDS = [
7
- "git", "ls", "find", "grep", "cat", "head", "tail",
8
- "wc", "diff", "tree", "du", "file"
9
- ];
10
-
11
- const supportedSet = new Set(RTK_SUPPORTED_COMMANDS);
12
-
13
- /**
14
- * Wrap a command with RTK if available and the command is in the whitelist.
15
- * @param {string} command
16
- * @param {string[]} args
17
- * @param {boolean} rtkAvailable
18
- * @returns {{ command: string, args: string[] }}
19
- */
20
- export function wrapWithRtk(command, args, rtkAvailable) {
21
- if (rtkAvailable && supportedSet.has(command)) {
22
- return { command: "rtk", args: [command, ...args] };
23
- }
24
- return { command, args };
25
- }
26
-
27
- /**
28
- * Session-level accumulator for RTK byte savings.
29
- */
30
- export class RtkSavingsTracker {
31
- constructor() {
32
- this.originalBytes = 0;
33
- this.rtkBytes = 0;
34
- this.callCount = 0;
35
- }
36
-
37
- record(originalSize, rtkSize) {
38
- this.originalBytes += originalSize;
39
- this.rtkBytes += rtkSize;
40
- this.callCount += 1;
41
- }
42
-
43
- summary() {
44
- const savedBytes = this.originalBytes - this.rtkBytes;
45
- const savedPct = this.originalBytes > 0
46
- ? Number(((savedBytes / this.originalBytes) * 100).toFixed(1))
47
- : 0;
48
- const estimatedTokensSaved = Math.floor(savedBytes / 4);
49
- return {
50
- originalBytes: this.originalBytes,
51
- rtkBytes: this.rtkBytes,
52
- savedBytes,
53
- savedPct,
54
- estimatedTokensSaved,
55
- callCount: this.callCount
56
- };
57
- }
58
-
59
- /** Returns true if any commands were recorded. */
60
- hasData() {
61
- return this.callCount > 0;
62
- }
63
- }
64
-
65
- /**
66
- * Create a runner function that transparently wraps supported commands with RTK.
67
- * @param {boolean} rtkAvailable
68
- * @param {RtkSavingsTracker} [tracker] - Optional savings tracker
69
- * @returns {(command: string, args?: string[], options?: object) => Promise<object>}
70
- */
71
- export function createRtkRunner(rtkAvailable, tracker = null) {
72
- return async (command, args = [], options = {}) => {
73
- const wrapped = wrapWithRtk(command, args, rtkAvailable);
74
- const result = await runCommand(wrapped.command, wrapped.args, options);
75
-
76
- if (tracker && rtkAvailable && supportedSet.has(command)) {
77
- const outputSize = Buffer.byteLength(result.stdout || "", "utf8");
78
- // For RTK-wrapped calls, the output is already compressed.
79
- // We estimate the original size as outputSize (conservative — real savings
80
- // would require running the command without RTK, which defeats the purpose).
81
- // The tracker is useful when the caller provides real estimates externally.
82
- tracker.record(outputSize, outputSize);
83
- }
84
-
85
- return result;
86
- };
87
- }
@@ -1,9 +0,0 @@
1
- // Shim: run-registry now lives in karajan-core/run-registry so the
2
- // hu-board workspace can consume it without a relative dep on the CLI
3
- // src tree. KJC-TSK-0511 PR3.
4
- export {
5
- runsDir,
6
- registerRun,
7
- unregisterRun,
8
- listActiveRuns,
9
- } from "karajan-core/run-registry";