@ag-eco/agentplate-cli 0.13.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 (455) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +462 -0
  3. package/agents/ap-co-creation.md +90 -0
  4. package/agents/builder.md +144 -0
  5. package/agents/coordinator.md +377 -0
  6. package/agents/lead.md +435 -0
  7. package/agents/merger.md +164 -0
  8. package/agents/monitor.md +214 -0
  9. package/agents/orchestrator.md +239 -0
  10. package/agents/reviewer.md +140 -0
  11. package/agents/scout.md +125 -0
  12. package/agents/supervisor.md +427 -0
  13. package/package.json +66 -0
  14. package/src/agents/capabilities.test.ts +85 -0
  15. package/src/agents/capabilities.ts +125 -0
  16. package/src/agents/checkpoint.test.ts +88 -0
  17. package/src/agents/checkpoint.ts +101 -0
  18. package/src/agents/copilot-hooks-deployer.test.ts +162 -0
  19. package/src/agents/copilot-hooks-deployer.ts +93 -0
  20. package/src/agents/guard-rules.test.ts +372 -0
  21. package/src/agents/guard-rules.ts +97 -0
  22. package/src/agents/headless-mail-injector.test.ts +709 -0
  23. package/src/agents/headless-mail-injector.ts +377 -0
  24. package/src/agents/headless-prompt.test.ts +102 -0
  25. package/src/agents/headless-prompt.ts +68 -0
  26. package/src/agents/hooks-deployer.test.ts +3119 -0
  27. package/src/agents/hooks-deployer.ts +804 -0
  28. package/src/agents/identity.test.ts +604 -0
  29. package/src/agents/identity.ts +384 -0
  30. package/src/agents/lifecycle.test.ts +196 -0
  31. package/src/agents/lifecycle.ts +183 -0
  32. package/src/agents/mail-poll-detect.test.ts +153 -0
  33. package/src/agents/mail-poll-detect.ts +73 -0
  34. package/src/agents/manifest.test.ts +1026 -0
  35. package/src/agents/manifest.ts +376 -0
  36. package/src/agents/overlay.test.ts +1058 -0
  37. package/src/agents/overlay.ts +490 -0
  38. package/src/agents/scope-detect.test.ts +190 -0
  39. package/src/agents/scope-detect.ts +146 -0
  40. package/src/agents/turn-lock.test.ts +181 -0
  41. package/src/agents/turn-lock.ts +235 -0
  42. package/src/agents/turn-runner-dispatch.test.ts +182 -0
  43. package/src/agents/turn-runner-dispatch.ts +105 -0
  44. package/src/agents/turn-runner.test.ts +2312 -0
  45. package/src/agents/turn-runner.ts +1383 -0
  46. package/src/beads/client.test.ts +217 -0
  47. package/src/beads/client.ts +230 -0
  48. package/src/beads/molecules.test.ts +338 -0
  49. package/src/beads/molecules.ts +198 -0
  50. package/src/commands/agents.test.ts +328 -0
  51. package/src/commands/agents.ts +299 -0
  52. package/src/commands/clean.test.ts +797 -0
  53. package/src/commands/clean.ts +791 -0
  54. package/src/commands/completions.test.ts +348 -0
  55. package/src/commands/completions.ts +981 -0
  56. package/src/commands/coordinator.test.ts +2975 -0
  57. package/src/commands/coordinator.ts +1841 -0
  58. package/src/commands/costs.test.ts +1183 -0
  59. package/src/commands/costs.ts +599 -0
  60. package/src/commands/dashboard.test.ts +954 -0
  61. package/src/commands/dashboard.ts +1212 -0
  62. package/src/commands/discover.test.ts +288 -0
  63. package/src/commands/discover.ts +202 -0
  64. package/src/commands/doctor.test.ts +303 -0
  65. package/src/commands/doctor.ts +311 -0
  66. package/src/commands/ecosystem.test.ts +226 -0
  67. package/src/commands/ecosystem.ts +248 -0
  68. package/src/commands/errors.test.ts +654 -0
  69. package/src/commands/errors.ts +197 -0
  70. package/src/commands/feed.test.ts +709 -0
  71. package/src/commands/feed.ts +260 -0
  72. package/src/commands/group.test.ts +475 -0
  73. package/src/commands/group.ts +546 -0
  74. package/src/commands/hooks.test.ts +458 -0
  75. package/src/commands/hooks.ts +263 -0
  76. package/src/commands/init.test.ts +1011 -0
  77. package/src/commands/init.ts +967 -0
  78. package/src/commands/inspect.test.ts +1239 -0
  79. package/src/commands/inspect.ts +648 -0
  80. package/src/commands/log.test.ts +1913 -0
  81. package/src/commands/log.ts +958 -0
  82. package/src/commands/logs.test.ts +801 -0
  83. package/src/commands/logs.ts +483 -0
  84. package/src/commands/mail.test.ts +1501 -0
  85. package/src/commands/mail.ts +848 -0
  86. package/src/commands/merge.test.ts +864 -0
  87. package/src/commands/merge.ts +381 -0
  88. package/src/commands/metrics.test.ts +458 -0
  89. package/src/commands/metrics.ts +129 -0
  90. package/src/commands/monitor.test.ts +191 -0
  91. package/src/commands/monitor.ts +409 -0
  92. package/src/commands/nudge.test.ts +579 -0
  93. package/src/commands/nudge.ts +646 -0
  94. package/src/commands/orchestrator.ts +42 -0
  95. package/src/commands/prime.test.ts +612 -0
  96. package/src/commands/prime.ts +359 -0
  97. package/src/commands/replay.test.ts +757 -0
  98. package/src/commands/replay.ts +231 -0
  99. package/src/commands/run.test.ts +469 -0
  100. package/src/commands/run.ts +353 -0
  101. package/src/commands/serve/agent-actions.test.ts +210 -0
  102. package/src/commands/serve/agent-actions.ts +192 -0
  103. package/src/commands/serve/build.test.ts +202 -0
  104. package/src/commands/serve/build.ts +206 -0
  105. package/src/commands/serve/coordinator-actions.test.ts +339 -0
  106. package/src/commands/serve/coordinator-actions.ts +410 -0
  107. package/src/commands/serve/dev.test.ts +168 -0
  108. package/src/commands/serve/dev.ts +117 -0
  109. package/src/commands/serve/mail-actions.test.ts +312 -0
  110. package/src/commands/serve/mail-actions.ts +167 -0
  111. package/src/commands/serve/rest.test.ts +1680 -0
  112. package/src/commands/serve/rest.ts +1130 -0
  113. package/src/commands/serve/static.ts +51 -0
  114. package/src/commands/serve/ws.test.ts +361 -0
  115. package/src/commands/serve/ws.ts +332 -0
  116. package/src/commands/serve.test.ts +459 -0
  117. package/src/commands/serve.ts +654 -0
  118. package/src/commands/sling.test.ts +1583 -0
  119. package/src/commands/sling.ts +1351 -0
  120. package/src/commands/spec.test.ts +179 -0
  121. package/src/commands/spec.ts +105 -0
  122. package/src/commands/status.test.ts +614 -0
  123. package/src/commands/status.ts +403 -0
  124. package/src/commands/stop.test.ts +964 -0
  125. package/src/commands/stop.ts +319 -0
  126. package/src/commands/supervisor.test.ts +185 -0
  127. package/src/commands/supervisor.ts +537 -0
  128. package/src/commands/trace.test.ts +762 -0
  129. package/src/commands/trace.ts +205 -0
  130. package/src/commands/update.test.ts +466 -0
  131. package/src/commands/update.ts +263 -0
  132. package/src/commands/upgrade.test.ts +48 -0
  133. package/src/commands/upgrade.ts +240 -0
  134. package/src/commands/watch.test.ts +257 -0
  135. package/src/commands/watch.ts +308 -0
  136. package/src/commands/worktree.test.ts +1297 -0
  137. package/src/commands/worktree.ts +451 -0
  138. package/src/config.test.ts +1535 -0
  139. package/src/config.ts +1064 -0
  140. package/src/doctor/agents.test.ts +523 -0
  141. package/src/doctor/agents.ts +399 -0
  142. package/src/doctor/config-check.test.ts +191 -0
  143. package/src/doctor/config-check.ts +183 -0
  144. package/src/doctor/consistency.test.ts +807 -0
  145. package/src/doctor/consistency.ts +347 -0
  146. package/src/doctor/databases.test.ts +350 -0
  147. package/src/doctor/databases.ts +243 -0
  148. package/src/doctor/dependencies.test.ts +296 -0
  149. package/src/doctor/dependencies.ts +272 -0
  150. package/src/doctor/ecosystem.test.ts +308 -0
  151. package/src/doctor/ecosystem.ts +156 -0
  152. package/src/doctor/logs.test.ts +253 -0
  153. package/src/doctor/logs.ts +295 -0
  154. package/src/doctor/merge-queue.test.ts +315 -0
  155. package/src/doctor/merge-queue.ts +167 -0
  156. package/src/doctor/providers.test.ts +409 -0
  157. package/src/doctor/providers.ts +250 -0
  158. package/src/doctor/serve.test.ts +95 -0
  159. package/src/doctor/serve.ts +86 -0
  160. package/src/doctor/structure.test.ts +423 -0
  161. package/src/doctor/structure.ts +285 -0
  162. package/src/doctor/types.ts +43 -0
  163. package/src/doctor/version.test.ts +241 -0
  164. package/src/doctor/version.ts +132 -0
  165. package/src/doctor/watchdog.test.ts +167 -0
  166. package/src/doctor/watchdog.ts +214 -0
  167. package/src/e2e/init-sling-lifecycle.test.ts +283 -0
  168. package/src/errors.test.ts +350 -0
  169. package/src/errors.ts +217 -0
  170. package/src/events/store.test.ts +660 -0
  171. package/src/events/store.ts +369 -0
  172. package/src/events/tailer.test.ts +719 -0
  173. package/src/events/tailer.ts +332 -0
  174. package/src/events/tool-filter.test.ts +330 -0
  175. package/src/events/tool-filter.ts +126 -0
  176. package/src/index.ts +533 -0
  177. package/src/insights/analyzer.test.ts +466 -0
  178. package/src/insights/analyzer.ts +203 -0
  179. package/src/insights/quality-gates.test.ts +141 -0
  180. package/src/insights/quality-gates.ts +156 -0
  181. package/src/json.test.ts +72 -0
  182. package/src/json.ts +53 -0
  183. package/src/loam/client.test.ts +752 -0
  184. package/src/loam/client.ts +664 -0
  185. package/src/logging/color.test.ts +252 -0
  186. package/src/logging/color.ts +105 -0
  187. package/src/logging/format.test.ts +110 -0
  188. package/src/logging/format.ts +255 -0
  189. package/src/logging/logger.test.ts +814 -0
  190. package/src/logging/logger.ts +266 -0
  191. package/src/logging/reporter.test.ts +259 -0
  192. package/src/logging/reporter.ts +110 -0
  193. package/src/logging/sanitizer.test.ts +190 -0
  194. package/src/logging/sanitizer.ts +57 -0
  195. package/src/logging/theme.ts +140 -0
  196. package/src/mail/broadcast.test.ts +204 -0
  197. package/src/mail/broadcast.ts +92 -0
  198. package/src/mail/client.test.ts +774 -0
  199. package/src/mail/client.ts +236 -0
  200. package/src/mail/store.test.ts +898 -0
  201. package/src/mail/store.ts +425 -0
  202. package/src/merge/lock.test.ts +149 -0
  203. package/src/merge/lock.ts +140 -0
  204. package/src/merge/predict.test.ts +387 -0
  205. package/src/merge/predict.ts +249 -0
  206. package/src/merge/queue.test.ts +426 -0
  207. package/src/merge/queue.ts +246 -0
  208. package/src/merge/resolver.test.ts +1993 -0
  209. package/src/merge/resolver.ts +926 -0
  210. package/src/metrics/pricing.test.ts +258 -0
  211. package/src/metrics/pricing.ts +135 -0
  212. package/src/metrics/store.test.ts +978 -0
  213. package/src/metrics/store.ts +501 -0
  214. package/src/metrics/summary.test.ts +398 -0
  215. package/src/metrics/summary.ts +178 -0
  216. package/src/metrics/transcript.test.ts +483 -0
  217. package/src/metrics/transcript.ts +114 -0
  218. package/src/runtimes/__fixtures__/claude-stream-fixture.ts +22 -0
  219. package/src/runtimes/aider.test.ts +124 -0
  220. package/src/runtimes/aider.ts +147 -0
  221. package/src/runtimes/amp.test.ts +164 -0
  222. package/src/runtimes/amp.ts +154 -0
  223. package/src/runtimes/claude.test.ts +1474 -0
  224. package/src/runtimes/claude.ts +579 -0
  225. package/src/runtimes/codex.test.ts +805 -0
  226. package/src/runtimes/codex.ts +273 -0
  227. package/src/runtimes/connections.test.ts +214 -0
  228. package/src/runtimes/connections.ts +103 -0
  229. package/src/runtimes/copilot.test.ts +707 -0
  230. package/src/runtimes/copilot.ts +316 -0
  231. package/src/runtimes/cursor.test.ts +497 -0
  232. package/src/runtimes/cursor.ts +205 -0
  233. package/src/runtimes/gemini.test.ts +537 -0
  234. package/src/runtimes/gemini.ts +243 -0
  235. package/src/runtimes/goose.test.ts +133 -0
  236. package/src/runtimes/goose.ts +157 -0
  237. package/src/runtimes/headless-connection.test.ts +264 -0
  238. package/src/runtimes/headless-connection.ts +158 -0
  239. package/src/runtimes/opencode.test.ts +325 -0
  240. package/src/runtimes/opencode.ts +188 -0
  241. package/src/runtimes/pi-guards.test.ts +486 -0
  242. package/src/runtimes/pi-guards.ts +367 -0
  243. package/src/runtimes/pi.test.ts +789 -0
  244. package/src/runtimes/pi.ts +305 -0
  245. package/src/runtimes/registry.test.ts +196 -0
  246. package/src/runtimes/registry.ts +99 -0
  247. package/src/runtimes/sapling.test.ts +1267 -0
  248. package/src/runtimes/sapling.ts +710 -0
  249. package/src/runtimes/types.ts +266 -0
  250. package/src/schema-consistency.test.ts +246 -0
  251. package/src/sessions/compat.test.ts +281 -0
  252. package/src/sessions/compat.ts +105 -0
  253. package/src/sessions/store.test.ts +1748 -0
  254. package/src/sessions/store.ts +858 -0
  255. package/src/test-helpers.test.ts +124 -0
  256. package/src/test-helpers.ts +145 -0
  257. package/src/test-setup.test.ts +31 -0
  258. package/src/test-setup.ts +28 -0
  259. package/src/tools/loam/api.ts +368 -0
  260. package/src/tools/loam/cli.ts +278 -0
  261. package/src/tools/loam/commands/add.ts +52 -0
  262. package/src/tools/loam/commands/archive.ts +214 -0
  263. package/src/tools/loam/commands/audit.ts +276 -0
  264. package/src/tools/loam/commands/compact.ts +1062 -0
  265. package/src/tools/loam/commands/completions.ts +79 -0
  266. package/src/tools/loam/commands/config.ts +381 -0
  267. package/src/tools/loam/commands/delete-domain.ts +121 -0
  268. package/src/tools/loam/commands/delete.ts +316 -0
  269. package/src/tools/loam/commands/diff.ts +200 -0
  270. package/src/tools/loam/commands/doctor.ts +1113 -0
  271. package/src/tools/loam/commands/edit.ts +226 -0
  272. package/src/tools/loam/commands/init.ts +31 -0
  273. package/src/tools/loam/commands/learn.ts +179 -0
  274. package/src/tools/loam/commands/move.ts +323 -0
  275. package/src/tools/loam/commands/onboard.ts +374 -0
  276. package/src/tools/loam/commands/outcome.ts +185 -0
  277. package/src/tools/loam/commands/prime.ts +688 -0
  278. package/src/tools/loam/commands/prune.ts +614 -0
  279. package/src/tools/loam/commands/query.ts +218 -0
  280. package/src/tools/loam/commands/rank.ts +180 -0
  281. package/src/tools/loam/commands/ready.ts +189 -0
  282. package/src/tools/loam/commands/record.ts +1210 -0
  283. package/src/tools/loam/commands/restore.ts +166 -0
  284. package/src/tools/loam/commands/search.ts +327 -0
  285. package/src/tools/loam/commands/setup.ts +887 -0
  286. package/src/tools/loam/commands/status.ts +103 -0
  287. package/src/tools/loam/commands/sync.ts +298 -0
  288. package/src/tools/loam/commands/update.ts +19 -0
  289. package/src/tools/loam/commands/upgrade.ts +93 -0
  290. package/src/tools/loam/commands/validate.ts +190 -0
  291. package/src/tools/loam/index.ts +62 -0
  292. package/src/tools/loam/log.ts +127 -0
  293. package/src/tools/loam/registry/builtins.ts +409 -0
  294. package/src/tools/loam/registry/custom.ts +431 -0
  295. package/src/tools/loam/registry/init.ts +55 -0
  296. package/src/tools/loam/registry/template.ts +40 -0
  297. package/src/tools/loam/registry/type-registry.ts +113 -0
  298. package/src/tools/loam/schemas/config-schema.ts +489 -0
  299. package/src/tools/loam/schemas/config.ts +245 -0
  300. package/src/tools/loam/schemas/index.ts +18 -0
  301. package/src/tools/loam/schemas/record-schema.ts +191 -0
  302. package/src/tools/loam/schemas/record.ts +115 -0
  303. package/src/tools/loam/utils/active-work.ts +205 -0
  304. package/src/tools/loam/utils/anchor-validity.ts +80 -0
  305. package/src/tools/loam/utils/archive.ts +146 -0
  306. package/src/tools/loam/utils/audit.ts +667 -0
  307. package/src/tools/loam/utils/bm25.ts +238 -0
  308. package/src/tools/loam/utils/budget.ts +142 -0
  309. package/src/tools/loam/utils/config.ts +344 -0
  310. package/src/tools/loam/utils/dir-anchors.ts +62 -0
  311. package/src/tools/loam/utils/domain-rules.ts +114 -0
  312. package/src/tools/loam/utils/expertise.ts +393 -0
  313. package/src/tools/loam/utils/format-helpers.ts +96 -0
  314. package/src/tools/loam/utils/format.ts +1234 -0
  315. package/src/tools/loam/utils/git-context.ts +50 -0
  316. package/src/tools/loam/utils/git.ts +183 -0
  317. package/src/tools/loam/utils/hooks.ts +299 -0
  318. package/src/tools/loam/utils/index.ts +52 -0
  319. package/src/tools/loam/utils/json-output.ts +13 -0
  320. package/src/tools/loam/utils/lock.ts +76 -0
  321. package/src/tools/loam/utils/markers.ts +48 -0
  322. package/src/tools/loam/utils/numeric-flags.ts +20 -0
  323. package/src/tools/loam/utils/palette.ts +44 -0
  324. package/src/tools/loam/utils/prime-ranking.ts +135 -0
  325. package/src/tools/loam/utils/recipe-discovery.ts +195 -0
  326. package/src/tools/loam/utils/runtime-flags.ts +28 -0
  327. package/src/tools/loam/utils/scoring.ts +94 -0
  328. package/src/tools/loam/utils/version.ts +116 -0
  329. package/src/tools/sprout/commands/block.ts +64 -0
  330. package/src/tools/sprout/commands/blocked.ts +86 -0
  331. package/src/tools/sprout/commands/close.ts +129 -0
  332. package/src/tools/sprout/commands/completions.ts +198 -0
  333. package/src/tools/sprout/commands/config.ts +238 -0
  334. package/src/tools/sprout/commands/create.ts +164 -0
  335. package/src/tools/sprout/commands/dep.ts +148 -0
  336. package/src/tools/sprout/commands/doctor.ts +979 -0
  337. package/src/tools/sprout/commands/init.ts +83 -0
  338. package/src/tools/sprout/commands/label.ts +178 -0
  339. package/src/tools/sprout/commands/list.ts +210 -0
  340. package/src/tools/sprout/commands/migrate.ts +133 -0
  341. package/src/tools/sprout/commands/onboard.ts +207 -0
  342. package/src/tools/sprout/commands/plan-show.ts +278 -0
  343. package/src/tools/sprout/commands/plan.ts +2526 -0
  344. package/src/tools/sprout/commands/prime.ts +399 -0
  345. package/src/tools/sprout/commands/ready.ts +245 -0
  346. package/src/tools/sprout/commands/search.ts +221 -0
  347. package/src/tools/sprout/commands/show.ts +277 -0
  348. package/src/tools/sprout/commands/stats.ts +146 -0
  349. package/src/tools/sprout/commands/sync.ts +134 -0
  350. package/src/tools/sprout/commands/tpl.ts +364 -0
  351. package/src/tools/sprout/commands/unblock.ts +115 -0
  352. package/src/tools/sprout/commands/update.ts +257 -0
  353. package/src/tools/sprout/commands/upgrade.ts +91 -0
  354. package/src/tools/sprout/config-schema.ts +152 -0
  355. package/src/tools/sprout/config.ts +355 -0
  356. package/src/tools/sprout/filter.ts +107 -0
  357. package/src/tools/sprout/format.ts +43 -0
  358. package/src/tools/sprout/id.ts +22 -0
  359. package/src/tools/sprout/index.ts +204 -0
  360. package/src/tools/sprout/log.ts +76 -0
  361. package/src/tools/sprout/markers.ts +22 -0
  362. package/src/tools/sprout/output.ts +121 -0
  363. package/src/tools/sprout/plan-backref.ts +93 -0
  364. package/src/tools/sprout/plan-context.ts +81 -0
  365. package/src/tools/sprout/plan-domain.ts +139 -0
  366. package/src/tools/sprout/plan-lifecycle.ts +65 -0
  367. package/src/tools/sprout/plan-loam.ts +207 -0
  368. package/src/tools/sprout/plan-schema.ts +209 -0
  369. package/src/tools/sprout/sort.ts +31 -0
  370. package/src/tools/sprout/store.ts +172 -0
  371. package/src/tools/sprout/types.ts +118 -0
  372. package/src/tools/sprout/validation.ts +119 -0
  373. package/src/tools/sprout/version.ts +1 -0
  374. package/src/tools/sprout/yaml.ts +387 -0
  375. package/src/tools/trellis/commands/archive.ts +87 -0
  376. package/src/tools/trellis/commands/completions.ts +610 -0
  377. package/src/tools/trellis/commands/config.ts +382 -0
  378. package/src/tools/trellis/commands/create.ts +252 -0
  379. package/src/tools/trellis/commands/diff.ts +150 -0
  380. package/src/tools/trellis/commands/doctor.ts +771 -0
  381. package/src/tools/trellis/commands/emit.ts +365 -0
  382. package/src/tools/trellis/commands/history.ts +83 -0
  383. package/src/tools/trellis/commands/import.ts +198 -0
  384. package/src/tools/trellis/commands/init.ts +81 -0
  385. package/src/tools/trellis/commands/list.ts +103 -0
  386. package/src/tools/trellis/commands/onboard.ts +156 -0
  387. package/src/tools/trellis/commands/pin.ts +172 -0
  388. package/src/tools/trellis/commands/prime.ts +193 -0
  389. package/src/tools/trellis/commands/render.ts +122 -0
  390. package/src/tools/trellis/commands/schema.ts +353 -0
  391. package/src/tools/trellis/commands/show.ts +115 -0
  392. package/src/tools/trellis/commands/stats.ts +65 -0
  393. package/src/tools/trellis/commands/sync.ts +112 -0
  394. package/src/tools/trellis/commands/tree.ts +123 -0
  395. package/src/tools/trellis/commands/update.ts +330 -0
  396. package/src/tools/trellis/commands/upgrade.ts +95 -0
  397. package/src/tools/trellis/commands/validate.ts +166 -0
  398. package/src/tools/trellis/config-schema.ts +81 -0
  399. package/src/tools/trellis/config.ts +108 -0
  400. package/src/tools/trellis/frontmatter.ts +348 -0
  401. package/src/tools/trellis/id.ts +24 -0
  402. package/src/tools/trellis/index.ts +209 -0
  403. package/src/tools/trellis/markers.ts +28 -0
  404. package/src/tools/trellis/output.ts +84 -0
  405. package/src/tools/trellis/render.ts +212 -0
  406. package/src/tools/trellis/store.ts +144 -0
  407. package/src/tools/trellis/types.ts +82 -0
  408. package/src/tools/trellis/validate.ts +199 -0
  409. package/src/tools/trellis/yaml.ts +309 -0
  410. package/src/tracker/beads.test.ts +454 -0
  411. package/src/tracker/beads.ts +56 -0
  412. package/src/tracker/factory.test.ts +90 -0
  413. package/src/tracker/factory.ts +65 -0
  414. package/src/tracker/sprout.test.ts +461 -0
  415. package/src/tracker/sprout.ts +182 -0
  416. package/src/tracker/types.ts +52 -0
  417. package/src/trellis/client.test.ts +107 -0
  418. package/src/trellis/client.ts +179 -0
  419. package/src/types.ts +970 -0
  420. package/src/utils/bin.test.ts +10 -0
  421. package/src/utils/bin.ts +37 -0
  422. package/src/utils/browser.test.ts +49 -0
  423. package/src/utils/browser.ts +48 -0
  424. package/src/utils/fs.test.ts +119 -0
  425. package/src/utils/fs.ts +62 -0
  426. package/src/utils/pid.test.ts +152 -0
  427. package/src/utils/pid.ts +130 -0
  428. package/src/utils/process-scan.test.ts +53 -0
  429. package/src/utils/process-scan.ts +76 -0
  430. package/src/utils/time.test.ts +43 -0
  431. package/src/utils/time.ts +37 -0
  432. package/src/utils/version.test.ts +33 -0
  433. package/src/utils/version.ts +70 -0
  434. package/src/version.ts +5 -0
  435. package/src/watchdog/daemon.test.ts +3721 -0
  436. package/src/watchdog/daemon.ts +1257 -0
  437. package/src/watchdog/health.test.ts +830 -0
  438. package/src/watchdog/health.ts +434 -0
  439. package/src/watchdog/triage.test.ts +205 -0
  440. package/src/watchdog/triage.ts +205 -0
  441. package/src/worktree/manager.test.ts +720 -0
  442. package/src/worktree/manager.ts +405 -0
  443. package/src/worktree/process.test.ts +172 -0
  444. package/src/worktree/process.ts +131 -0
  445. package/src/worktree/tmux.test.ts +1616 -0
  446. package/src/worktree/tmux.ts +721 -0
  447. package/templates/CLAUDE.md.tmpl +100 -0
  448. package/templates/copilot-hooks.json.tmpl +13 -0
  449. package/templates/hooks.json.tmpl +109 -0
  450. package/templates/overlay.md.tmpl +88 -0
  451. package/ui/dist/apple-touch-icon-bdy6teep.png +0 -0
  452. package/ui/dist/chunk-8s31f05k.css +1 -0
  453. package/ui/dist/chunk-vm5rz679.js +300 -0
  454. package/ui/dist/favicon-nzb39vza.svg +4 -0
  455. package/ui/dist/index.html +17 -0
@@ -0,0 +1,599 @@
1
+ /**
2
+ * CLI command: ap costs [--agent <name>] [--run <id>] [--by-capability] [--last <n>] [--self] [--json]
3
+ *
4
+ * Shows token/cost analysis and breakdown for agent sessions.
5
+ * Data source: metrics.db via createMetricsStore().
6
+ * Use --self to parse the current orchestrator session's transcript directly.
7
+ */
8
+
9
+ import { readdir, stat } from "node:fs/promises";
10
+ import { join } from "node:path";
11
+ import { Command } from "commander";
12
+ import { loadConfig } from "../config.ts";
13
+ import { ValidationError } from "../errors.ts";
14
+ import { jsonError, jsonOutput } from "../json.ts";
15
+ import { color } from "../logging/color.ts";
16
+ import { renderHeader, separator } from "../logging/theme.ts";
17
+ import { estimateCost } from "../metrics/pricing.ts";
18
+ import { createMetricsStore } from "../metrics/store.ts";
19
+ import { parseTranscriptUsage } from "../metrics/transcript.ts";
20
+ import { getRuntime } from "../runtimes/registry.ts";
21
+ import type { AgentRuntime } from "../runtimes/types.ts";
22
+ import { openSessionStore } from "../sessions/compat.ts";
23
+ import type { SessionMetrics } from "../types.ts";
24
+
25
+ /** Format a number with thousands separators (e.g., 12345 -> "12,345"). */
26
+ function formatNumber(n: number): string {
27
+ return n.toLocaleString("en-US");
28
+ }
29
+
30
+ /** Format a cost value as "$X.XX". Returns "$0.00" for null/undefined. */
31
+ function formatCost(cost: number | null): string {
32
+ if (cost === null || cost === undefined) {
33
+ return "$0.00";
34
+ }
35
+ return `$${cost.toFixed(2)}`;
36
+ }
37
+
38
+ /** Right-pad a string to the given width. */
39
+ function padRight(str: string, width: number): string {
40
+ return str.length >= width ? str : str + " ".repeat(width - str.length);
41
+ }
42
+
43
+ /** Left-pad a string to the given width. */
44
+ function padLeft(str: string, width: number): string {
45
+ return str.length >= width ? str : " ".repeat(width - str.length) + str;
46
+ }
47
+
48
+ /**
49
+ * Discover the orchestrator's transcript JSONL file for the given runtime.
50
+ *
51
+ * Scans the runtime-specific transcript directory for JSONL files and returns
52
+ * the most recently modified one, corresponding to the current orchestrator session.
53
+ *
54
+ * @param runtime - The agent runtime adapter
55
+ * @param projectRoot - Absolute path to the project root
56
+ * @returns Absolute path to the most recent transcript, or null if none found
57
+ */
58
+ async function discoverOrchestratorTranscript(
59
+ runtime: AgentRuntime,
60
+ projectRoot: string,
61
+ ): Promise<string | null> {
62
+ const transcriptDir = runtime.getTranscriptDir(projectRoot);
63
+ if (transcriptDir === null) return null;
64
+
65
+ let entries: string[];
66
+ try {
67
+ entries = await readdir(transcriptDir);
68
+ } catch {
69
+ return null;
70
+ }
71
+
72
+ const jsonlFiles = entries.filter((e) => e.endsWith(".jsonl"));
73
+ if (jsonlFiles.length === 0) return null;
74
+
75
+ let bestPath: string | null = null;
76
+ let bestMtime = 0;
77
+
78
+ for (const file of jsonlFiles) {
79
+ const filePath = join(transcriptDir, file);
80
+ try {
81
+ const fileStat = await stat(filePath);
82
+ if (fileStat.mtimeMs > bestMtime) {
83
+ bestMtime = fileStat.mtimeMs;
84
+ bestPath = filePath;
85
+ }
86
+ } catch {
87
+ // Skip files we cannot stat
88
+ }
89
+ }
90
+
91
+ return bestPath;
92
+ }
93
+
94
+ /** Aggregate totals from a list of SessionMetrics. */
95
+ interface Totals {
96
+ inputTokens: number;
97
+ outputTokens: number;
98
+ cacheTokens: number;
99
+ costUsd: number;
100
+ }
101
+
102
+ function computeTotals(sessions: SessionMetrics[]): Totals {
103
+ let inputTokens = 0;
104
+ let outputTokens = 0;
105
+ let cacheTokens = 0;
106
+ let costUsd = 0;
107
+ for (const s of sessions) {
108
+ inputTokens += s.inputTokens;
109
+ outputTokens += s.outputTokens;
110
+ cacheTokens += s.cacheReadTokens + s.cacheCreationTokens;
111
+ costUsd += s.estimatedCostUsd ?? 0;
112
+ }
113
+ return { inputTokens, outputTokens, cacheTokens, costUsd };
114
+ }
115
+
116
+ /** Group SessionMetrics by capability. */
117
+ interface CapabilityGroup {
118
+ capability: string;
119
+ sessions: SessionMetrics[];
120
+ totals: Totals;
121
+ }
122
+
123
+ function groupByCapability(sessions: SessionMetrics[]): CapabilityGroup[] {
124
+ const groups = new Map<string, SessionMetrics[]>();
125
+ for (const s of sessions) {
126
+ const existing = groups.get(s.capability);
127
+ if (existing) {
128
+ existing.push(s);
129
+ } else {
130
+ groups.set(s.capability, [s]);
131
+ }
132
+ }
133
+ const result: CapabilityGroup[] = [];
134
+ for (const [capability, capSessions] of groups) {
135
+ result.push({
136
+ capability,
137
+ sessions: capSessions,
138
+ totals: computeTotals(capSessions),
139
+ });
140
+ }
141
+ // Sort by cost descending
142
+ result.sort((a, b) => b.totals.costUsd - a.totals.costUsd);
143
+ return result;
144
+ }
145
+
146
+ /** Print the standard per-agent cost summary table. */
147
+ function printCostSummary(sessions: SessionMetrics[]): void {
148
+ const w = process.stdout.write.bind(process.stdout);
149
+
150
+ w(`${renderHeader("Cost Summary")}\n`);
151
+
152
+ if (sessions.length === 0) {
153
+ w(`${color.dim("No session data found.")}\n`);
154
+ return;
155
+ }
156
+
157
+ w(
158
+ `${padRight("Agent", 19)}${padRight("Capability", 12)}` +
159
+ `${padLeft("Input", 10)}${padLeft("Output", 10)}` +
160
+ `${padLeft("Cache", 10)}${padLeft("Cost", 10)}\n`,
161
+ );
162
+ w(`${color.dim(separator())}\n`);
163
+
164
+ for (const s of sessions) {
165
+ const cacheTotal = s.cacheReadTokens + s.cacheCreationTokens;
166
+ w(
167
+ `${padRight(s.agentName, 19)}${padRight(s.capability, 12)}` +
168
+ `${padLeft(formatNumber(s.inputTokens), 10)}` +
169
+ `${padLeft(formatNumber(s.outputTokens), 10)}` +
170
+ `${padLeft(formatNumber(cacheTotal), 10)}` +
171
+ `${padLeft(formatCost(s.estimatedCostUsd), 10)}\n`,
172
+ );
173
+ }
174
+
175
+ const totals = computeTotals(sessions);
176
+ w(`${color.dim(separator())}\n`);
177
+ w(
178
+ `${color.green(
179
+ color.bold(
180
+ padRight("Total", 31) +
181
+ padLeft(formatNumber(totals.inputTokens), 10) +
182
+ padLeft(formatNumber(totals.outputTokens), 10) +
183
+ padLeft(formatNumber(totals.cacheTokens), 10) +
184
+ padLeft(formatCost(totals.costUsd), 10),
185
+ ),
186
+ )}\n`,
187
+ );
188
+ }
189
+
190
+ /** Print the capability-grouped cost table. */
191
+ function printByCapability(sessions: SessionMetrics[]): void {
192
+ const w = process.stdout.write.bind(process.stdout);
193
+
194
+ w(`${renderHeader("Cost by Capability")}\n`);
195
+
196
+ if (sessions.length === 0) {
197
+ w(`${color.dim("No session data found.")}\n`);
198
+ return;
199
+ }
200
+
201
+ w(
202
+ `${padRight("Capability", 14)}${padLeft("Sessions", 10)}` +
203
+ `${padLeft("Input", 10)}${padLeft("Output", 10)}` +
204
+ `${padLeft("Cache", 10)}${padLeft("Cost", 10)}\n`,
205
+ );
206
+ w(`${color.dim(separator())}\n`);
207
+
208
+ const groups = groupByCapability(sessions);
209
+
210
+ for (const group of groups) {
211
+ w(
212
+ `${padRight(group.capability, 14)}` +
213
+ `${padLeft(formatNumber(group.sessions.length), 10)}` +
214
+ `${padLeft(formatNumber(group.totals.inputTokens), 10)}` +
215
+ `${padLeft(formatNumber(group.totals.outputTokens), 10)}` +
216
+ `${padLeft(formatNumber(group.totals.cacheTokens), 10)}` +
217
+ `${padLeft(formatCost(group.totals.costUsd), 10)}\n`,
218
+ );
219
+ }
220
+
221
+ const totals = computeTotals(sessions);
222
+ w(`${color.dim(separator())}\n`);
223
+ w(
224
+ `${color.green(
225
+ color.bold(
226
+ padRight("Total", 14) +
227
+ padLeft(formatNumber(sessions.length), 10) +
228
+ padLeft(formatNumber(totals.inputTokens), 10) +
229
+ padLeft(formatNumber(totals.outputTokens), 10) +
230
+ padLeft(formatNumber(totals.cacheTokens), 10) +
231
+ padLeft(formatCost(totals.costUsd), 10),
232
+ ),
233
+ )}\n`,
234
+ );
235
+ }
236
+
237
+ interface CostsOpts {
238
+ live?: boolean;
239
+ self?: boolean;
240
+ byCapability?: boolean;
241
+ agent?: string;
242
+ run?: string;
243
+ bead?: string;
244
+ last?: string;
245
+ json?: boolean;
246
+ }
247
+
248
+ async function executeCosts(opts: CostsOpts): Promise<void> {
249
+ const json = opts.json ?? false;
250
+ const live = opts.live ?? false;
251
+ const self = opts.self ?? false;
252
+ const byCapability = opts.byCapability ?? false;
253
+ const agentName = opts.agent;
254
+ const runId = opts.run;
255
+ const beadId = opts.bead;
256
+ const lastStr = opts.last;
257
+
258
+ if (lastStr !== undefined) {
259
+ const parsed = Number.parseInt(lastStr, 10);
260
+ if (Number.isNaN(parsed) || parsed < 1) {
261
+ throw new ValidationError("--last must be a positive integer", {
262
+ field: "last",
263
+ value: lastStr,
264
+ });
265
+ }
266
+ }
267
+
268
+ const last = lastStr ? Number.parseInt(lastStr, 10) : 20;
269
+
270
+ const cwd = process.cwd();
271
+ const config = await loadConfig(cwd);
272
+ const agentplateDir = join(config.project.root, ".agentplate");
273
+
274
+ // Handle --self flag (early return for self-scan)
275
+ if (self) {
276
+ const runtime = getRuntime(undefined, config);
277
+ const transcriptPath = await discoverOrchestratorTranscript(runtime, config.project.root);
278
+ if (!transcriptPath) {
279
+ if (json) {
280
+ jsonError("costs", `No transcript found for runtime '${runtime.id}'`);
281
+ } else {
282
+ process.stdout.write(
283
+ `No transcript found for runtime '${runtime.id}'.\n` +
284
+ "Transcript discovery may not be supported for this runtime.\n",
285
+ );
286
+ }
287
+ return;
288
+ }
289
+
290
+ const usage = await parseTranscriptUsage(transcriptPath);
291
+ const cost = estimateCost(usage);
292
+ const cacheTotal = usage.cacheReadTokens + usage.cacheCreationTokens;
293
+
294
+ if (json) {
295
+ jsonOutput("costs", {
296
+ source: "self",
297
+ transcriptPath,
298
+ model: usage.modelUsed,
299
+ inputTokens: usage.inputTokens,
300
+ outputTokens: usage.outputTokens,
301
+ cacheReadTokens: usage.cacheReadTokens,
302
+ cacheCreationTokens: usage.cacheCreationTokens,
303
+ estimatedCostUsd: cost,
304
+ });
305
+ } else {
306
+ const w = process.stdout.write.bind(process.stdout);
307
+
308
+ w(`${renderHeader("Orchestrator Session Cost")}\n`);
309
+ w(`${padRight("Model:", 12)}${usage.modelUsed ?? "unknown"}\n`);
310
+ w(`${padRight("Transcript:", 12)}${transcriptPath}\n`);
311
+ w(`${color.dim(separator())}\n`);
312
+ w(`${padRight("Input tokens:", 22)}${padLeft(formatNumber(usage.inputTokens), 12)}\n`);
313
+ w(`${padRight("Output tokens:", 22)}${padLeft(formatNumber(usage.outputTokens), 12)}\n`);
314
+ w(`${padRight("Cache tokens:", 22)}${padLeft(formatNumber(cacheTotal), 12)}\n`);
315
+ w(`${color.dim(separator())}\n`);
316
+ w(
317
+ `${color.green(color.bold(padRight("Estimated cost:", 22) + padLeft(formatCost(cost), 12)))}\n`,
318
+ );
319
+ }
320
+ return;
321
+ }
322
+
323
+ // Handle --live flag (early return for live view)
324
+ if (live) {
325
+ const metricsDbPath = join(agentplateDir, "metrics.db");
326
+ const metricsFile = Bun.file(metricsDbPath);
327
+ if (!(await metricsFile.exists())) {
328
+ if (json) {
329
+ jsonOutput("costs", {
330
+ agents: [],
331
+ totals: {
332
+ inputTokens: 0,
333
+ outputTokens: 0,
334
+ cacheTokens: 0,
335
+ costUsd: 0,
336
+ burnRatePerMin: 0,
337
+ tokensPerMin: 0,
338
+ },
339
+ });
340
+ } else {
341
+ process.stdout.write(
342
+ "No live data available. Token snapshots begin after first tool call.\n",
343
+ );
344
+ }
345
+ return;
346
+ }
347
+
348
+ const metricsStore = createMetricsStore(metricsDbPath);
349
+ const { store: sessionStore } = openSessionStore(agentplateDir);
350
+
351
+ try {
352
+ const snapshots = metricsStore.getLatestSnapshots(runId ?? undefined);
353
+ if (snapshots.length === 0) {
354
+ if (json) {
355
+ jsonOutput("costs", {
356
+ agents: [],
357
+ totals: {
358
+ inputTokens: 0,
359
+ outputTokens: 0,
360
+ cacheTokens: 0,
361
+ costUsd: 0,
362
+ burnRatePerMin: 0,
363
+ tokensPerMin: 0,
364
+ },
365
+ });
366
+ } else {
367
+ process.stdout.write(
368
+ "No live data available. Token snapshots begin after first tool call.\n",
369
+ );
370
+ }
371
+ return;
372
+ }
373
+
374
+ // Get active sessions to join with snapshots
375
+ const activeSessions = sessionStore.getActive();
376
+
377
+ // Filter snapshots by agent if --agent is provided
378
+ const filteredSnapshots = agentName
379
+ ? snapshots.filter((s) => s.agentName === agentName)
380
+ : snapshots;
381
+
382
+ // Build agent data with session info
383
+ interface LiveAgentData {
384
+ agentName: string;
385
+ capability: string;
386
+ inputTokens: number;
387
+ outputTokens: number;
388
+ cacheReadTokens: number;
389
+ cacheCreationTokens: number;
390
+ estimatedCostUsd: number;
391
+ modelUsed: string | null;
392
+ snapshotAt: string;
393
+ sessionStartedAt: string;
394
+ elapsedMs: number;
395
+ }
396
+
397
+ const agentData: LiveAgentData[] = [];
398
+ const now = Date.now();
399
+
400
+ for (const snapshot of filteredSnapshots) {
401
+ const session = activeSessions.find((s) => s.agentName === snapshot.agentName);
402
+ if (!session) continue; // Skip inactive agents
403
+
404
+ const startedAt = new Date(session.startedAt).getTime();
405
+ const elapsedMs = now - startedAt;
406
+
407
+ agentData.push({
408
+ agentName: snapshot.agentName,
409
+ capability: session.capability,
410
+ inputTokens: snapshot.inputTokens,
411
+ outputTokens: snapshot.outputTokens,
412
+ cacheReadTokens: snapshot.cacheReadTokens,
413
+ cacheCreationTokens: snapshot.cacheCreationTokens,
414
+ estimatedCostUsd: snapshot.estimatedCostUsd ?? 0,
415
+ modelUsed: snapshot.modelUsed,
416
+ snapshotAt: snapshot.createdAt,
417
+ sessionStartedAt: session.startedAt,
418
+ elapsedMs,
419
+ });
420
+ }
421
+
422
+ // Compute totals
423
+ let totalInput = 0;
424
+ let totalOutput = 0;
425
+ let totalCacheRead = 0;
426
+ let totalCacheCreate = 0;
427
+ let totalCost = 0;
428
+ let totalElapsedMs = 0;
429
+
430
+ for (const agent of agentData) {
431
+ totalInput += agent.inputTokens;
432
+ totalOutput += agent.outputTokens;
433
+ totalCacheRead += agent.cacheReadTokens;
434
+ totalCacheCreate += agent.cacheCreationTokens;
435
+ totalCost += agent.estimatedCostUsd;
436
+ totalElapsedMs += agent.elapsedMs;
437
+ }
438
+
439
+ const avgElapsedMs = agentData.length > 0 ? totalElapsedMs / agentData.length : 0;
440
+ const totalCacheTokens = totalCacheRead + totalCacheCreate;
441
+ const totalTokens = totalInput + totalOutput;
442
+ const burnRatePerMin = avgElapsedMs > 0 ? totalCost / (avgElapsedMs / 60_000) : 0;
443
+ const tokensPerMin = avgElapsedMs > 0 ? totalTokens / (avgElapsedMs / 60_000) : 0;
444
+
445
+ if (json) {
446
+ jsonOutput("costs", {
447
+ agents: agentData,
448
+ totals: {
449
+ inputTokens: totalInput,
450
+ outputTokens: totalOutput,
451
+ cacheTokens: totalCacheTokens,
452
+ costUsd: totalCost,
453
+ burnRatePerMin,
454
+ tokensPerMin,
455
+ },
456
+ });
457
+ } else {
458
+ const w = process.stdout.write.bind(process.stdout);
459
+
460
+ w(`${renderHeader(`Live Token Usage (${agentData.length} active agents)`)}\n`);
461
+ w(
462
+ `${padRight("Agent", 19)}${padRight("Capability", 12)}` +
463
+ `${padLeft("Input", 10)}${padLeft("Output", 10)}` +
464
+ `${padLeft("Cache", 10)}${padLeft("Cost", 10)}\n`,
465
+ );
466
+ w(`${color.dim(separator())}\n`);
467
+
468
+ for (const agent of agentData) {
469
+ const cacheTotal = agent.cacheReadTokens + agent.cacheCreationTokens;
470
+ w(
471
+ `${padRight(agent.agentName, 19)}${padRight(agent.capability, 12)}` +
472
+ `${padLeft(formatNumber(agent.inputTokens), 10)}` +
473
+ `${padLeft(formatNumber(agent.outputTokens), 10)}` +
474
+ `${padLeft(formatNumber(cacheTotal), 10)}` +
475
+ `${padLeft(formatCost(agent.estimatedCostUsd), 10)}\n`,
476
+ );
477
+ }
478
+
479
+ w(`${color.dim(separator())}\n`);
480
+ w(
481
+ `${color.green(
482
+ color.bold(
483
+ padRight("Total", 31) +
484
+ padLeft(formatNumber(totalInput), 10) +
485
+ padLeft(formatNumber(totalOutput), 10) +
486
+ padLeft(formatNumber(totalCacheTokens), 10) +
487
+ padLeft(formatCost(totalCost), 10),
488
+ ),
489
+ )}\n\n`,
490
+ );
491
+
492
+ // Format elapsed time
493
+ const totalElapsedSec = Math.floor(avgElapsedMs / 1000);
494
+ const minutes = Math.floor(totalElapsedSec / 60);
495
+ const seconds = totalElapsedSec % 60;
496
+ const elapsedStr = `${minutes}m ${seconds}s`;
497
+
498
+ w(
499
+ `Burn rate: ${formatCost(burnRatePerMin)}/min | ` +
500
+ `${formatNumber(Math.floor(tokensPerMin))} tokens/min | ` +
501
+ `Elapsed: ${elapsedStr}\n`,
502
+ );
503
+ }
504
+ } finally {
505
+ metricsStore.close();
506
+ sessionStore.close();
507
+ }
508
+ return;
509
+ }
510
+
511
+ // Check if metrics.db exists
512
+ const metricsDbPath = join(agentplateDir, "metrics.db");
513
+ const metricsFile = Bun.file(metricsDbPath);
514
+ if (!(await metricsFile.exists())) {
515
+ if (json) {
516
+ jsonOutput("costs", { sessions: [] });
517
+ } else {
518
+ process.stdout.write("No metrics data yet.\n");
519
+ }
520
+ return;
521
+ }
522
+
523
+ const metricsStore = createMetricsStore(metricsDbPath);
524
+
525
+ try {
526
+ let sessions: SessionMetrics[];
527
+
528
+ if (agentName !== undefined) {
529
+ sessions = metricsStore.getSessionsByAgent(agentName);
530
+ } else if (runId !== undefined) {
531
+ sessions = metricsStore.getSessionsByRun(runId);
532
+ } else if (beadId !== undefined) {
533
+ sessions = metricsStore.getSessionsByTask(beadId);
534
+ } else {
535
+ sessions = metricsStore.getRecentSessions(last);
536
+ }
537
+
538
+ if (json) {
539
+ if (byCapability) {
540
+ const groups = groupByCapability(sessions);
541
+ const grouped: Record<string, { sessions: SessionMetrics[]; totals: Totals }> = {};
542
+ for (const group of groups) {
543
+ grouped[group.capability] = {
544
+ sessions: group.sessions,
545
+ totals: group.totals,
546
+ };
547
+ }
548
+ jsonOutput("costs", { grouped });
549
+ } else {
550
+ jsonOutput("costs", { sessions });
551
+ }
552
+ return;
553
+ }
554
+
555
+ if (byCapability) {
556
+ printByCapability(sessions);
557
+ } else {
558
+ printCostSummary(sessions);
559
+ }
560
+ } finally {
561
+ metricsStore.close();
562
+ }
563
+ }
564
+
565
+ export function createCostsCommand(): Command {
566
+ return new Command("costs")
567
+ .description("Token/cost analysis and breakdown")
568
+ .option("--live", "Show real-time token usage for active agents")
569
+ .option("--self", "Show cost for the current orchestrator session")
570
+ .option("--agent <name>", "Filter by agent name")
571
+ .option("--run <id>", "Filter by run ID")
572
+ .option("--bead <id>", "Show cost breakdown for a specific task/bead")
573
+ .option("--by-capability", "Group results by capability with subtotals")
574
+ .option("--last <n>", "Number of recent sessions (default: 20)")
575
+ .option("--json", "Output as JSON")
576
+ .action(async (opts: CostsOpts) => {
577
+ await executeCosts(opts);
578
+ });
579
+ }
580
+
581
+ export async function costsCommand(args: string[]): Promise<void> {
582
+ const cmd = createCostsCommand();
583
+ cmd.exitOverride();
584
+ try {
585
+ await cmd.parseAsync(args, { from: "user" });
586
+ } catch (err: unknown) {
587
+ if (err && typeof err === "object" && "code" in err) {
588
+ const code = (err as { code: string }).code;
589
+ if (code === "commander.helpDisplayed" || code === "commander.version") {
590
+ return;
591
+ }
592
+ if (code.startsWith("commander.")) {
593
+ const message = err instanceof Error ? err.message : String(err);
594
+ throw new ValidationError(message, { field: "args" });
595
+ }
596
+ }
597
+ throw err;
598
+ }
599
+ }