@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,328 @@
1
+ /**
2
+ * Tests for the agents command.
3
+ */
4
+
5
+ import { afterEach, beforeEach, describe, expect, it, mock } from "bun:test";
6
+ import { mkdtemp } from "node:fs/promises";
7
+ import { tmpdir } from "node:os";
8
+ import { join } from "node:path";
9
+ import { createSessionStore } from "../sessions/store.ts";
10
+ import { cleanupTempDir } from "../test-helpers.ts";
11
+ import type { AgentSession } from "../types.ts";
12
+ import { agentsCommand, discoverAgents, extractFileScope } from "./agents.ts";
13
+
14
+ describe("extractFileScope", () => {
15
+ let tempDir: string;
16
+
17
+ beforeEach(async () => {
18
+ tempDir = await mkdtemp(join(tmpdir(), "agentplate-test-"));
19
+ });
20
+
21
+ it("should return empty array when overlay doesn't exist", async () => {
22
+ const scope = await extractFileScope(tempDir);
23
+ expect(scope).toEqual([]);
24
+ });
25
+
26
+ it("should return empty array when 'No file scope restrictions'", async () => {
27
+ const overlayPath = join(tempDir, ".claude", "CLAUDE.md");
28
+ const content = `# Agent Overlay
29
+
30
+ ## File Scope (exclusive ownership)
31
+
32
+ No file scope restrictions. You may modify any file in the worktree.
33
+
34
+ ## Expertise
35
+
36
+ Some expertise here.
37
+ `;
38
+ await Bun.write(overlayPath, content);
39
+ const scope = await extractFileScope(tempDir);
40
+ expect(scope).toEqual([]);
41
+ });
42
+
43
+ it("should extract file paths from valid overlay", async () => {
44
+ const overlayPath = join(tempDir, ".claude", "CLAUDE.md");
45
+ const content = `# Agent Overlay
46
+
47
+ ## File Scope (exclusive ownership)
48
+
49
+ These files are yours to modify:
50
+
51
+ - \`src/commands/agents.ts\`
52
+ - \`src/commands/agents.test.ts\`
53
+ - \`src/index.ts\`
54
+
55
+ ## Expertise
56
+
57
+ Some expertise here.
58
+ `;
59
+ await Bun.write(overlayPath, content);
60
+ const scope = await extractFileScope(tempDir);
61
+ expect(scope).toEqual([
62
+ "src/commands/agents.ts",
63
+ "src/commands/agents.test.ts",
64
+ "src/index.ts",
65
+ ]);
66
+ });
67
+
68
+ afterEach(async () => {
69
+ await cleanupTempDir(tempDir);
70
+ });
71
+ });
72
+
73
+ describe("discoverAgents", () => {
74
+ let tempDir: string;
75
+ let dbPath: string;
76
+
77
+ beforeEach(async () => {
78
+ tempDir = await mkdtemp(join(tmpdir(), "agentplate-test-"));
79
+ const agentplateDir = join(tempDir, ".agentplate");
80
+ await Bun.write(join(agentplateDir, ".gitkeep"), "");
81
+ dbPath = join(agentplateDir, "sessions.db");
82
+ });
83
+
84
+ it("should return empty when no sessions", async () => {
85
+ const store = createSessionStore(dbPath);
86
+ store.close();
87
+
88
+ const agents = await discoverAgents(tempDir);
89
+ expect(agents).toEqual([]);
90
+ });
91
+
92
+ it("should return active agents", async () => {
93
+ const store = createSessionStore(dbPath);
94
+
95
+ const session: AgentSession = {
96
+ id: "session-1",
97
+ agentName: "builder-test",
98
+ capability: "builder",
99
+ worktreePath: join(tempDir, ".agentplate", "worktrees", "builder-test"),
100
+ branchName: "agentplate/builder-test/task-123",
101
+ taskId: "task-123",
102
+ tmuxSession: "agentplate-test-builder",
103
+ state: "working",
104
+ pid: 12345,
105
+ parentAgent: null,
106
+ depth: 0,
107
+ runId: "run-1",
108
+ startedAt: "2024-01-01T00:00:00Z",
109
+ lastActivity: "2024-01-01T00:01:00Z",
110
+ escalationLevel: 0,
111
+ stalledSince: null,
112
+ transcriptPath: null,
113
+ };
114
+
115
+ store.upsert(session);
116
+ store.close();
117
+
118
+ const agents = await discoverAgents(tempDir);
119
+ expect(agents).toHaveLength(1);
120
+ expect(agents[0]?.agentName).toBe("builder-test");
121
+ expect(agents[0]?.capability).toBe("builder");
122
+ expect(agents[0]?.state).toBe("working");
123
+ });
124
+
125
+ it("should filter by capability", async () => {
126
+ const store = createSessionStore(dbPath);
127
+
128
+ const builder: AgentSession = {
129
+ id: "session-1",
130
+ agentName: "builder-test",
131
+ capability: "builder",
132
+ worktreePath: join(tempDir, ".agentplate", "worktrees", "builder-test"),
133
+ branchName: "agentplate/builder-test/task-123",
134
+ taskId: "task-123",
135
+ tmuxSession: "agentplate-test-builder",
136
+ state: "working",
137
+ pid: 12345,
138
+ parentAgent: null,
139
+ depth: 0,
140
+ runId: "run-1",
141
+ startedAt: "2024-01-01T00:00:00Z",
142
+ lastActivity: "2024-01-01T00:01:00Z",
143
+ escalationLevel: 0,
144
+ stalledSince: null,
145
+ transcriptPath: null,
146
+ };
147
+
148
+ const scout: AgentSession = {
149
+ id: "session-2",
150
+ agentName: "scout-test",
151
+ capability: "scout",
152
+ worktreePath: join(tempDir, ".agentplate", "worktrees", "scout-test"),
153
+ branchName: "agentplate/scout-test/task-456",
154
+ taskId: "task-456",
155
+ tmuxSession: "agentplate-test-scout",
156
+ state: "working",
157
+ pid: 12346,
158
+ parentAgent: null,
159
+ depth: 0,
160
+ runId: "run-1",
161
+ startedAt: "2024-01-01T00:00:00Z",
162
+ lastActivity: "2024-01-01T00:01:00Z",
163
+ escalationLevel: 0,
164
+ stalledSince: null,
165
+ transcriptPath: null,
166
+ };
167
+
168
+ store.upsert(builder);
169
+ store.upsert(scout);
170
+ store.close();
171
+
172
+ const agents = await discoverAgents(tempDir, { capability: "builder" });
173
+ expect(agents).toHaveLength(1);
174
+ expect(agents[0]?.agentName).toBe("builder-test");
175
+ expect(agents[0]?.capability).toBe("builder");
176
+ });
177
+
178
+ it("should includeAll returns completed agents too", async () => {
179
+ const store = createSessionStore(dbPath);
180
+
181
+ const working: AgentSession = {
182
+ id: "session-1",
183
+ agentName: "builder-working",
184
+ capability: "builder",
185
+ worktreePath: join(tempDir, ".agentplate", "worktrees", "builder-working"),
186
+ branchName: "agentplate/builder-working/task-123",
187
+ taskId: "task-123",
188
+ tmuxSession: "agentplate-test-working",
189
+ state: "working",
190
+ pid: 12345,
191
+ parentAgent: null,
192
+ depth: 0,
193
+ runId: "run-1",
194
+ startedAt: "2024-01-01T00:00:00Z",
195
+ lastActivity: "2024-01-01T00:01:00Z",
196
+ escalationLevel: 0,
197
+ stalledSince: null,
198
+ transcriptPath: null,
199
+ };
200
+
201
+ const completed: AgentSession = {
202
+ id: "session-2",
203
+ agentName: "builder-completed",
204
+ capability: "builder",
205
+ worktreePath: join(tempDir, ".agentplate", "worktrees", "builder-completed"),
206
+ branchName: "agentplate/builder-completed/task-456",
207
+ taskId: "task-456",
208
+ tmuxSession: "agentplate-test-completed",
209
+ state: "completed",
210
+ pid: null,
211
+ parentAgent: null,
212
+ depth: 0,
213
+ runId: "run-1",
214
+ startedAt: "2024-01-01T00:00:00Z",
215
+ lastActivity: "2024-01-01T00:02:00Z",
216
+ escalationLevel: 0,
217
+ stalledSince: null,
218
+ transcriptPath: null,
219
+ };
220
+
221
+ store.upsert(working);
222
+ store.upsert(completed);
223
+ store.close();
224
+
225
+ // Without includeAll, only active agents
226
+ const activeAgents = await discoverAgents(tempDir);
227
+ expect(activeAgents).toHaveLength(1);
228
+ expect(activeAgents[0]?.agentName).toBe("builder-working");
229
+
230
+ // With includeAll, both working and completed
231
+ const allAgents = await discoverAgents(tempDir, { includeAll: true });
232
+ expect(allAgents).toHaveLength(2);
233
+ const names = allAgents.map((a) => a.agentName);
234
+ expect(names).toContain("builder-working");
235
+ expect(names).toContain("builder-completed");
236
+ });
237
+
238
+ afterEach(async () => {
239
+ await cleanupTempDir(tempDir);
240
+ });
241
+ });
242
+
243
+ describe("agentsCommand", () => {
244
+ let tempDir: string;
245
+ let originalCwd: string;
246
+ let originalStdoutWrite: typeof process.stdout.write;
247
+ let stdoutBuffer: string;
248
+
249
+ beforeEach(async () => {
250
+ tempDir = await mkdtemp(join(tmpdir(), "agentplate-test-"));
251
+ const agentplateDir = join(tempDir, ".agentplate");
252
+
253
+ // Create config.yaml
254
+ const configContent = `project:
255
+ name: test-project
256
+ root: ${tempDir}
257
+ canonicalBranch: main
258
+ agents:
259
+ manifestPath: .agentplate/agent-manifest.json
260
+ baseDir: agents
261
+ maxConcurrent: 5
262
+ staggerDelayMs: 100
263
+ maxDepth: 2
264
+ worktrees:
265
+ baseDir: .agentplate/worktrees
266
+ beads:
267
+ enabled: true
268
+ loam:
269
+ enabled: true
270
+ domains: []
271
+ primeFormat: markdown
272
+ merge:
273
+ aiResolveEnabled: false
274
+ reimagineEnabled: false
275
+ watchdog:
276
+ tier0Enabled: false
277
+ tier0IntervalMs: 30000
278
+ tier1Enabled: false
279
+ tier2Enabled: false
280
+ staleThresholdMs: 300000
281
+ zombieThresholdMs: 600000
282
+ nudgeIntervalMs: 60000
283
+ logging:
284
+ verbose: false
285
+ redactSecrets: true
286
+ `;
287
+ await Bun.write(join(agentplateDir, "config.yaml"), configContent);
288
+
289
+ // Create sessions.db
290
+ const dbPath = join(agentplateDir, "sessions.db");
291
+ const store = createSessionStore(dbPath);
292
+ store.close();
293
+
294
+ // Mock stdout.write
295
+ stdoutBuffer = "";
296
+ originalStdoutWrite = process.stdout.write;
297
+ process.stdout.write = mock((chunk: unknown) => {
298
+ stdoutBuffer += String(chunk);
299
+ return true;
300
+ });
301
+
302
+ // Change to temp dir
303
+ originalCwd = process.cwd();
304
+ process.chdir(tempDir);
305
+ });
306
+
307
+ it("should show help with --help flag", async () => {
308
+ await agentsCommand(["--help"]);
309
+ expect(stdoutBuffer).toContain("agents");
310
+ expect(stdoutBuffer).toContain("discover");
311
+ });
312
+
313
+ it("should show help with no subcommand", async () => {
314
+ await agentsCommand([]);
315
+ expect(stdoutBuffer).toContain("agents");
316
+ expect(stdoutBuffer).toContain("discover");
317
+ });
318
+
319
+ it("should error on unknown subcommand", async () => {
320
+ await expect(agentsCommand(["unknown"])).rejects.toThrow("unknown command");
321
+ });
322
+
323
+ afterEach(async () => {
324
+ process.stdout.write = originalStdoutWrite;
325
+ process.chdir(originalCwd);
326
+ await cleanupTempDir(tempDir);
327
+ });
328
+ });
@@ -0,0 +1,299 @@
1
+ /**
2
+ * CLI command: ap agents <sub> [--json]
3
+ *
4
+ * Discover and query agents by capability.
5
+ */
6
+
7
+ import { join } from "node:path";
8
+ import { Command } from "commander";
9
+ import { loadConfig } from "../config.ts";
10
+ import { ValidationError } from "../errors.ts";
11
+ import { jsonOutput } from "../json.ts";
12
+ import { accent, color } from "../logging/color.ts";
13
+ import { getAllRuntimes, getRuntime } from "../runtimes/registry.ts";
14
+ import { openSessionStore } from "../sessions/compat.ts";
15
+ import { type AgentSession, SUPPORTED_CAPABILITIES } from "../types.ts";
16
+
17
+ /**
18
+ * Discovered agent information including file scope.
19
+ */
20
+ export interface DiscoveredAgent {
21
+ agentName: string;
22
+ capability: string;
23
+ state: string;
24
+ taskId: string;
25
+ branchName: string;
26
+ parentAgent: string | null;
27
+ depth: number;
28
+ fileScope: string[];
29
+ startedAt: string;
30
+ lastActivity: string;
31
+ }
32
+
33
+ /** Build the list of known instruction file paths from all registered runtimes. */
34
+ function getKnownInstructionPaths(): string[] {
35
+ return [...new Set(getAllRuntimes().map((r) => r.instructionPath))];
36
+ }
37
+
38
+ /**
39
+ * Extract file scope from an agent's overlay instruction file.
40
+ * Returns empty array if no overlay exists, has no file scope restrictions,
41
+ * or can't be read.
42
+ *
43
+ * @param worktreePath - Absolute path to the agent's worktree
44
+ * @param runtimeInstructionPath - Optional runtime-specific instruction path to try first
45
+ * @returns Array of file paths (relative to worktree root)
46
+ */
47
+ export async function extractFileScope(
48
+ worktreePath: string,
49
+ runtimeInstructionPath?: string,
50
+ ): Promise<string[]> {
51
+ try {
52
+ let content: string | null = null;
53
+ const knownPaths = getKnownInstructionPaths();
54
+ const pathsToTry = runtimeInstructionPath
55
+ ? [runtimeInstructionPath, ...knownPaths]
56
+ : knownPaths;
57
+ for (const relPath of pathsToTry) {
58
+ const overlayPath = join(worktreePath, relPath);
59
+ const overlayFile = Bun.file(overlayPath);
60
+ if (await overlayFile.exists()) {
61
+ content = await overlayFile.text();
62
+ break;
63
+ }
64
+ }
65
+ if (content === null) {
66
+ return [];
67
+ }
68
+
69
+ // Find the section between "## File Scope (exclusive ownership)" and "## Expertise"
70
+ const startMarker = "## File Scope (exclusive ownership)";
71
+ const endMarker = "## Expertise";
72
+
73
+ const startIdx = content.indexOf(startMarker);
74
+ if (startIdx === -1) {
75
+ return [];
76
+ }
77
+
78
+ const endIdx = content.indexOf(endMarker, startIdx);
79
+ if (endIdx === -1) {
80
+ return [];
81
+ }
82
+
83
+ const section = content.slice(startIdx, endIdx);
84
+
85
+ // Check for "No file scope restrictions"
86
+ if (section.includes("No file scope restrictions")) {
87
+ return [];
88
+ }
89
+
90
+ // Extract file paths from markdown list items: - `path`
91
+ const paths: string[] = [];
92
+ const regex = /^- `(.+)`$/gm;
93
+ let match = regex.exec(section);
94
+
95
+ while (match !== null) {
96
+ if (match[1]) {
97
+ paths.push(match[1]);
98
+ }
99
+ match = regex.exec(section);
100
+ }
101
+
102
+ return paths;
103
+ } catch {
104
+ // Best effort: return empty array if anything fails
105
+ return [];
106
+ }
107
+ }
108
+
109
+ /**
110
+ * Discover agents in the project.
111
+ *
112
+ * @param root - Absolute path to project root
113
+ * @param opts - Filter options
114
+ * @returns Array of discovered agents with file scopes
115
+ */
116
+ export async function discoverAgents(
117
+ root: string,
118
+ opts?: { capability?: string; includeAll?: boolean },
119
+ ): Promise<DiscoveredAgent[]> {
120
+ const agentplateDir = join(root, ".agentplate");
121
+ const { store } = openSessionStore(agentplateDir);
122
+
123
+ // Resolve runtime instruction path from config; fall back gracefully if config is absent.
124
+ let runtimeInstructionPath: string | undefined;
125
+ try {
126
+ const config = await loadConfig(root);
127
+ const runtime = getRuntime(undefined, config);
128
+ runtimeInstructionPath = runtime.instructionPath;
129
+ } catch {
130
+ // Config may not exist in all contexts; KNOWN_INSTRUCTION_PATHS will be used as fallback.
131
+ }
132
+
133
+ try {
134
+ const sessions: AgentSession[] = opts?.includeAll ? store.getAll() : store.getActive();
135
+
136
+ // Filter by capability if specified
137
+ let filteredSessions = sessions;
138
+ if (opts?.capability) {
139
+ filteredSessions = sessions.filter((s) => s.capability === opts.capability);
140
+ }
141
+
142
+ // Extract file scopes for each agent
143
+ const agents: DiscoveredAgent[] = await Promise.all(
144
+ filteredSessions.map(async (session) => {
145
+ const fileScope = await extractFileScope(session.worktreePath, runtimeInstructionPath);
146
+ return {
147
+ agentName: session.agentName,
148
+ capability: session.capability,
149
+ state: session.state,
150
+ taskId: session.taskId,
151
+ branchName: session.branchName,
152
+ parentAgent: session.parentAgent,
153
+ depth: session.depth,
154
+ fileScope,
155
+ startedAt: session.startedAt,
156
+ lastActivity: session.lastActivity,
157
+ };
158
+ }),
159
+ );
160
+
161
+ return agents;
162
+ } finally {
163
+ store.close();
164
+ }
165
+ }
166
+
167
+ /**
168
+ * Format the state icon for display.
169
+ *
170
+ * `in_turn` and `between_turns` (agentplate-3087) render with the same cyan
171
+ * accent as `working` so a spawn-per-turn worker is visually grouped with
172
+ * other healthy/active agents in `ap agents` output. They use distinct
173
+ * glyphs ('>' vs '~') to mirror the dashboard / theme.ts mapping.
174
+ */
175
+ function getStateIcon(state: string): string {
176
+ switch (state) {
177
+ case "working":
178
+ return color.cyan(">");
179
+ case "in_turn":
180
+ return color.cyan(">");
181
+ case "between_turns":
182
+ return color.cyan("~");
183
+ case "booting":
184
+ return color.green("-");
185
+ case "stalled":
186
+ return color.yellow("!");
187
+ default:
188
+ return " ";
189
+ }
190
+ }
191
+
192
+ /**
193
+ * Print discovered agents in human-readable format.
194
+ */
195
+ function printAgents(agents: DiscoveredAgent[]): void {
196
+ const w = process.stdout.write.bind(process.stdout);
197
+
198
+ if (agents.length === 0) {
199
+ w("No agents found.\n");
200
+ return;
201
+ }
202
+
203
+ w(`Found ${agents.length} agent${agents.length === 1 ? "" : "s"}:\n\n`);
204
+
205
+ for (const agent of agents) {
206
+ const icon = getStateIcon(agent.state);
207
+ w(` ${icon} ${accent(agent.agentName)} [${agent.capability}]\n`);
208
+ w(` State: ${agent.state} | Task: ${accent(agent.taskId)}\n`);
209
+ w(` Branch: ${accent(agent.branchName)}\n`);
210
+ w(
211
+ ` Parent: ${agent.parentAgent ? accent(agent.parentAgent) : "none"} | Depth: ${agent.depth}\n`,
212
+ );
213
+
214
+ if (agent.fileScope.length === 0) {
215
+ w(" Files: (unrestricted)\n");
216
+ } else {
217
+ w(` Files: ${agent.fileScope.join(", ")}\n`);
218
+ }
219
+
220
+ w("\n");
221
+ }
222
+ }
223
+
224
+ /**
225
+ * Create the Commander command for `ap agents`.
226
+ */
227
+ export function createAgentsCommand(): Command {
228
+ const cmd = new Command("agents").description("Discover and query agents");
229
+
230
+ cmd
231
+ .command("discover")
232
+ .description("Find active agents by capability")
233
+ .option(
234
+ "--capability <type>",
235
+ "Filter by capability (builder, scout, reviewer, lead, merger, orchestrator, coordinator, supervisor)",
236
+ )
237
+ .option("--all", "Include completed and zombie agents (default: active only)")
238
+ .option("--json", "Output as JSON")
239
+ .action(async (opts: { capability?: string; all?: boolean; json?: boolean }) => {
240
+ const capability = opts.capability;
241
+
242
+ // Validate capability if provided
243
+ if (capability && !SUPPORTED_CAPABILITIES.includes(capability as never)) {
244
+ throw new ValidationError(
245
+ `Invalid capability: ${capability}. Must be one of: ${SUPPORTED_CAPABILITIES.join(", ")}`,
246
+ {
247
+ field: "capability",
248
+ value: capability,
249
+ },
250
+ );
251
+ }
252
+
253
+ const cwd = process.cwd();
254
+ const config = await loadConfig(cwd);
255
+ const root = config.project.root;
256
+
257
+ const agents = await discoverAgents(root, {
258
+ capability,
259
+ includeAll: opts.all ?? false,
260
+ });
261
+
262
+ if (opts.json) {
263
+ jsonOutput("agents discover", { agents });
264
+ } else {
265
+ printAgents(agents);
266
+ }
267
+ });
268
+
269
+ return cmd;
270
+ }
271
+
272
+ /**
273
+ * Entry point for `ap agents <subcommand>`.
274
+ */
275
+ export async function agentsCommand(args: string[]): Promise<void> {
276
+ const cmd = createAgentsCommand();
277
+ cmd.exitOverride();
278
+
279
+ if (args.length === 0) {
280
+ process.stdout.write(cmd.helpInformation());
281
+ return;
282
+ }
283
+
284
+ try {
285
+ await cmd.parseAsync(args, { from: "user" });
286
+ } catch (err: unknown) {
287
+ if (err && typeof err === "object" && "code" in err) {
288
+ const code = (err as { code: string }).code;
289
+ if (code === "commander.helpDisplayed" || code === "commander.version") {
290
+ return;
291
+ }
292
+ if (code === "commander.unknownCommand") {
293
+ const message = err instanceof Error ? err.message : String(err);
294
+ throw new ValidationError(message, { field: "subcommand" });
295
+ }
296
+ }
297
+ throw err;
298
+ }
299
+ }