karajan-code 4.70.4 → 5.0.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 (380) 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/retired-commands.js +49 -0
  68. package/src/cli.js +18 -5
  69. package/src/commands/agent-run.js +40 -26
  70. package/src/commands/audit.js +127 -124
  71. package/src/commands/board.js +5 -9
  72. package/src/commands/check.js +29 -16
  73. package/src/commands/doctor.js +2 -0
  74. package/src/commands/env.js +176 -150
  75. package/src/commands/go.js +71 -53
  76. package/src/commands/harden.js +90 -81
  77. package/src/commands/hu-start.js +52 -0
  78. package/src/commands/hu.js +288 -221
  79. package/src/commands/identity.js +111 -78
  80. package/src/commands/init-atril.js +47 -0
  81. package/src/commands/init.js +11 -40
  82. package/src/commands/install-tools.js +70 -85
  83. package/src/commands/main-guard.js +78 -0
  84. package/src/commands/policy.js +226 -184
  85. package/src/commands/qmd.js +27 -21
  86. package/src/commands/rag.js +75 -48
  87. package/src/commands/review-gate.js +421 -341
  88. package/src/commands/start.js +4 -5
  89. package/src/commands/steward.js +96 -47
  90. package/src/commands/tournament.js +46 -37
  91. package/src/commands/worktree.js +94 -25
  92. package/src/config/loader.js +34 -17
  93. package/src/config/secrets.js +36 -0
  94. package/src/config.js +1 -0
  95. package/src/environment/adr.js +16 -2
  96. package/src/git/karajan-label.js +20 -8
  97. package/src/guards/main-guard.js +54 -0
  98. package/src/harden/hook-templates.js +16 -1
  99. package/src/harden/sentinel/posttooluse.mjs +18 -6
  100. package/src/harden/sentinel/pretooluse-sentinel.mjs +64 -36
  101. package/src/harden/sentinel/sentinel-lib.mjs +129 -26
  102. package/src/harden/sentinel/sentinel-shell.mjs +5 -16
  103. package/src/harden/sentinel/sessionstart.mjs +3 -2
  104. package/src/harden/sentinel/stop.mjs +5 -4
  105. package/src/harden/workflow-templates.js +1 -1
  106. package/src/hu/board-lookup.js +29 -0
  107. package/src/hu/gh-identity.js +23 -0
  108. package/src/hu/github-board.js +4 -2
  109. package/src/hu/lane-prune.js +15 -7
  110. package/src/hu/lane-setup.js +65 -0
  111. package/src/hu/lanes.js +66 -0
  112. package/src/hu/team-board-mirror.js +3 -2
  113. package/src/infrastructure/command-runner.js +1 -1
  114. package/src/infrastructure/file-system-service.js +1 -1
  115. package/src/mcp/handlers/direct-handlers.js +2 -292
  116. package/src/mcp/handlers/hu-handlers.js +1 -35
  117. package/src/mcp/handlers/management-handlers.js +2 -42
  118. package/src/mcp/server-handlers.js +16 -22
  119. package/src/mcp/tools.js +1 -196
  120. package/src/plan/lane-plans.js +54 -0
  121. package/src/plan/plan-store.js +7 -4
  122. package/src/policy/add.js +26 -12
  123. package/src/policy/adr-number-check.js +31 -0
  124. package/src/prompts/audit.js +299 -339
  125. package/src/prompts/card-context.js +10 -5
  126. package/src/prompts/reviewer.js +5 -2
  127. package/src/rag/auto-update.js +56 -43
  128. package/src/rag/bootstrap-index.js +28 -54
  129. package/src/rag/migrate.js +1 -1
  130. package/src/rag/onnx-fallback.js +2 -2
  131. package/src/rag/pid-lease.js +70 -0
  132. package/src/rag/project-store.js +2 -12
  133. package/src/review/card-first.js +57 -46
  134. package/src/review/gate-gitignore.js +23 -4
  135. package/src/review/gate-hook.js +12 -4
  136. package/src/review/one-shot-review.js +45 -35
  137. package/src/review/publish-pr.js +14 -2
  138. package/src/review/repo-docs.js +73 -0
  139. package/src/review/repo-stack.js +59 -0
  140. package/src/review/reviewer-fallback.js +19 -4
  141. package/src/review/seal-commit.js +29 -0
  142. package/src/review/sonar-pregate.js +59 -44
  143. package/src/review/third-party-review.js +90 -16
  144. package/src/review/third-party-size.js +43 -0
  145. package/src/review/third-party-skills.js +54 -0
  146. package/src/review/verify-pr.js +1 -24
  147. package/src/roles/audit-role.js +106 -125
  148. package/src/skills/atril-skills.js +5 -4
  149. package/src/sonar/scanner.js +116 -101
  150. package/src/steward/invariants.js +5 -4
  151. package/src/steward/phantom-sweep.js +66 -0
  152. package/src/tournament/judge.js +60 -53
  153. package/src/utils/gh-account.js +37 -0
  154. package/src/utils/git.js +0 -13
  155. package/src/utils/home-migration.js +7 -1
  156. package/src/utils/main-checkout.js +53 -0
  157. package/src/utils/qmd-collection.js +3 -1
  158. package/src/utils/welcome.js +3 -3
  159. package/templates/{skills → atril/commands}/kj-architect.md +5 -0
  160. package/templates/{skills → atril/commands}/kj-audit.md +5 -0
  161. package/templates/{skills → atril/commands}/kj-board.md +5 -0
  162. package/templates/{skills → atril/commands}/kj-code.md +5 -0
  163. package/templates/{skills → atril/commands}/kj-csv-transform.md +5 -0
  164. package/templates/{skills → atril/commands}/kj-data-report.md +5 -0
  165. package/templates/{skills → atril/commands}/kj-discover.md +5 -0
  166. package/templates/{skills → atril/commands}/kj-rag-query.md +5 -0
  167. package/templates/{skills → atril/commands}/kj-review.md +5 -0
  168. package/templates/{skills → atril/commands}/kj-security.md +5 -0
  169. package/templates/{skills → atril/commands}/kj-sonar.md +5 -0
  170. package/templates/{skills → atril/commands}/kj-sql-analysis.md +5 -0
  171. package/templates/{skills → atril/commands}/kj-test.md +5 -0
  172. package/packages/hu-board/public/utils/run-launcher.js +0 -169
  173. package/packages/hu-board/src/run-tracker.js +0 -121
  174. package/src/activity-log.js +0 -59
  175. package/src/agents/host-agent.js +0 -38
  176. package/src/agents/model-registry.js +0 -142
  177. package/src/audit/plan-adherence.js +0 -224
  178. package/src/autonomy/arbiter-role.js +0 -71
  179. package/src/autonomy/arbiter.js +0 -22
  180. package/src/autonomy/decider.js +0 -18
  181. package/src/autonomy/decision-resolver.js +0 -58
  182. package/src/autonomy/outcome-report.js +0 -55
  183. package/src/autonomy/stage-ask.js +0 -30
  184. package/src/brain/decision-tracker.js +0 -125
  185. package/src/brain/decisor.js +0 -243
  186. package/src/brain/solomon-consult.js +0 -171
  187. package/src/brain/standby-scheduler.js +0 -8
  188. package/src/budget/comparison.js +0 -96
  189. package/src/canvas/parse-md.js +0 -238
  190. package/src/canvas/schema.js +0 -101
  191. package/src/canvas/to-flat.js +0 -85
  192. package/src/canvas/validate.js +0 -163
  193. package/src/ci/dispatch.js +0 -99
  194. package/src/ci/index.js +0 -3
  195. package/src/ci/pr-diff.js +0 -26
  196. package/src/cli/register-standby.js +0 -26
  197. package/src/commands/architect.js +0 -111
  198. package/src/commands/autorun.js +0 -49
  199. package/src/commands/researcher.js +0 -54
  200. package/src/commands/resume.js +0 -72
  201. package/src/commands/review.js +0 -89
  202. package/src/commands/run.js +0 -185
  203. package/src/commands/standby.js +0 -117
  204. package/src/commands/status.js +0 -36
  205. package/src/commands/triage.js +0 -78
  206. package/src/commands/undo.js +0 -62
  207. package/src/domains/domain-loader.js +0 -245
  208. package/src/domains/domain-registry.js +0 -140
  209. package/src/domains/domain-synthesizer.js +0 -129
  210. package/src/git/automation.js +0 -433
  211. package/src/git/coder-commit-guard.js +0 -40
  212. package/src/git/hu-automation.js +0 -243
  213. package/src/git/hu-snapshot.js +0 -10
  214. package/src/git/symlink-targets.js +0 -57
  215. package/src/golden/asserter.js +0 -92
  216. package/src/golden/loader.js +0 -52
  217. package/src/golden/runner.js +0 -92
  218. package/src/golden/schema.js +0 -41
  219. package/src/guards/duplicate-members.js +0 -86
  220. package/src/guards/intent-guard.js +0 -161
  221. package/src/guards/perf-guard.js +0 -126
  222. package/src/guards/policy-guard.js +0 -90
  223. package/src/guards/policy-resolver.js +0 -85
  224. package/src/guards/secret-redactor.js +0 -71
  225. package/src/hu/acceptance-runner.js +0 -138
  226. package/src/hu/lazy-planner.js +0 -109
  227. package/src/hu/parallel-executor.js +0 -94
  228. package/src/hu/routing-metrics.js +0 -17
  229. package/src/hu/split-validator.js +0 -143
  230. package/src/hu/splitting-detector.js +0 -158
  231. package/src/hu/splitting-generator.js +0 -175
  232. package/src/hu/store.js +0 -394
  233. package/src/infrastructure/mocks.js +0 -182
  234. package/src/mcp/handlers/run-handler.js +0 -318
  235. package/src/mcp/sovereignty-guard.js +0 -113
  236. package/src/mcp/tool-arg-normalizers.js +0 -16
  237. package/src/mutate/reviewer-signal.js +0 -76
  238. package/src/orchestrator/agent-fallback.js +0 -81
  239. package/src/orchestrator/brain-coordinator.js +0 -186
  240. package/src/orchestrator/ci-integration.js +0 -139
  241. package/src/orchestrator/config-init.js +0 -426
  242. package/src/orchestrator/direct-actions.js +0 -217
  243. package/src/orchestrator/drivers/error-recovery.js +0 -287
  244. package/src/orchestrator/drivers/init-context.js +0 -238
  245. package/src/orchestrator/drivers/iteration-loop.js +0 -382
  246. package/src/orchestrator/drivers/iteration-phases/coder-and-refactorer.js +0 -69
  247. package/src/orchestrator/drivers/iteration-phases/guards.js +0 -91
  248. package/src/orchestrator/drivers/iteration-phases/handle-approved.js +0 -29
  249. package/src/orchestrator/drivers/iteration-phases/quality-gates.js +0 -125
  250. package/src/orchestrator/drivers/iteration-phases/reviewer-gate.js +0 -62
  251. package/src/orchestrator/drivers/post-loop.js +0 -404
  252. package/src/orchestrator/drivers/pre-loop-phases/auto-hu-batch.js +0 -137
  253. package/src/orchestrator/drivers/pre-loop-phases/config-deprecations.js +0 -47
  254. package/src/orchestrator/drivers/pre-loop-phases/ensure-addyosmani-skills.js +0 -84
  255. package/src/orchestrator/drivers/pre-loop-phases/inject-loaded-plan.js +0 -393
  256. package/src/orchestrator/drivers/pre-loop.js +0 -524
  257. package/src/orchestrator/drivers/run-hu-batch.js +0 -468
  258. package/src/orchestrator/feedback-enrichment.js +0 -140
  259. package/src/orchestrator/feedback-queue.js +0 -151
  260. package/src/orchestrator/flow-control.js +0 -170
  261. package/src/orchestrator/flow-runner.js +0 -365
  262. package/src/orchestrator/fs-leak-detector.js +0 -228
  263. package/src/orchestrator/hu-scheduler.js +0 -114
  264. package/src/orchestrator/hu-sub-pipeline.js +0 -642
  265. package/src/orchestrator/iteration-gate.js +0 -73
  266. package/src/orchestrator/iteration-stages.js +0 -9
  267. package/src/orchestrator/parallel-limiter.js +0 -74
  268. package/src/orchestrator/pipeline-context.js +0 -72
  269. package/src/orchestrator/post-loop-stages.js +0 -468
  270. package/src/orchestrator/pre-loop-stages.js +0 -11
  271. package/src/orchestrator/preflight-checks.js +0 -487
  272. package/src/orchestrator/repair/repair-detector.js +0 -117
  273. package/src/orchestrator/repair/repair-runner.js +0 -142
  274. package/src/orchestrator/reviewer-fallback.js +0 -45
  275. package/src/orchestrator/role-output-compressor.js +0 -189
  276. package/src/orchestrator/session-journal.js +0 -308
  277. package/src/orchestrator/solomon-escalation.js +0 -331
  278. package/src/orchestrator/solomon-rules.js +0 -212
  279. package/src/orchestrator/stages/acceptance-coverage-stage.js +0 -47
  280. package/src/orchestrator/stages/architect-stage.js +0 -172
  281. package/src/orchestrator/stages/coder-stage.js +0 -506
  282. package/src/orchestrator/stages/domain-curator-stage.js +0 -82
  283. package/src/orchestrator/stages/format-stage.js +0 -61
  284. package/src/orchestrator/stages/hu-reviewer-phases/detect-and-apply-splits.js +0 -127
  285. package/src/orchestrator/stages/hu-reviewer-stage.js +0 -419
  286. package/src/orchestrator/stages/perf-stage.js +0 -140
  287. package/src/orchestrator/stages/planner-stage.js +0 -85
  288. package/src/orchestrator/stages/rag-context-stage.js +0 -80
  289. package/src/orchestrator/stages/rag-preload-decisor.js +0 -58
  290. package/src/orchestrator/stages/research-stage.js +0 -69
  291. package/src/orchestrator/stages/reviewer-stage.js +0 -431
  292. package/src/orchestrator/stages/sonar-stage.js +0 -439
  293. package/src/orchestrator/stages/stage-classes.js +0 -84
  294. package/src/orchestrator/stages/stage-executor.js +0 -155
  295. package/src/orchestrator/stages/suite-green-stage.js +0 -62
  296. package/src/orchestrator/stages/tdd-discipline-stage.js +0 -56
  297. package/src/orchestrator/stages/tool-judge-stage.js +0 -53
  298. package/src/orchestrator/stages/triage-stage.js +0 -172
  299. package/src/orchestrator/standby.js +0 -71
  300. package/src/orchestrator/verification-gate.js +0 -183
  301. package/src/orchestrator.js +0 -22
  302. package/src/plan/adr-generator.js +0 -170
  303. package/src/plan/adr-loader.js +0 -60
  304. package/src/plan/plan-executor.js +0 -100
  305. package/src/plan/plan-validation.js +0 -4
  306. package/src/prompts/acceptance-coverage.js +0 -32
  307. package/src/prompts/arbiter.js +0 -38
  308. package/src/prompts/architect.js +0 -103
  309. package/src/prompts/hu-reviewer.js +0 -244
  310. package/src/prompts/tool-correctness-judge.js +0 -31
  311. package/src/prompts/triage.js +0 -57
  312. package/src/rag/embedder.js +0 -2
  313. package/src/rag/embedders/_cloud-base.js +0 -2
  314. package/src/rag/embedders/cohere.js +0 -2
  315. package/src/rag/embedders/mistral.js +0 -2
  316. package/src/rag/embedders/onnx.js +0 -2
  317. package/src/rag/embedders/openai.js +0 -2
  318. package/src/rag/embedders/voyage.js +0 -2
  319. package/src/rag/rerank.js +0 -4
  320. package/src/rag/where-parser.js +0 -4
  321. package/src/repeat-detector.js +0 -88
  322. package/src/review/diff-generator.js +0 -112
  323. package/src/review/git-stash-helper.js +0 -104
  324. package/src/review/schema.js +0 -31
  325. package/src/review/scope-filter.js +0 -152
  326. package/src/review/snapshot-diff.js +0 -122
  327. package/src/review/tdd-discipline.js +0 -90
  328. package/src/review/tdd-policy.js +0 -69
  329. package/src/roles/acceptance-coverage-role.js +0 -78
  330. package/src/roles/architect-role.js +0 -77
  331. package/src/roles/coder-role.js +0 -113
  332. package/src/roles/commiter-role.js +0 -113
  333. package/src/roles/domain-curator-role.js +0 -134
  334. package/src/roles/hu-reviewer-role.js +0 -64
  335. package/src/roles/impeccable-role.js +0 -85
  336. package/src/roles/index.js +0 -18
  337. package/src/roles/karajan-brain-role.js +0 -134
  338. package/src/roles/perf-role.js +0 -122
  339. package/src/roles/planner-role.js +0 -151
  340. package/src/roles/refactorer-role.js +0 -30
  341. package/src/roles/repairer-role.js +0 -181
  342. package/src/roles/researcher-role.js +0 -70
  343. package/src/roles/reviewer-role.js +0 -115
  344. package/src/roles/security-role.js +0 -73
  345. package/src/roles/solomon-role.js +0 -271
  346. package/src/roles/sonar-role.js +0 -72
  347. package/src/roles/tester-role.js +0 -235
  348. package/src/roles/tool-correctness-judge-role.js +0 -78
  349. package/src/roles/triage-role.js +0 -99
  350. package/src/session/journal/decisions-writer.js +0 -200
  351. package/src/session/journal/iteration-logger.js +0 -194
  352. package/src/session/journal/summary-writer.js +0 -320
  353. package/src/session/journal/tree-writer.js +0 -164
  354. package/src/session/journal/write-all.js +0 -89
  355. package/src/session-cleanup.js +0 -116
  356. package/src/skills/semantic-detector.js +0 -167
  357. package/src/skills/skill-detector.js +0 -385
  358. package/src/sonar/cloud-scanner.js +0 -78
  359. package/src/tracker-bootstrap.js +0 -44
  360. package/src/types/index.js +0 -38
  361. package/src/types/policy.js +0 -43
  362. package/src/types/solomon.js +0 -87
  363. package/src/utils/async-lock.js +0 -31
  364. package/src/utils/budget.js +0 -229
  365. package/src/utils/cwd-confirm.js +0 -39
  366. package/src/utils/display/event-handlers.js +0 -403
  367. package/src/utils/display/formatters.js +0 -132
  368. package/src/utils/display/header.js +0 -47
  369. package/src/utils/display/session-summary.js +0 -118
  370. package/src/utils/display/solomon.js +0 -42
  371. package/src/utils/pricing.js +0 -29
  372. package/src/utils/quota-simulator.js +0 -56
  373. package/src/utils/role-assigner.js +0 -137
  374. package/src/utils/rtk-wrapper.js +0 -87
  375. package/src/utils/run-registry.js +0 -9
  376. package/src/utils/status-dashboard.js +0 -254
  377. package/src/utils/tool-call-extractor.js +0 -56
  378. package/src/webperf/devtools-detect.js +0 -112
  379. package/src/webperf/webperf-role-integration.js +0 -66
  380. 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";