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