@swarmify/agents-cli 1.12.0 → 1.13.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (539) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/LICENSE +21 -0
  3. package/README.md +212 -232
  4. package/dist/commands/__tests__/sessions.test.js +90 -20
  5. package/dist/commands/__tests__/sessions.test.js.map +1 -1
  6. package/dist/commands/cloud.d.ts +11 -0
  7. package/dist/commands/cloud.d.ts.map +1 -0
  8. package/dist/commands/cloud.js +363 -0
  9. package/dist/commands/cloud.js.map +1 -0
  10. package/dist/commands/commands.d.ts +9 -0
  11. package/dist/commands/commands.d.ts.map +1 -1
  12. package/dist/commands/commands.js +330 -139
  13. package/dist/commands/commands.js.map +1 -1
  14. package/dist/commands/daemon.d.ts +8 -0
  15. package/dist/commands/daemon.d.ts.map +1 -1
  16. package/dist/commands/daemon.js +38 -222
  17. package/dist/commands/daemon.js.map +1 -1
  18. package/dist/commands/drive.d.ts +8 -0
  19. package/dist/commands/drive.d.ts.map +1 -1
  20. package/dist/commands/drive.js +70 -7
  21. package/dist/commands/drive.js.map +1 -1
  22. package/dist/commands/exec.d.ts +9 -1
  23. package/dist/commands/exec.d.ts.map +1 -1
  24. package/dist/commands/exec.js +198 -24
  25. package/dist/commands/exec.js.map +1 -1
  26. package/dist/commands/factory.d.ts +11 -0
  27. package/dist/commands/factory.d.ts.map +1 -0
  28. package/dist/commands/factory.js +445 -0
  29. package/dist/commands/factory.js.map +1 -0
  30. package/dist/commands/fork.d.ts +8 -0
  31. package/dist/commands/fork.d.ts.map +1 -1
  32. package/dist/commands/fork.js +38 -4
  33. package/dist/commands/fork.js.map +1 -1
  34. package/dist/commands/hooks.d.ts +9 -0
  35. package/dist/commands/hooks.d.ts.map +1 -1
  36. package/dist/commands/hooks.js +252 -18
  37. package/dist/commands/hooks.js.map +1 -1
  38. package/dist/commands/init.d.ts +15 -0
  39. package/dist/commands/init.d.ts.map +1 -0
  40. package/dist/commands/init.js +137 -0
  41. package/dist/commands/init.js.map +1 -0
  42. package/dist/commands/mcp.d.ts +9 -0
  43. package/dist/commands/mcp.d.ts.map +1 -1
  44. package/dist/commands/mcp.js +250 -169
  45. package/dist/commands/mcp.js.map +1 -1
  46. package/dist/commands/models.d.ts +11 -0
  47. package/dist/commands/models.d.ts.map +1 -0
  48. package/dist/commands/models.js +170 -0
  49. package/dist/commands/models.js.map +1 -0
  50. package/dist/commands/packages.d.ts +8 -0
  51. package/dist/commands/packages.d.ts.map +1 -1
  52. package/dist/commands/packages.js +155 -14
  53. package/dist/commands/packages.js.map +1 -1
  54. package/dist/commands/permissions.d.ts +9 -0
  55. package/dist/commands/permissions.d.ts.map +1 -1
  56. package/dist/commands/permissions.js +72 -13
  57. package/dist/commands/permissions.js.map +1 -1
  58. package/dist/commands/plugins.d.ts +8 -0
  59. package/dist/commands/plugins.d.ts.map +1 -1
  60. package/dist/commands/plugins.js +265 -44
  61. package/dist/commands/plugins.js.map +1 -1
  62. package/dist/commands/profiles.d.ts +12 -0
  63. package/dist/commands/profiles.d.ts.map +1 -0
  64. package/dist/commands/profiles.js +255 -0
  65. package/dist/commands/profiles.js.map +1 -0
  66. package/dist/commands/pty.d.ts +1 -0
  67. package/dist/commands/pty.d.ts.map +1 -1
  68. package/dist/commands/pty.js +133 -22
  69. package/dist/commands/pty.js.map +1 -1
  70. package/dist/commands/pull.d.ts +8 -0
  71. package/dist/commands/pull.d.ts.map +1 -1
  72. package/dist/commands/pull.js +103 -14
  73. package/dist/commands/pull.js.map +1 -1
  74. package/dist/commands/push.d.ts +8 -0
  75. package/dist/commands/push.d.ts.map +1 -1
  76. package/dist/commands/push.js +37 -3
  77. package/dist/commands/push.js.map +1 -1
  78. package/dist/commands/refresh-memory.d.ts +16 -0
  79. package/dist/commands/refresh-memory.d.ts.map +1 -0
  80. package/dist/commands/refresh-memory.js +52 -0
  81. package/dist/commands/refresh-memory.js.map +1 -0
  82. package/dist/commands/resource-view.d.ts +39 -0
  83. package/dist/commands/resource-view.d.ts.map +1 -0
  84. package/dist/commands/resource-view.js +197 -0
  85. package/dist/commands/resource-view.js.map +1 -0
  86. package/dist/commands/routines.d.ts +8 -0
  87. package/dist/commands/routines.d.ts.map +1 -1
  88. package/dist/commands/routines.js +163 -34
  89. package/dist/commands/routines.js.map +1 -1
  90. package/dist/commands/rules.d.ts +9 -0
  91. package/dist/commands/rules.d.ts.map +1 -1
  92. package/dist/commands/rules.js +83 -12
  93. package/dist/commands/rules.js.map +1 -1
  94. package/dist/commands/secrets.d.ts +11 -0
  95. package/dist/commands/secrets.d.ts.map +1 -0
  96. package/dist/commands/secrets.js +352 -0
  97. package/dist/commands/secrets.js.map +1 -0
  98. package/dist/commands/sessions-picker.d.ts +18 -0
  99. package/dist/commands/sessions-picker.d.ts.map +1 -0
  100. package/dist/commands/sessions-picker.js +265 -0
  101. package/dist/commands/sessions-picker.js.map +1 -0
  102. package/dist/commands/sessions.d.ts +15 -0
  103. package/dist/commands/sessions.d.ts.map +1 -1
  104. package/dist/commands/sessions.js +700 -263
  105. package/dist/commands/sessions.js.map +1 -1
  106. package/dist/commands/skills.d.ts +9 -0
  107. package/dist/commands/skills.d.ts.map +1 -1
  108. package/dist/commands/skills.js +355 -233
  109. package/dist/commands/skills.js.map +1 -1
  110. package/dist/commands/status.d.ts +7 -0
  111. package/dist/commands/status.d.ts.map +1 -1
  112. package/dist/commands/status.js +7 -0
  113. package/dist/commands/status.js.map +1 -1
  114. package/dist/commands/subagents.d.ts +8 -0
  115. package/dist/commands/subagents.d.ts.map +1 -1
  116. package/dist/commands/subagents.js +214 -74
  117. package/dist/commands/subagents.js.map +1 -1
  118. package/dist/commands/sync.d.ts +8 -0
  119. package/dist/commands/sync.d.ts.map +1 -1
  120. package/dist/commands/sync.js +15 -7
  121. package/dist/commands/sync.js.map +1 -1
  122. package/dist/commands/teams-picker.d.ts +18 -0
  123. package/dist/commands/teams-picker.d.ts.map +1 -0
  124. package/dist/commands/teams-picker.js +290 -0
  125. package/dist/commands/teams-picker.js.map +1 -0
  126. package/dist/commands/teams.d.ts +18 -0
  127. package/dist/commands/teams.d.ts.map +1 -0
  128. package/dist/commands/teams.js +1098 -0
  129. package/dist/commands/teams.js.map +1 -0
  130. package/dist/commands/utils.d.ts +20 -0
  131. package/dist/commands/utils.d.ts.map +1 -1
  132. package/dist/commands/utils.js +34 -0
  133. package/dist/commands/utils.js.map +1 -1
  134. package/dist/commands/versions.d.ts +8 -0
  135. package/dist/commands/versions.d.ts.map +1 -1
  136. package/dist/commands/versions.js +71 -8
  137. package/dist/commands/versions.js.map +1 -1
  138. package/dist/commands/view.d.ts +36 -1
  139. package/dist/commands/view.d.ts.map +1 -1
  140. package/dist/commands/view.js +375 -15
  141. package/dist/commands/view.js.map +1 -1
  142. package/dist/index.d.ts +6 -0
  143. package/dist/index.d.ts.map +1 -1
  144. package/dist/index.js +136 -51
  145. package/dist/index.js.map +1 -1
  146. package/dist/lib/__tests__/bugfixes.test.js +3 -3
  147. package/dist/lib/__tests__/bugfixes.test.js.map +1 -1
  148. package/dist/lib/__tests__/exec.test.js +125 -19
  149. package/dist/lib/__tests__/exec.test.js.map +1 -1
  150. package/dist/lib/__tests__/hooks.test.d.ts +2 -0
  151. package/dist/lib/__tests__/hooks.test.d.ts.map +1 -0
  152. package/dist/lib/__tests__/hooks.test.js +203 -0
  153. package/dist/lib/__tests__/hooks.test.js.map +1 -0
  154. package/dist/lib/__tests__/memory-compile.test.d.ts +2 -0
  155. package/dist/lib/__tests__/memory-compile.test.d.ts.map +1 -0
  156. package/dist/lib/__tests__/memory-compile.test.js +95 -0
  157. package/dist/lib/__tests__/memory-compile.test.js.map +1 -0
  158. package/dist/lib/__tests__/models.test.d.ts +2 -0
  159. package/dist/lib/__tests__/models.test.d.ts.map +1 -0
  160. package/dist/lib/__tests__/models.test.js +239 -0
  161. package/dist/lib/__tests__/models.test.js.map +1 -0
  162. package/dist/lib/__tests__/rotate.test.d.ts +2 -0
  163. package/dist/lib/__tests__/rotate.test.d.ts.map +1 -0
  164. package/dist/lib/__tests__/rotate.test.js +80 -0
  165. package/dist/lib/__tests__/rotate.test.js.map +1 -0
  166. package/dist/lib/__tests__/secrets-bundles.test.d.ts +2 -0
  167. package/dist/lib/__tests__/secrets-bundles.test.d.ts.map +1 -0
  168. package/dist/lib/__tests__/secrets-bundles.test.js +104 -0
  169. package/dist/lib/__tests__/secrets-bundles.test.js.map +1 -0
  170. package/dist/lib/__tests__/secrets.test.d.ts +2 -0
  171. package/dist/lib/__tests__/secrets.test.d.ts.map +1 -0
  172. package/dist/lib/__tests__/secrets.test.js +90 -0
  173. package/dist/lib/__tests__/secrets.test.js.map +1 -0
  174. package/dist/lib/__tests__/shims.test.d.ts +2 -0
  175. package/dist/lib/__tests__/shims.test.d.ts.map +1 -0
  176. package/dist/lib/__tests__/shims.test.js +39 -0
  177. package/dist/lib/__tests__/shims.test.js.map +1 -0
  178. package/dist/lib/__tests__/usage.test.js +4 -2
  179. package/dist/lib/__tests__/usage.test.js.map +1 -1
  180. package/dist/lib/__tests__/versions.test.d.ts +2 -0
  181. package/dist/lib/__tests__/versions.test.d.ts.map +1 -0
  182. package/dist/lib/__tests__/versions.test.js +63 -0
  183. package/dist/lib/__tests__/versions.test.js.map +1 -0
  184. package/dist/lib/agents.d.ts +53 -1
  185. package/dist/lib/agents.d.ts.map +1 -1
  186. package/dist/lib/agents.js +178 -37
  187. package/dist/lib/agents.js.map +1 -1
  188. package/dist/lib/artifact-actions.d.ts +8 -3
  189. package/dist/lib/artifact-actions.d.ts.map +1 -1
  190. package/dist/lib/artifact-actions.js +8 -5
  191. package/dist/lib/artifact-actions.js.map +1 -1
  192. package/dist/lib/cloud/codex.d.ts +26 -0
  193. package/dist/lib/cloud/codex.d.ts.map +1 -0
  194. package/dist/lib/cloud/codex.js +237 -0
  195. package/dist/lib/cloud/codex.js.map +1 -0
  196. package/dist/lib/cloud/factory.d.ts +32 -0
  197. package/dist/lib/cloud/factory.d.ts.map +1 -0
  198. package/dist/lib/cloud/factory.js +43 -0
  199. package/dist/lib/cloud/factory.js.map +1 -0
  200. package/dist/lib/cloud/registry.d.ts +16 -0
  201. package/dist/lib/cloud/registry.d.ts.map +1 -0
  202. package/dist/lib/cloud/registry.js +68 -0
  203. package/dist/lib/cloud/registry.js.map +1 -0
  204. package/dist/lib/cloud/rush.d.ts +37 -0
  205. package/dist/lib/cloud/rush.d.ts.map +1 -0
  206. package/dist/lib/cloud/rush.js +230 -0
  207. package/dist/lib/cloud/rush.js.map +1 -0
  208. package/dist/lib/cloud/rush.test.d.ts +2 -0
  209. package/dist/lib/cloud/rush.test.d.ts.map +1 -0
  210. package/dist/lib/cloud/rush.test.js +63 -0
  211. package/dist/lib/cloud/rush.test.js.map +1 -0
  212. package/dist/lib/cloud/store.d.ts +23 -0
  213. package/dist/lib/cloud/store.d.ts.map +1 -0
  214. package/dist/lib/cloud/store.js +116 -0
  215. package/dist/lib/cloud/store.js.map +1 -0
  216. package/dist/lib/cloud/stream.d.ts +24 -0
  217. package/dist/lib/cloud/stream.d.ts.map +1 -0
  218. package/dist/lib/cloud/stream.js +145 -0
  219. package/dist/lib/cloud/stream.js.map +1 -0
  220. package/dist/lib/cloud/types.d.ts +109 -0
  221. package/dist/lib/cloud/types.d.ts.map +1 -0
  222. package/dist/lib/cloud/types.js +33 -0
  223. package/dist/lib/cloud/types.js.map +1 -0
  224. package/dist/lib/cloud/types.test.d.ts +2 -0
  225. package/dist/lib/cloud/types.test.d.ts.map +1 -0
  226. package/dist/lib/cloud/types.test.js +41 -0
  227. package/dist/lib/cloud/types.test.js.map +1 -0
  228. package/dist/lib/commands.d.ts +67 -0
  229. package/dist/lib/commands.d.ts.map +1 -1
  230. package/dist/lib/commands.js +161 -2
  231. package/dist/lib/commands.js.map +1 -1
  232. package/dist/lib/convert.d.ts +10 -0
  233. package/dist/lib/convert.d.ts.map +1 -1
  234. package/dist/lib/convert.js +9 -0
  235. package/dist/lib/convert.js.map +1 -1
  236. package/dist/lib/daemon.d.ts +21 -0
  237. package/dist/lib/daemon.d.ts.map +1 -1
  238. package/dist/lib/daemon.js +21 -0
  239. package/dist/lib/daemon.js.map +1 -1
  240. package/dist/lib/drive-sync.d.ts +18 -0
  241. package/dist/lib/drive-sync.d.ts.map +1 -1
  242. package/dist/lib/drive-sync.js +16 -0
  243. package/dist/lib/drive-sync.js.map +1 -1
  244. package/dist/lib/exec.d.ts +64 -3
  245. package/dist/lib/exec.d.ts.map +1 -1
  246. package/dist/lib/exec.js +218 -80
  247. package/dist/lib/exec.js.map +1 -1
  248. package/dist/lib/factory/__tests__/config.test.d.ts +2 -0
  249. package/dist/lib/factory/__tests__/config.test.d.ts.map +1 -0
  250. package/dist/lib/factory/__tests__/config.test.js +128 -0
  251. package/dist/lib/factory/__tests__/config.test.js.map +1 -0
  252. package/dist/lib/factory/config.d.ts +49 -0
  253. package/dist/lib/factory/config.d.ts.map +1 -0
  254. package/dist/lib/factory/config.js +127 -0
  255. package/dist/lib/factory/config.js.map +1 -0
  256. package/dist/lib/factory.js +1 -1
  257. package/dist/lib/factory.js.map +1 -1
  258. package/dist/lib/git.d.ts +16 -1
  259. package/dist/lib/git.d.ts.map +1 -1
  260. package/dist/lib/git.js +33 -4
  261. package/dist/lib/git.js.map +1 -1
  262. package/dist/lib/help.d.ts +7 -0
  263. package/dist/lib/help.d.ts.map +1 -1
  264. package/dist/lib/help.js +3 -0
  265. package/dist/lib/help.js.map +1 -1
  266. package/dist/lib/hooks.d.ts +59 -3
  267. package/dist/lib/hooks.d.ts.map +1 -1
  268. package/dist/lib/hooks.js +413 -33
  269. package/dist/lib/hooks.js.map +1 -1
  270. package/dist/lib/ledger/__tests__/local.test.d.ts +2 -0
  271. package/dist/lib/ledger/__tests__/local.test.d.ts.map +1 -0
  272. package/dist/lib/ledger/__tests__/local.test.js +177 -0
  273. package/dist/lib/ledger/__tests__/local.test.js.map +1 -0
  274. package/dist/lib/ledger/__tests__/sync.test.d.ts +2 -0
  275. package/dist/lib/ledger/__tests__/sync.test.d.ts.map +1 -0
  276. package/dist/lib/ledger/__tests__/sync.test.js +117 -0
  277. package/dist/lib/ledger/__tests__/sync.test.js.map +1 -0
  278. package/dist/lib/ledger/index.d.ts +18 -0
  279. package/dist/lib/ledger/index.d.ts.map +1 -0
  280. package/dist/lib/ledger/index.js +32 -0
  281. package/dist/lib/ledger/index.js.map +1 -0
  282. package/dist/lib/ledger/local.d.ts +22 -0
  283. package/dist/lib/ledger/local.d.ts.map +1 -0
  284. package/dist/lib/ledger/local.js +333 -0
  285. package/dist/lib/ledger/local.js.map +1 -0
  286. package/dist/lib/ledger/r2.d.ts +41 -0
  287. package/dist/lib/ledger/r2.d.ts.map +1 -0
  288. package/dist/lib/ledger/r2.js +335 -0
  289. package/dist/lib/ledger/r2.js.map +1 -0
  290. package/dist/lib/ledger/sync.d.ts +33 -0
  291. package/dist/lib/ledger/sync.d.ts.map +1 -0
  292. package/dist/lib/ledger/sync.js +106 -0
  293. package/dist/lib/ledger/sync.js.map +1 -0
  294. package/dist/lib/ledger/types.d.ts +100 -0
  295. package/dist/lib/ledger/types.d.ts.map +1 -0
  296. package/dist/lib/ledger/types.js +21 -0
  297. package/dist/lib/ledger/types.js.map +1 -0
  298. package/dist/lib/manifest.d.ts +6 -0
  299. package/dist/lib/manifest.d.ts.map +1 -1
  300. package/dist/lib/manifest.js +12 -0
  301. package/dist/lib/manifest.js.map +1 -1
  302. package/dist/lib/markdown.d.ts.map +1 -1
  303. package/dist/lib/markdown.js +6 -0
  304. package/dist/lib/markdown.js.map +1 -1
  305. package/dist/lib/mcp.d.ts +0 -9
  306. package/dist/lib/mcp.d.ts.map +1 -1
  307. package/dist/lib/mcp.js +0 -20
  308. package/dist/lib/mcp.js.map +1 -1
  309. package/dist/lib/memory-compile.d.ts +65 -0
  310. package/dist/lib/memory-compile.d.ts.map +1 -0
  311. package/dist/lib/memory-compile.js +174 -0
  312. package/dist/lib/memory-compile.js.map +1 -0
  313. package/dist/lib/memory.d.ts +8 -0
  314. package/dist/lib/memory.d.ts.map +1 -1
  315. package/dist/lib/memory.js +8 -0
  316. package/dist/lib/memory.js.map +1 -1
  317. package/dist/lib/models.d.ts +98 -0
  318. package/dist/lib/models.d.ts.map +1 -0
  319. package/dist/lib/models.js +728 -0
  320. package/dist/lib/models.js.map +1 -0
  321. package/dist/lib/permissions.d.ts +24 -1
  322. package/dist/lib/permissions.d.ts.map +1 -1
  323. package/dist/lib/permissions.js +52 -3
  324. package/dist/lib/permissions.js.map +1 -1
  325. package/dist/lib/picker.d.ts +27 -0
  326. package/dist/lib/picker.d.ts.map +1 -0
  327. package/dist/lib/picker.js +110 -0
  328. package/dist/lib/picker.js.map +1 -0
  329. package/dist/lib/plugins.d.ts +22 -0
  330. package/dist/lib/plugins.d.ts.map +1 -1
  331. package/dist/lib/plugins.js +114 -0
  332. package/dist/lib/plugins.js.map +1 -1
  333. package/dist/lib/profiles-keychain.d.ts +11 -0
  334. package/dist/lib/profiles-keychain.d.ts.map +1 -0
  335. package/dist/lib/profiles-keychain.js +14 -0
  336. package/dist/lib/profiles-keychain.js.map +1 -0
  337. package/dist/lib/profiles-presets.d.ts +25 -0
  338. package/dist/lib/profiles-presets.d.ts.map +1 -0
  339. package/dist/lib/profiles-presets.js +104 -0
  340. package/dist/lib/profiles-presets.js.map +1 -0
  341. package/dist/lib/profiles.d.ts +70 -0
  342. package/dist/lib/profiles.d.ts.map +1 -0
  343. package/dist/lib/profiles.js +145 -0
  344. package/dist/lib/profiles.js.map +1 -0
  345. package/dist/lib/pty-client.d.ts +1 -0
  346. package/dist/lib/pty-client.d.ts.map +1 -1
  347. package/dist/lib/pty-client.js.map +1 -1
  348. package/dist/lib/pty-server.d.ts +5 -0
  349. package/dist/lib/pty-server.d.ts.map +1 -1
  350. package/dist/lib/pty-server.js +5 -0
  351. package/dist/lib/pty-server.js.map +1 -1
  352. package/dist/lib/registry.d.ts +17 -0
  353. package/dist/lib/registry.d.ts.map +1 -1
  354. package/dist/lib/registry.js +17 -0
  355. package/dist/lib/registry.js.map +1 -1
  356. package/dist/lib/resources.d.ts +5 -0
  357. package/dist/lib/resources.d.ts.map +1 -1
  358. package/dist/lib/resources.js.map +1 -1
  359. package/dist/lib/rotate.d.ts +58 -0
  360. package/dist/lib/rotate.d.ts.map +1 -0
  361. package/dist/lib/rotate.js +93 -0
  362. package/dist/lib/rotate.js.map +1 -0
  363. package/dist/lib/routines.d.ts +30 -1
  364. package/dist/lib/routines.d.ts.map +1 -1
  365. package/dist/lib/routines.js +31 -4
  366. package/dist/lib/routines.js.map +1 -1
  367. package/dist/lib/runner.d.ts +14 -0
  368. package/dist/lib/runner.d.ts.map +1 -1
  369. package/dist/lib/runner.js +45 -11
  370. package/dist/lib/runner.js.map +1 -1
  371. package/dist/lib/sandbox.d.ts +16 -0
  372. package/dist/lib/sandbox.d.ts.map +1 -1
  373. package/dist/lib/sandbox.js +19 -2
  374. package/dist/lib/sandbox.js.map +1 -1
  375. package/dist/lib/scheduler.d.ts +8 -0
  376. package/dist/lib/scheduler.d.ts.map +1 -1
  377. package/dist/lib/scheduler.js +8 -0
  378. package/dist/lib/scheduler.js.map +1 -1
  379. package/dist/lib/secrets-bundles.d.ts +38 -0
  380. package/dist/lib/secrets-bundles.d.ts.map +1 -0
  381. package/dist/lib/secrets-bundles.js +176 -0
  382. package/dist/lib/secrets-bundles.js.map +1 -0
  383. package/dist/lib/secrets.d.ts +53 -0
  384. package/dist/lib/secrets.d.ts.map +1 -0
  385. package/dist/lib/secrets.js +140 -0
  386. package/dist/lib/secrets.js.map +1 -0
  387. package/dist/lib/session/__tests__/db.test.d.ts +2 -0
  388. package/dist/lib/session/__tests__/db.test.d.ts.map +1 -0
  389. package/dist/lib/session/__tests__/db.test.js +54 -0
  390. package/dist/lib/session/__tests__/db.test.js.map +1 -0
  391. package/dist/lib/session/__tests__/discover.test.js +54 -91
  392. package/dist/lib/session/__tests__/discover.test.js.map +1 -1
  393. package/dist/lib/session/__tests__/prompt.test.d.ts +2 -0
  394. package/dist/lib/session/__tests__/prompt.test.d.ts.map +1 -0
  395. package/dist/lib/session/__tests__/prompt.test.js +44 -0
  396. package/dist/lib/session/__tests__/prompt.test.js.map +1 -0
  397. package/dist/lib/session/__tests__/render.test.d.ts +2 -0
  398. package/dist/lib/session/__tests__/render.test.d.ts.map +1 -0
  399. package/dist/lib/session/__tests__/render.test.js +602 -0
  400. package/dist/lib/session/__tests__/render.test.js.map +1 -0
  401. package/dist/lib/session/artifacts.d.ts +15 -0
  402. package/dist/lib/session/artifacts.d.ts.map +1 -0
  403. package/dist/lib/session/artifacts.js +86 -0
  404. package/dist/lib/session/artifacts.js.map +1 -0
  405. package/dist/lib/session/db.d.ts +140 -0
  406. package/dist/lib/session/db.d.ts.map +1 -0
  407. package/dist/lib/session/db.js +599 -0
  408. package/dist/lib/session/db.js.map +1 -0
  409. package/dist/lib/session/discover.d.ts +44 -32
  410. package/dist/lib/session/discover.d.ts.map +1 -1
  411. package/dist/lib/session/discover.js +418 -464
  412. package/dist/lib/session/discover.js.map +1 -1
  413. package/dist/lib/session/parse.d.ts +11 -0
  414. package/dist/lib/session/parse.d.ts.map +1 -1
  415. package/dist/lib/session/parse.js +50 -0
  416. package/dist/lib/session/parse.js.map +1 -1
  417. package/dist/lib/session/prompt.d.ts +10 -0
  418. package/dist/lib/session/prompt.d.ts.map +1 -1
  419. package/dist/lib/session/prompt.js +38 -2
  420. package/dist/lib/session/prompt.js.map +1 -1
  421. package/dist/lib/session/prompt.test.d.ts +2 -0
  422. package/dist/lib/session/prompt.test.d.ts.map +1 -0
  423. package/dist/lib/session/prompt.test.js +57 -0
  424. package/dist/lib/session/prompt.test.js.map +1 -0
  425. package/dist/lib/session/render.d.ts +91 -10
  426. package/dist/lib/session/render.d.ts.map +1 -1
  427. package/dist/lib/session/render.js +708 -180
  428. package/dist/lib/session/render.js.map +1 -1
  429. package/dist/lib/session/team-filter.d.ts +35 -0
  430. package/dist/lib/session/team-filter.d.ts.map +1 -0
  431. package/dist/lib/session/team-filter.js +75 -0
  432. package/dist/lib/session/team-filter.js.map +1 -0
  433. package/dist/lib/session/team-filter.test.d.ts +2 -0
  434. package/dist/lib/session/team-filter.test.d.ts.map +1 -0
  435. package/dist/lib/session/team-filter.test.js +157 -0
  436. package/dist/lib/session/team-filter.test.js.map +1 -0
  437. package/dist/lib/session/types.d.ts +48 -6
  438. package/dist/lib/session/types.d.ts.map +1 -1
  439. package/dist/lib/session/types.js +9 -0
  440. package/dist/lib/session/types.js.map +1 -1
  441. package/dist/lib/shims.d.ts +101 -2
  442. package/dist/lib/shims.d.ts.map +1 -1
  443. package/dist/lib/shims.js +282 -25
  444. package/dist/lib/shims.js.map +1 -1
  445. package/dist/lib/skills.d.ts +68 -0
  446. package/dist/lib/skills.d.ts.map +1 -1
  447. package/dist/lib/skills.js +267 -1
  448. package/dist/lib/skills.js.map +1 -1
  449. package/dist/lib/state.d.ts +41 -2
  450. package/dist/lib/state.d.ts.map +1 -1
  451. package/dist/lib/state.js +63 -4
  452. package/dist/lib/state.js.map +1 -1
  453. package/dist/lib/subagents.d.ts +9 -0
  454. package/dist/lib/subagents.d.ts.map +1 -1
  455. package/dist/lib/subagents.js +9 -1
  456. package/dist/lib/subagents.js.map +1 -1
  457. package/dist/lib/teams/__tests__/oracle.test.d.ts +2 -0
  458. package/dist/lib/teams/__tests__/oracle.test.d.ts.map +1 -0
  459. package/dist/lib/teams/__tests__/oracle.test.js +89 -0
  460. package/dist/lib/teams/__tests__/oracle.test.js.map +1 -0
  461. package/dist/lib/teams/__tests__/supervisor.test.d.ts +2 -0
  462. package/dist/lib/teams/__tests__/supervisor.test.d.ts.map +1 -0
  463. package/dist/lib/teams/__tests__/supervisor.test.js +179 -0
  464. package/dist/lib/teams/__tests__/supervisor.test.js.map +1 -0
  465. package/dist/lib/teams/agents.d.ts +247 -0
  466. package/dist/lib/teams/agents.d.ts.map +1 -0
  467. package/dist/lib/teams/agents.js +1244 -0
  468. package/dist/lib/teams/agents.js.map +1 -0
  469. package/dist/lib/teams/api.d.ts +91 -0
  470. package/dist/lib/teams/api.d.ts.map +1 -0
  471. package/dist/lib/teams/api.js +239 -0
  472. package/dist/lib/teams/api.js.map +1 -0
  473. package/dist/lib/teams/cloud.d.ts +11 -0
  474. package/dist/lib/teams/cloud.d.ts.map +1 -0
  475. package/dist/lib/teams/cloud.js +169 -0
  476. package/dist/lib/teams/cloud.js.map +1 -0
  477. package/dist/lib/teams/debug.d.ts +8 -0
  478. package/dist/lib/teams/debug.d.ts.map +1 -0
  479. package/dist/lib/teams/debug.js +12 -0
  480. package/dist/lib/teams/debug.js.map +1 -0
  481. package/dist/lib/teams/file_ops.d.ts +13 -0
  482. package/dist/lib/teams/file_ops.d.ts.map +1 -0
  483. package/dist/lib/teams/file_ops.js +66 -0
  484. package/dist/lib/teams/file_ops.js.map +1 -0
  485. package/dist/lib/teams/index.d.ts +16 -0
  486. package/dist/lib/teams/index.d.ts.map +1 -0
  487. package/dist/lib/teams/index.js +15 -0
  488. package/dist/lib/teams/index.js.map +1 -0
  489. package/dist/lib/teams/oracle.d.ts +20 -0
  490. package/dist/lib/teams/oracle.d.ts.map +1 -0
  491. package/dist/lib/teams/oracle.js +59 -0
  492. package/dist/lib/teams/oracle.js.map +1 -0
  493. package/dist/lib/teams/parsers.d.ts +9 -0
  494. package/dist/lib/teams/parsers.d.ts.map +1 -0
  495. package/dist/lib/teams/parsers.js +837 -0
  496. package/dist/lib/teams/parsers.js.map +1 -0
  497. package/dist/lib/teams/persistence.d.ts +43 -0
  498. package/dist/lib/teams/persistence.d.ts.map +1 -0
  499. package/dist/lib/teams/persistence.js +299 -0
  500. package/dist/lib/teams/persistence.js.map +1 -0
  501. package/dist/lib/teams/ralph.d.ts +8 -0
  502. package/dist/lib/teams/ralph.d.ts.map +1 -0
  503. package/dist/lib/teams/ralph.js +59 -0
  504. package/dist/lib/teams/ralph.js.map +1 -0
  505. package/dist/lib/teams/registry.d.ts +18 -0
  506. package/dist/lib/teams/registry.d.ts.map +1 -0
  507. package/dist/lib/teams/registry.js +68 -0
  508. package/dist/lib/teams/registry.js.map +1 -0
  509. package/dist/lib/teams/summarizer.d.ts +73 -0
  510. package/dist/lib/teams/summarizer.d.ts.map +1 -0
  511. package/dist/lib/teams/summarizer.js +780 -0
  512. package/dist/lib/teams/summarizer.js.map +1 -0
  513. package/dist/lib/teams/supervisor.d.ts +49 -0
  514. package/dist/lib/teams/supervisor.d.ts.map +1 -0
  515. package/dist/lib/teams/supervisor.js +74 -0
  516. package/dist/lib/teams/supervisor.js.map +1 -0
  517. package/dist/lib/template.d.ts +8 -5
  518. package/dist/lib/template.d.ts.map +1 -1
  519. package/dist/lib/template.js +8 -5
  520. package/dist/lib/template.js.map +1 -1
  521. package/dist/lib/types.d.ts +58 -1
  522. package/dist/lib/types.d.ts.map +1 -1
  523. package/dist/lib/types.js +16 -1
  524. package/dist/lib/types.js.map +1 -1
  525. package/dist/lib/usage.d.ts +48 -0
  526. package/dist/lib/usage.d.ts.map +1 -1
  527. package/dist/lib/usage.js +106 -14
  528. package/dist/lib/usage.js.map +1 -1
  529. package/dist/lib/versions.d.ts +12 -1
  530. package/dist/lib/versions.d.ts.map +1 -1
  531. package/dist/lib/versions.js +124 -41
  532. package/dist/lib/versions.js.map +1 -1
  533. package/package.json +20 -6
  534. package/scripts/postinstall.js +1 -1
  535. package/scripts/rebuild-sqlite.sh +46 -0
  536. package/dist/commands/sessions.test.d.ts +0 -2
  537. package/dist/commands/sessions.test.d.ts.map +0 -1
  538. package/dist/commands/sessions.test.js +0 -53
  539. package/dist/commands/sessions.test.js.map +0 -1
@@ -0,0 +1,1098 @@
1
+ import chalk from 'chalk';
2
+ import * as fs from 'fs/promises';
3
+ import * as path from 'path';
4
+ import { AgentManager, checkAllClis, getAgentsDir, VALID_TASK_TYPES, } from '../lib/teams/agents.js';
5
+ import { resolveProvider } from '../lib/cloud/registry.js';
6
+ import { resolveLedger, syncTeammate } from '../lib/ledger/index.js';
7
+ import { maybeFileBugfix } from '../lib/teams/oracle.js';
8
+ import { runSupervisor } from '../lib/teams/supervisor.js';
9
+ import { handleSpawn, handleStatus, handleStop, handleTasks, } from '../lib/teams/api.js';
10
+ import { createTeam, ensureTeam, loadTeams, removeTeam, teamExists, } from '../lib/teams/registry.js';
11
+ import { isVersionInstalled } from '../lib/versions.js';
12
+ import { discoverSessions, parseTimeFilter, resolveSessionById } from '../lib/session/discover.js';
13
+ import { buildPreview as buildSessionPreview } from './sessions-picker.js';
14
+ import { parseExecEnv } from '../lib/exec.js';
15
+ import { teamPicker, printTeamTable } from './teams-picker.js';
16
+ import { itemPicker } from '../lib/picker.js';
17
+ import { isPromptCancelled, isInteractiveTerminal, requireDestructiveArg, requireInteractiveSelection, } from './utils.js';
18
+ const AGENT_NAMES = {
19
+ claude: 'Claude',
20
+ codex: 'Codex',
21
+ gemini: 'Gemini',
22
+ cursor: 'Cursor',
23
+ opencode: 'OpenCode',
24
+ };
25
+ const VALID_AGENTS = Object.keys(AGENT_NAMES);
26
+ const VALID_MODES = ['plan', 'edit', 'full'];
27
+ const VALID_EFFORTS = ['low', 'medium', 'high', 'xhigh', 'max', 'auto'];
28
+ const VALID_CLOUD_PROVIDERS = ['rush', 'codex', 'factory'];
29
+ // Auto-enable JSON mode when piped / not a TTY so AI agent consumers get
30
+ // parseable output by default.
31
+ function isJsonMode(opts) {
32
+ return Boolean(opts.json) || !process.stdout.isTTY;
33
+ }
34
+ function die(msg, code = 1) {
35
+ console.error(chalk.red(msg));
36
+ process.exit(code);
37
+ }
38
+ function statusColor(status) {
39
+ switch (status) {
40
+ case 'pending': return chalk.blue;
41
+ case 'running': return chalk.yellow;
42
+ case 'completed': return chalk.green;
43
+ case 'failed': return chalk.red;
44
+ case 'stopped': return chalk.gray;
45
+ default: return chalk.white;
46
+ }
47
+ }
48
+ function relTime(iso) {
49
+ const secs = Math.floor((Date.now() - new Date(iso).getTime()) / 1000);
50
+ if (secs < 10)
51
+ return 'just now';
52
+ if (secs < 60)
53
+ return `${secs}s ago`;
54
+ if (secs < 3600)
55
+ return `${Math.floor(secs / 60)}m ago`;
56
+ if (secs < 86400)
57
+ return `${Math.floor(secs / 3600)}h ago`;
58
+ return `${Math.floor(secs / 86400)}d ago`;
59
+ }
60
+ function truncate(s, n) {
61
+ if (s.length <= n)
62
+ return s;
63
+ return s.slice(0, n - 1) + '…';
64
+ }
65
+ function fullName(type, version) {
66
+ const name = AGENT_NAMES[type];
67
+ return version ? `${name} ${version}` : name;
68
+ }
69
+ function parseTeammate(spec) {
70
+ const [name, version] = spec.split('@');
71
+ if (!VALID_AGENTS.includes(name)) {
72
+ die(`Unknown teammate '${name}'. Available: ${VALID_AGENTS.join(', ')}.\n` +
73
+ ` Use the form 'claude' or 'claude@2.1.112' (see 'agents view' for installed versions).`);
74
+ }
75
+ return { agent: name, version: version || null };
76
+ }
77
+ function shortId(id) {
78
+ return id.slice(0, 8);
79
+ }
80
+ /**
81
+ * Preamble injected into every factory worker's prompt. Tells the worker:
82
+ * - which team + teammate name + task-type it is
83
+ * - the 4 Ledger MCP tools it has access to
84
+ * - how to file more tasks via `agents teams add`
85
+ *
86
+ * The actual how-to lives in the /factory-worker skill; this preamble just
87
+ * summarises and points at it so workers get the dynamic-DAG pattern even
88
+ * when the spawning agent forgets to mention it.
89
+ */
90
+ function factoryWorkerPreamble(team, name, taskType, after) {
91
+ const n = name ?? '<anonymous>';
92
+ const deps = after.length > 0 ? after.join(', ') : '(none)';
93
+ return [
94
+ `FACTORY WORKER — team="${team}", name="${n}", task_type="${taskType}", after=${deps}`,
95
+ `You are a teammate in a Software Factory. Read the /factory-worker skill for the full pattern.`,
96
+ `Key rules:`,
97
+ ` - Other teammates may be running now. Coordinate via git, tests, and the Team Ledger (never peer-to-peer).`,
98
+ ` - Read dependency outputs via MCP: LedgerRead(team_id="${team}", task_id=<dep-agent-id>).`,
99
+ ` - If you discover work beyond your task, file a new teammate via Bash:`,
100
+ ` agents teams add "${team}" claude "<ask>" --name <slug> --task-type <implement|test|review|bugfix|docs> [--after <dep>]`,
101
+ ` A background supervisor picks up new tasks every wave.`,
102
+ ` - Before exiting, call LedgerNote(team_id="${team}", task_id=<your-agent-id>, teammate="${n}", text="...") with what you tried, what failed, what worked.`,
103
+ ` - test-type teammates: print "TESTS: N passed, M failed" as your last line. Failed tests auto-file a bugfix.`,
104
+ ``,
105
+ `YOUR TASK:`,
106
+ ].join('\n');
107
+ }
108
+ /**
109
+ * Build an AgentManager with the Ledger sync hook pre-wired. Every `teams`
110
+ * command call path that touches status goes through this so completions
111
+ * automatically land in the Ledger.
112
+ */
113
+ function mkManager() {
114
+ const mgr = new AgentManager();
115
+ const ledger = resolveLedger();
116
+ mgr.setCompletionHook(async (agent) => {
117
+ // 1. Push teammate outputs to the Ledger so other teammates can read
118
+ // them via MCP tools.
119
+ const snap = await agent.toSnapshot();
120
+ await syncTeammate(snap, ledger);
121
+ // 2. Run the test-oracle: failed test-type teammates auto-file a
122
+ // bugfix teammate.
123
+ await maybeFileBugfix(agent, mgr);
124
+ });
125
+ return mgr;
126
+ }
127
+ /**
128
+ * Register the generic cloud dispatcher — staged cloud teammates get
129
+ * dispatched when their --after deps resolve, using repo/branch stored on
130
+ * the teammate itself so we don't need the original --cloud CLI args.
131
+ */
132
+ export function wireCloudDispatcher(mgr) {
133
+ mgr.setCloudDispatcher(async (a) => {
134
+ if (!a.cloudProvider) {
135
+ throw new Error(`Teammate ${a.agentId} has no cloud provider set`);
136
+ }
137
+ const prov = resolveProvider(a.cloudProvider);
138
+ const dispatchOpts = {
139
+ prompt: a.prompt,
140
+ agent: a.agentType,
141
+ repo: a.cloudRepo ?? undefined,
142
+ branch: a.cloudBranch ?? undefined,
143
+ model: a.model ?? undefined,
144
+ };
145
+ const cloudTask = await prov.dispatch(dispatchOpts);
146
+ return { cloudSessionId: cloudTask.id };
147
+ });
148
+ }
149
+ /** Single-wave start used by `teams start` without --watch. */
150
+ async function runOneWave(mgr, team, json) {
151
+ const launched = await mgr.startReady(team);
152
+ const all = await mgr.listByTask(team);
153
+ const stillPending = all.filter((a) => a.status === 'pending');
154
+ if (json) {
155
+ console.log(JSON.stringify({
156
+ team,
157
+ launched: launched.map((a) => ({ agent_id: a.agentId, name: a.name, after: a.after })),
158
+ still_pending: stillPending.map((a) => ({ agent_id: a.agentId, name: a.name, after: a.after })),
159
+ }, null, 2));
160
+ return;
161
+ }
162
+ if (launched.length === 0 && stillPending.length === 0) {
163
+ console.log(chalk.gray(`No pending teammates in team ${team}.`));
164
+ return;
165
+ }
166
+ if (launched.length > 0) {
167
+ console.log(chalk.green(`Launched ${launched.length} teammate(s) in team ${chalk.cyan(team)}:`));
168
+ for (const a of launched) {
169
+ const who = fullName(a.agentType, a.version);
170
+ const h = a.name || shortId(a.agentId);
171
+ console.log(` ${chalk.cyan(h)} ${who}`);
172
+ }
173
+ }
174
+ if (stillPending.length > 0) {
175
+ console.log();
176
+ console.log(chalk.gray(`Still pending (${stillPending.length}):`));
177
+ for (const a of stillPending) {
178
+ const h = a.name || shortId(a.agentId);
179
+ console.log(` ${chalk.blue(h)} ${chalk.gray('after')} ${a.after.join(', ')}`);
180
+ }
181
+ }
182
+ }
183
+ // Pick the display handle for a teammate: their given name if they have one,
184
+ // otherwise the 8-char UUID prefix.
185
+ function handle(a) {
186
+ return a.name || shortId(a.agent_id);
187
+ }
188
+ // Resolve a teammate reference (name / UUID / UUID prefix) by scanning every
189
+ // meta.json under the agents dir. Team hint narrows the search.
190
+ async function resolveTeammateAcrossTeams(base, ref, teamHint) {
191
+ let entries = [];
192
+ try {
193
+ entries = await fs.readdir(base);
194
+ }
195
+ catch {
196
+ return { kind: 'none' };
197
+ }
198
+ // Cheap path: exact UUID or unique UUID prefix match by directory name.
199
+ const byDir = entries.filter((e) => e === ref || e.startsWith(ref));
200
+ if (byDir.length === 1 && byDir[0] === ref) {
201
+ return { kind: 'ok', agentId: ref };
202
+ }
203
+ // Otherwise scan meta.json files to match on name as well, and respect the
204
+ // team hint if given.
205
+ const candidates = [];
206
+ for (const dir of entries) {
207
+ try {
208
+ const meta = JSON.parse(await fs.readFile(path.join(base, dir, 'meta.json'), 'utf-8'));
209
+ if (teamHint && meta.task_name !== teamHint)
210
+ continue;
211
+ const matchesName = meta.name && meta.name === ref;
212
+ const matchesPrefix = dir.startsWith(ref);
213
+ if (matchesName || matchesPrefix) {
214
+ candidates.push({
215
+ team: meta.task_name || '(none)',
216
+ agentId: dir,
217
+ display: meta.name || shortId(dir),
218
+ name: meta.name || null,
219
+ });
220
+ }
221
+ }
222
+ catch {
223
+ /* skip entries without readable meta.json */
224
+ }
225
+ }
226
+ if (candidates.length === 0)
227
+ return { kind: 'none' };
228
+ if (candidates.length === 1)
229
+ return { kind: 'ok', agentId: candidates[0].agentId };
230
+ // If multiple match but one is an exact name hit, prefer it.
231
+ const exactName = candidates.filter((c) => c.name === ref);
232
+ if (exactName.length === 1)
233
+ return { kind: 'ok', agentId: exactName[0].agentId };
234
+ return { kind: 'ambiguous', candidates };
235
+ }
236
+ // Print a teammate block using the same session preview the sessions picker
237
+ // uses — one canonical renderer across `agents sessions`, teams picker
238
+ // preview, and teams status output.
239
+ //
240
+ // Layout:
241
+ // alice claude COMPLETED · 5.0 minutes
242
+ // after: bob
243
+ // <buildSessionPreview output> (when the session file was found)
244
+ // ! reported an error (if flagged)
245
+ // PR: <url> (if set)
246
+ function printAgentDetail(a, session) {
247
+ const label = statusColor(a.status)(a.status.toUpperCase());
248
+ const who = fullName(a.agent_type, a.version);
249
+ const h = handle(a);
250
+ const secondary = a.name ? chalk.gray(`(${shortId(a.agent_id)})`) : '';
251
+ const duration = a.duration ? `${chalk.gray(' · ')}${chalk.white(a.duration)}` : '';
252
+ console.log(` ${chalk.cyan(h.padEnd(10))} ${secondary.padEnd(11)} ${who.padEnd(18)} ${label}${duration}`);
253
+ if (a.after && a.after.length) {
254
+ console.log(` ${chalk.gray('after ')} ${a.after.join(', ')}`);
255
+ }
256
+ // If the agent's internal session id differs from ours (non-Claude), show
257
+ // it as a hint for `agents sessions <id>`.
258
+ if (a.remote_session_id && a.remote_session_id !== a.agent_id) {
259
+ console.log(` ${chalk.gray('session ')} ${chalk.gray(a.remote_session_id)}`);
260
+ }
261
+ if (session) {
262
+ // Hand off to the same renderer the sessions picker uses. Indent so the
263
+ // block visually belongs to this teammate.
264
+ const preview = buildSessionPreview(session);
265
+ for (const line of preview.split('\n')) {
266
+ console.log(line ? ` ${line}` : '');
267
+ }
268
+ }
269
+ else {
270
+ // Session file not yet on disk (e.g. teammate is pending, or their
271
+ // agent type writes sessions elsewhere). Fall back to a compact summary
272
+ // derived from the live status payload.
273
+ const activity = [];
274
+ if (a.files_modified.length)
275
+ activity.push(`${a.files_modified.length} modified`);
276
+ if (a.files_created.length)
277
+ activity.push(`${a.files_created.length} created`);
278
+ if (a.files_read.length)
279
+ activity.push(`${a.files_read.length} read`);
280
+ if (a.tool_count)
281
+ activity.push(`${a.tool_count} tools`);
282
+ if (activity.length) {
283
+ console.log(` ${chalk.gray(activity.join(' · '))}`);
284
+ }
285
+ const lastMsg = a.last_messages[a.last_messages.length - 1];
286
+ if (lastMsg) {
287
+ const firstLine = lastMsg.split(/\r?\n/).find((l) => l.trim()) || '';
288
+ if (firstLine)
289
+ console.log(` ${chalk.gray('> ' + truncate(firstLine, 96))}`);
290
+ }
291
+ }
292
+ if (a.has_errors)
293
+ console.log(` ${chalk.red('! reported an error')}`);
294
+ if (a.pr_url)
295
+ console.log(` ${chalk.gray('PR ')}${a.pr_url}`);
296
+ }
297
+ // Resolve each live teammate to its on-disk session (Claude/Codex/Gemini/
298
+ // OpenCode all write parseable session files). `agent_id === remote_session_id`
299
+ // for Claude teammates; non-Claude agents may carry their own session UUID on
300
+ // `remote_session_id`. We try both.
301
+ async function resolveTeammateSessions(agents) {
302
+ const map = new Map();
303
+ if (agents.length === 0)
304
+ return map;
305
+ // Scan every project dir — team teammates may have run from anywhere.
306
+ const all = await discoverSessions({ all: true, limit: 5000 });
307
+ for (const a of agents) {
308
+ const candidates = [a.remote_session_id, a.agent_id].filter(Boolean);
309
+ let found = null;
310
+ for (const id of candidates) {
311
+ const hits = resolveSessionById(all, id);
312
+ if (hits.length) {
313
+ found = hits[0];
314
+ break;
315
+ }
316
+ }
317
+ map.set(a.agent_id, found);
318
+ }
319
+ return map;
320
+ }
321
+ // Render a team's status in the same format the `status` subcommand uses, so
322
+ // the interactive picker's Enter action drops the user into a familiar view.
323
+ async function printTeamStatus(team, result) {
324
+ const { summary, agents } = result;
325
+ console.log(chalk.bold(`Team ${chalk.cyan(team)} `) +
326
+ chalk.gray(summary.pending > 0
327
+ ? `(${summary.pending} pending, ${summary.running} working, ${summary.completed} done, ${summary.failed} failed, ${summary.stopped} stopped)`
328
+ : `(${summary.running} working, ${summary.completed} done, ${summary.failed} failed, ${summary.stopped} stopped)`));
329
+ if (agents.length === 0) {
330
+ console.log(chalk.gray(' (no teammates yet — add one with `agents teams add`)'));
331
+ }
332
+ else {
333
+ const sessions = await resolveTeammateSessions(agents);
334
+ const width = Math.min(process.stdout.columns || 80, 80);
335
+ const divider = chalk.gray('┈'.repeat(width));
336
+ for (let i = 0; i < agents.length; i++) {
337
+ console.log();
338
+ if (i > 0) {
339
+ console.log(divider);
340
+ console.log();
341
+ }
342
+ printAgentDetail(agents[i], sessions.get(agents[i].agent_id) ?? null);
343
+ }
344
+ }
345
+ console.log();
346
+ console.log(chalk.gray(`cursor: ${result.cursor}`));
347
+ }
348
+ // Classify a team into a single bucket for --status filtering.
349
+ // - empty: no teammates (created but nobody added yet)
350
+ // - waiting: only staged teammates — call `teams start` to kick them off
351
+ // - working: at least one teammate still running
352
+ // - failed: at least one teammate failed or was stopped (any failure wins —
353
+ // even if others finished, you want to know about the failure)
354
+ // - done: everyone finished successfully, no failures
355
+ function classifyTeamStatus(t) {
356
+ if (t.agent_count === 0)
357
+ return 'empty';
358
+ if (t.running > 0)
359
+ return 'working';
360
+ if (t.failed + t.stopped > 0)
361
+ return 'failed';
362
+ // At this point nobody is running/failed/stopped. If there's any pending
363
+ // teammate (agent_count > running+completed+failed+stopped), it's "waiting".
364
+ const accounted = t.running + t.completed + t.failed + t.stopped;
365
+ if (accounted < t.agent_count)
366
+ return 'waiting';
367
+ return 'done';
368
+ }
369
+ // Merge persistent team registry with tasks derived from live agents so empty
370
+ // teams (created but no teammates yet) still show up.
371
+ function mergeTeams(registry, tasks) {
372
+ const byName = new Map();
373
+ for (const t of tasks)
374
+ byName.set(t.task_name, t);
375
+ for (const [name, meta] of Object.entries(registry)) {
376
+ if (!byName.has(name)) {
377
+ byName.set(name, {
378
+ task_name: name,
379
+ agent_count: 0,
380
+ pending: 0,
381
+ running: 0,
382
+ completed: 0,
383
+ failed: 0,
384
+ stopped: 0,
385
+ workspace_dir: null,
386
+ created_at: meta.created_at,
387
+ modified_at: meta.created_at,
388
+ });
389
+ }
390
+ }
391
+ return Array.from(byName.values()).sort((a, b) => new Date(b.modified_at).getTime() - new Date(a.modified_at).getTime());
392
+ }
393
+ // Build the same enriched rows the `list` picker uses. Shared between `list`
394
+ // (interactive default) and the picker fallback for `status` / `start`.
395
+ async function loadTeamRows(mgr) {
396
+ const [tasks, registry] = await Promise.all([handleTasks(mgr, 1000), loadTeams()]);
397
+ const merged = mergeTeams(registry, tasks.tasks);
398
+ const rows = await Promise.all(merged.map(async (team) => {
399
+ let agents = [];
400
+ try {
401
+ const res = await handleStatus(mgr, team.task_name, 'all');
402
+ agents = res.agents;
403
+ }
404
+ catch {
405
+ // Empty teams (no live agents) throw in some code paths.
406
+ }
407
+ return { team, agents, description: registry[team.task_name]?.description };
408
+ }));
409
+ return { rows, names: merged.map((t) => t.task_name) };
410
+ }
411
+ // Picker fallback for `teams logs` when the teammate ref is omitted. Shows a
412
+ // flat list of every teammate with their team context; Enter picks one.
413
+ async function pickTeammateOr(mgr, command) {
414
+ if (!isInteractiveTerminal()) {
415
+ requireInteractiveSelection(`Picking a teammate for \`${command}\``, [
416
+ `${command} <teammate>`,
417
+ `agents teams list # to see teammates per team`,
418
+ ]);
419
+ }
420
+ const all = await mgr.listAll();
421
+ if (all.length === 0) {
422
+ console.log(chalk.gray('No teammates on any team yet.'));
423
+ console.log(chalk.gray(' Add one with: agents teams add <team> <agent> <task>'));
424
+ return null;
425
+ }
426
+ const nameW = Math.max(8, ...all.map((a) => (a.name || shortId(a.agentId)).length));
427
+ const teamW = Math.max(6, ...all.map((a) => a.taskName.length));
428
+ try {
429
+ const picked = await itemPicker({
430
+ message: 'Select a teammate:',
431
+ items: all,
432
+ filter: (query) => {
433
+ const q = query.trim().toLowerCase();
434
+ if (!q)
435
+ return all;
436
+ return all.filter((a) => {
437
+ const hay = [a.name ?? '', a.agentId, a.taskName, a.agentType, a.status].join(' ').toLowerCase();
438
+ return hay.includes(q);
439
+ });
440
+ },
441
+ labelFor: (a) => {
442
+ const h = (a.name || shortId(a.agentId)).padEnd(nameW);
443
+ const team = a.taskName.padEnd(teamW);
444
+ const who = fullName(a.agentType, a.version);
445
+ return `${chalk.cyan(h)} ${chalk.gray(team)} ${who} ${statusColor(a.status)(a.status)}`;
446
+ },
447
+ shortIdFor: (a) => a.name || shortId(a.agentId),
448
+ pageSize: 10,
449
+ emptyMessage: 'No teammates match.',
450
+ enterHint: 'view log',
451
+ });
452
+ if (!picked)
453
+ return null;
454
+ return { agentId: picked.item.agentId, team: picked.item.taskName };
455
+ }
456
+ catch (err) {
457
+ if (isPromptCancelled(err))
458
+ return null;
459
+ throw err;
460
+ }
461
+ }
462
+ // Fallback for read-only / constructive subcommands when the user omits the
463
+ // team argument. In a TTY, show the picker and return the chosen team. Outside
464
+ // a TTY, hard-fail with a clear error so scripts surface the missing arg.
465
+ async function pickTeamOr(mgr, command) {
466
+ if (!isInteractiveTerminal()) {
467
+ requireInteractiveSelection(`Picking a team for \`${command}\``, [
468
+ `${command} <team>`,
469
+ `agents teams list # to see your teams`,
470
+ ]);
471
+ }
472
+ const { rows } = await loadTeamRows(mgr);
473
+ if (rows.length === 0) {
474
+ console.log(chalk.gray("You haven't started any teams yet."));
475
+ console.log(chalk.gray(' Start one with: agents teams create <name>'));
476
+ return null;
477
+ }
478
+ try {
479
+ const picked = await teamPicker(rows);
480
+ return picked?.team ?? null;
481
+ }
482
+ catch (err) {
483
+ if (isPromptCancelled(err))
484
+ return null;
485
+ throw err;
486
+ }
487
+ }
488
+ /** Register the `agents teams` command tree (list, create, add, status, start, remove, disband, logs, doctor). */
489
+ export function registerTeamsCommands(program) {
490
+ const teams = program
491
+ .command('teams')
492
+ .description('Organize AI coding agents into teams that collaborate on a shared task')
493
+ .addHelpText('after', `
494
+ A team is a named group of agents working together on a shared task. Each teammate
495
+ runs in the background; you use 'status' to check in on progress. Use --after to
496
+ create DAG-style dependencies (one teammate waits for another to finish first).
497
+
498
+ Teammate sessions appear in 'agents sessions --teams' with a [team/name · mode] tag.
499
+
500
+ Examples:
501
+ # Start a new team for a feature
502
+ agents teams create auth-feature
503
+
504
+ # Add Alice (Claude) to work on the backend
505
+ agents teams add auth-feature claude "Add JWT auth middleware" --name alice
506
+
507
+ # Add Bob (Codex 0.116.0) to write tests, but wait for Alice to finish first
508
+ agents teams add auth-feature codex@0.116.0 "Write integration tests" --name bob --after alice
509
+
510
+ # Kick off any staged teammates whose dependencies are satisfied
511
+ agents teams start auth-feature
512
+
513
+ # Check in on progress (delta polling with --since for efficiency)
514
+ agents teams status auth-feature
515
+ agents teams status auth-feature --since 2026-04-19T10:30:00Z
516
+
517
+ # Let Alice go when she's done
518
+ agents teams remove auth-feature alice
519
+
520
+ # Wind down the whole team when work is complete
521
+ agents teams disband auth-feature
522
+
523
+ Short aliases:
524
+ teams c = create teams a = add teams s = status
525
+ teams rm = remove teams d = disband teams ls = list
526
+
527
+ Teammate syntax (same as the rest of agents-cli):
528
+ 'claude' -> the default Claude version on this machine
529
+ 'claude@2.1.112' -> a specific installed version (see 'agents view')
530
+
531
+ Name teammates with --name alice to refer to them as 'alice' instead of a UUID.
532
+ `);
533
+ // list
534
+ teams
535
+ .command('list [query]')
536
+ .alias('ls')
537
+ .description('List your teams, most recent activity first')
538
+ .option('-a, --agent <agent>', 'Filter: only teams with this agent (e.g. claude or claude@2.1.112)')
539
+ .option('--status <status>', 'Filter: only teams with this status (working, done, failed, or empty)')
540
+ .option('--since <time>', 'Filter: teams active after this time (e.g. "2h", "7d", or ISO date)')
541
+ .option('--until <time>', 'Filter: teams active before this time (e.g. "30d", or ISO date)')
542
+ .option('-n, --limit <n>', 'Show at most this many teams (default: 20)', '20')
543
+ .option('--json', 'Output machine-readable JSON instead of formatted table')
544
+ .action(async (query, opts) => {
545
+ const mgr = mkManager();
546
+ const limit = Math.max(1, parseInt(opts.limit, 10) || 20);
547
+ const [tasks, registry, everyAgent] = await Promise.all([
548
+ handleTasks(mgr, 1000),
549
+ loadTeams(),
550
+ mgr.listAll(),
551
+ ]);
552
+ // Group agents by team so we can filter on agent-type / version.
553
+ const byTeam = new Map();
554
+ for (const a of everyAgent) {
555
+ const arr = byTeam.get(a.taskName) || [];
556
+ arr.push({ agent_type: a.agentType, version: a.version });
557
+ byTeam.set(a.taskName, arr);
558
+ }
559
+ let merged = mergeTeams(registry, tasks.tasks);
560
+ // --- query: substring match on team name ---
561
+ if (query) {
562
+ const q = query.toLowerCase();
563
+ merged = merged.filter((t) => t.task_name.toLowerCase().includes(q));
564
+ }
565
+ // --- --agent: filter teams containing a matching teammate ---
566
+ if (opts.agent) {
567
+ const [wantType, wantVersion] = opts.agent.split('@');
568
+ merged = merged.filter((t) => {
569
+ const teammates = byTeam.get(t.task_name) || [];
570
+ return teammates.some((m) => m.agent_type === wantType && (!wantVersion || m.version === wantVersion));
571
+ });
572
+ }
573
+ // --- --status: classify each team, filter ---
574
+ if (opts.status) {
575
+ const want = opts.status.toLowerCase();
576
+ const validStatuses = ['working', 'done', 'failed', 'empty'];
577
+ if (!validStatuses.includes(want)) {
578
+ die(`Invalid --status '${opts.status}'. Use one of: ${validStatuses.join(', ')}`);
579
+ }
580
+ merged = merged.filter((t) => classifyTeamStatus(t) === want);
581
+ }
582
+ // --- --since / --until: filter by activity window ---
583
+ if (opts.since) {
584
+ const cutoff = parseTimeFilter(opts.since);
585
+ if (!cutoff)
586
+ die(`Could not parse --since '${opts.since}'`);
587
+ merged = merged.filter((t) => new Date(t.modified_at).getTime() >= cutoff);
588
+ }
589
+ if (opts.until) {
590
+ const cutoff = parseTimeFilter(opts.until);
591
+ if (!cutoff)
592
+ die(`Could not parse --until '${opts.until}'`);
593
+ merged = merged.filter((t) => new Date(t.modified_at).getTime() <= cutoff);
594
+ }
595
+ merged = merged.slice(0, limit);
596
+ if (isJsonMode(opts)) {
597
+ console.log(JSON.stringify({ teams: merged }, null, 2));
598
+ return;
599
+ }
600
+ if (merged.length === 0) {
601
+ if (query || opts.agent || opts.status || opts.since || opts.until) {
602
+ console.log(chalk.gray('No teams match those filters.'));
603
+ }
604
+ else {
605
+ console.log(chalk.gray("You haven't started any teams yet."));
606
+ console.log(chalk.gray(' Start one with: agents teams create <name>'));
607
+ }
608
+ return;
609
+ }
610
+ // Enrich teams with teammate details for the picker's preview pane.
611
+ const rows = await Promise.all(merged.map(async (team) => {
612
+ let agents = [];
613
+ try {
614
+ const res = await handleStatus(mgr, team.task_name, 'all');
615
+ agents = res.agents;
616
+ }
617
+ catch {
618
+ // Empty teams (no live agents) throw in some code paths — preview
619
+ // will just show "no teammates yet".
620
+ }
621
+ return { team, agents, description: registry[team.task_name]?.description };
622
+ }));
623
+ if (isInteractiveTerminal()) {
624
+ try {
625
+ const picked = await teamPicker(rows, query);
626
+ if (picked) {
627
+ // Fall through to the status subcommand's action for the picked team.
628
+ const result = await handleStatus(mgr, picked.team, 'all');
629
+ await printTeamStatus(picked.team, result);
630
+ }
631
+ }
632
+ catch (err) {
633
+ if (!isPromptCancelled(err))
634
+ throw err;
635
+ }
636
+ return;
637
+ }
638
+ // Non-interactive fallback: rows flow without a header, matching the
639
+ // shape of `agents sessions` when piped.
640
+ printTeamTable(rows);
641
+ });
642
+ // create
643
+ teams
644
+ .command('create <team>')
645
+ .aliases(['c', 'new'])
646
+ .description('Start a new team. No teammates yet; add them with `teams add`.')
647
+ .option('-d, --description <text>', 'One-line summary of what this team is working on')
648
+ .option('--json', 'Output machine-readable JSON')
649
+ .action(async (team, opts) => {
650
+ try {
651
+ const meta = await createTeam(team, opts.description);
652
+ if (isJsonMode(opts)) {
653
+ console.log(JSON.stringify({ team, ...meta }, null, 2));
654
+ return;
655
+ }
656
+ console.log(chalk.green(`New team: ${chalk.cyan(team)}`));
657
+ if (meta.description)
658
+ console.log(chalk.gray(` ${meta.description}`));
659
+ console.log();
660
+ console.log(chalk.gray('Add your first teammate:'));
661
+ console.log(chalk.gray(` agents teams add ${team} claude "your task here"`));
662
+ }
663
+ catch (err) {
664
+ die(err.message);
665
+ }
666
+ });
667
+ // add
668
+ teams
669
+ .command('add <team> <teammate> <task>')
670
+ .alias('a')
671
+ .description("Add a teammate to work on a task. Runs in background; returns immediately. Use 'status' to check in.")
672
+ .option('-n, --name <name>', 'Friendly name for this teammate (e.g. alice). Required if using --after. Unique within team.')
673
+ .option('-m, --mode <mode>', `Permissions: plan (read-only) | edit (can write files) | full (write + skip permission prompts)`, 'edit')
674
+ .option('-e, --effort <effort>', `Reasoning intensity: ${VALID_EFFORTS.join('|')}`, 'medium')
675
+ .option('--model <model>', 'Override the effort tier and use this specific model (e.g. claude-opus-4-6)')
676
+ .option('--env <key=value>', 'Set an environment variable for this teammate (repeatable for multiple vars)', (val, prev) => [...prev, val], [])
677
+ .option('--cwd <dir>', 'Working directory for this teammate (default: current directory)')
678
+ .option('--after <names>', "DAG dependencies: comma-separated teammate names to wait for. Stages as PENDING; run 'teams start' to launch when ready.")
679
+ .option('--task-type <type>', `Factory label: ${VALID_TASK_TYPES.join('|')}. Drives planner fan-out + test-oracle bugfix loop.`)
680
+ .option('--cloud <provider>', `Dispatch to cloud backend instead of local CLI: ${VALID_CLOUD_PROVIDERS.join('|')}`)
681
+ .option('--repo <owner/repo>', 'GitHub repository (required for --cloud rush)')
682
+ .option('--branch <name>', 'Target git branch for cloud dispatch')
683
+ .option('--json', 'Output machine-readable JSON')
684
+ .action(async (team, teammate, task, opts) => {
685
+ if (!VALID_MODES.includes(opts.mode)) {
686
+ die(`Invalid mode '${opts.mode}'. Use one of: ${VALID_MODES.join(', ')}`);
687
+ }
688
+ if (!VALID_EFFORTS.includes(opts.effort)) {
689
+ die(`Invalid effort '${opts.effort}'. Use one of: ${VALID_EFFORTS.join(', ')}`);
690
+ }
691
+ let taskType = null;
692
+ if (opts.taskType) {
693
+ if (!VALID_TASK_TYPES.includes(opts.taskType)) {
694
+ die(`Invalid task-type '${opts.taskType}'. Use one of: ${VALID_TASK_TYPES.join(', ')}`);
695
+ }
696
+ taskType = opts.taskType;
697
+ }
698
+ let cloudProviderId = null;
699
+ if (opts.cloud) {
700
+ if (!VALID_CLOUD_PROVIDERS.includes(opts.cloud)) {
701
+ die(`Invalid cloud provider '${opts.cloud}'. Use one of: ${VALID_CLOUD_PROVIDERS.join(', ')}`);
702
+ }
703
+ cloudProviderId = opts.cloud;
704
+ if (cloudProviderId === 'rush' && !opts.repo) {
705
+ die(`--cloud rush requires --repo <owner/repo>`);
706
+ }
707
+ }
708
+ const { agent, version } = parseTeammate(teammate);
709
+ if (version && !isVersionInstalled(agent, version)) {
710
+ die(`${AGENT_NAMES[agent]} ${version} isn't installed.\n` +
711
+ ` Install it: agents add ${agent}@${version}\n` +
712
+ ` Or see what's installed: agents view ${agent}`);
713
+ }
714
+ if (opts.name !== undefined) {
715
+ if (!opts.name || !/^[A-Za-z0-9_-]+$/.test(opts.name)) {
716
+ die(`Invalid teammate name '${opts.name}'. Use letters, numbers, '-', or '_'.`);
717
+ }
718
+ }
719
+ const after = opts.after
720
+ ? opts.after.split(',').map((s) => s.trim()).filter(Boolean)
721
+ : [];
722
+ if (after.length > 0 && !opts.name) {
723
+ die("--after requires --name (dependencies reference teammates by name).");
724
+ }
725
+ let envOverrides;
726
+ try {
727
+ envOverrides = parseExecEnv(opts.env);
728
+ }
729
+ catch (err) {
730
+ die(err.message);
731
+ }
732
+ // Auto-create the team if it doesn't exist yet (friendlier UX than erroring).
733
+ await ensureTeam(team);
734
+ const cwd = opts.cwd ?? process.cwd();
735
+ const mgr = mkManager();
736
+ // Factory teammates: prepend the worker-skill preamble to every task
737
+ // prompt so implementers/testers/reviewers know about the Ledger, the
738
+ // dynamic DAG, and the pattern for filing new tasks mid-flight. No
739
+ // preamble when --task-type isn't set (plain teammates work as before).
740
+ let effectiveTask = task;
741
+ if (taskType) {
742
+ effectiveTask = factoryWorkerPreamble(team, opts.name ?? null, taskType, after) + '\n\n' + task;
743
+ }
744
+ // Dispatcher callback: when a staged cloud teammate's deps resolve,
745
+ // AgentManager.startReady() invokes this to kick off the remote task.
746
+ if (cloudProviderId) {
747
+ const providerId = cloudProviderId;
748
+ mgr.setCloudDispatcher(async (a) => {
749
+ const prov = resolveProvider(providerId);
750
+ const dispatchOpts = {
751
+ prompt: a.prompt,
752
+ agent: a.agentType,
753
+ repo: opts.repo,
754
+ branch: opts.branch,
755
+ model: a.model ?? undefined,
756
+ };
757
+ const cloudTask = await prov.dispatch(dispatchOpts);
758
+ return { cloudSessionId: cloudTask.id };
759
+ });
760
+ }
761
+ let cloudSessionId = null;
762
+ const isStaged = after.length > 0;
763
+ if (cloudProviderId && !isStaged) {
764
+ // Ready to run now: dispatch to the cloud provider before registering
765
+ // the teammate so we have the remote session id up front.
766
+ const prov = resolveProvider(cloudProviderId);
767
+ const dispatchOpts = {
768
+ prompt: effectiveTask,
769
+ agent,
770
+ repo: opts.repo,
771
+ branch: opts.branch,
772
+ model: opts.model,
773
+ };
774
+ try {
775
+ const cloudTask = await prov.dispatch(dispatchOpts);
776
+ cloudSessionId = cloudTask.id;
777
+ }
778
+ catch (err) {
779
+ die(`Cloud dispatch failed: ${err.message}`);
780
+ }
781
+ }
782
+ try {
783
+ const result = await handleSpawn(mgr, team, agent, effectiveTask, cwd, opts.mode, opts.effort, null, cwd, version, opts.name ?? null, after, opts.model ?? null, envOverrides ?? null, taskType, cloudProviderId, cloudSessionId, opts.repo ?? null, opts.branch ?? null);
784
+ if (isJsonMode(opts)) {
785
+ console.log(JSON.stringify(result, null, 2));
786
+ return;
787
+ }
788
+ const who = fullName(agent, version);
789
+ const staged = result.status === 'pending';
790
+ const verb = staged ? 'Staged' : 'Welcomed';
791
+ const greeting = result.name
792
+ ? `${verb} ${chalk.cyan(result.name)} (${who}) ${staged ? 'in' : 'to'} team ${chalk.cyan(team)}`
793
+ : `${verb} ${who} ${staged ? 'in' : 'to'} team ${chalk.cyan(team)}`;
794
+ console.log(chalk.green(greeting));
795
+ if (result.name) {
796
+ console.log(` ${chalk.gray('name ')} ${chalk.cyan(result.name)}`);
797
+ }
798
+ console.log(` ${chalk.gray('agent_id')} ${chalk.cyan(shortId(result.agent_id))} ${chalk.gray(`(${result.agent_id})`)}`);
799
+ console.log(` ${chalk.gray('status ')} ${statusColor(result.status)(result.status)}`);
800
+ console.log(` ${chalk.gray('mode ')} ${opts.mode}`);
801
+ console.log(` ${chalk.gray('working ')} ${cwd}`);
802
+ if (result.task_type) {
803
+ console.log(` ${chalk.gray('task ')} ${chalk.cyan(result.task_type)}`);
804
+ }
805
+ if (result.cloud_provider) {
806
+ console.log(` ${chalk.gray('cloud ')} ${chalk.magenta(result.cloud_provider)}${result.cloud_session_id ? chalk.gray(' — ' + result.cloud_session_id.slice(0, 12)) : ''}`);
807
+ }
808
+ if (result.after && result.after.length) {
809
+ console.log(` ${chalk.gray('after ')} ${result.after.join(', ')}`);
810
+ }
811
+ console.log();
812
+ if (staged) {
813
+ console.log(chalk.gray(`Start the ready teammates: agents teams start ${team}`));
814
+ }
815
+ else {
816
+ console.log(chalk.gray(`Check in later: agents teams status ${team}`));
817
+ }
818
+ }
819
+ catch (err) {
820
+ die(`Could not add ${fullName(agent, version)} to ${team}: ${err.message}`);
821
+ }
822
+ });
823
+ // status
824
+ teams
825
+ .command('status [team]')
826
+ .aliases(['s', 'st', 'check'])
827
+ .description("Check in on a team: who's working, what files they touched, recent commands, last output. Pass --since for efficient delta polling.")
828
+ .option('-f, --filter <state>', 'Show only teammates in this state: working, completed, failed, stopped, or all (default: all)', 'all')
829
+ .option('-s, --since <iso>', 'Cursor from a previous status call; only show updates after this timestamp (enables efficient polling)')
830
+ .option('--agent-id <id>', 'Show only this one teammate (by UUID or UUID prefix)')
831
+ .option('--json', 'Output machine-readable JSON')
832
+ .action(async (team, opts) => {
833
+ // Map friendly 'working' → internal 'running' for filter.
834
+ const filter = opts.filter === 'working' ? 'running' : opts.filter;
835
+ const mgr = mkManager();
836
+ // No team given → drop into the picker (TTY) or fail clearly (script).
837
+ if (!team) {
838
+ const picked = await pickTeamOr(mgr, 'agents teams status');
839
+ if (!picked)
840
+ return;
841
+ team = picked;
842
+ }
843
+ try {
844
+ const result = await handleStatus(mgr, team, filter, opts.since);
845
+ const agents = opts.agentId
846
+ ? result.agents.filter((a) => a.agent_id.startsWith(opts.agentId))
847
+ : result.agents;
848
+ if (isJsonMode(opts)) {
849
+ console.log(JSON.stringify({ ...result, agents }, null, 2));
850
+ return;
851
+ }
852
+ const exists = await teamExists(team);
853
+ if (!exists && result.agents.length === 0) {
854
+ console.log(chalk.yellow(`No team called '${team}'. Create it with: agents teams create ${team}`));
855
+ return;
856
+ }
857
+ await printTeamStatus(team, { ...result, agents });
858
+ }
859
+ catch (err) {
860
+ die(`Could not check on team ${team}: ${err.message}`);
861
+ }
862
+ });
863
+ // start — fire any staged teammates whose --after deps have all completed
864
+ teams
865
+ .command('start [team]')
866
+ .description('Launch any pending teammates whose --after dependencies are satisfied. Use --watch to keep draining the DAG as teammates finish and as new tasks are added mid-flight.')
867
+ .option('--json', 'Output machine-readable JSON')
868
+ .option('--watch', 'Keep running: poll every --interval seconds, fire new waves, exit when the DAG drains.')
869
+ .option('--interval <seconds>', 'Seconds between waves in --watch mode (default 8)', '8')
870
+ .option('--max-waves <n>', 'Safety cap on waves in --watch mode (default 1000)', '1000')
871
+ .action(async (team, opts) => {
872
+ const mgr = mkManager();
873
+ wireCloudDispatcher(mgr);
874
+ if (!team) {
875
+ const picked = await pickTeamOr(mgr, 'agents teams start');
876
+ if (!picked)
877
+ return;
878
+ team = picked;
879
+ }
880
+ if (!opts.watch) {
881
+ await runOneWave(mgr, team, Boolean(opts.json));
882
+ return;
883
+ }
884
+ const intervalMs = Math.max(1000, Number.parseInt(opts.interval, 10) * 1000 || 8000);
885
+ const maxWaves = Math.max(1, Number.parseInt(opts.maxWaves, 10) || 1000);
886
+ const json = isJsonMode(opts);
887
+ const result = await runSupervisor(mgr, {
888
+ team,
889
+ intervalMs,
890
+ maxWaves,
891
+ onWave: (s) => {
892
+ const ts = s.timestamp.slice(11, 19);
893
+ if (json) {
894
+ console.log(JSON.stringify({
895
+ wave: s.wave, ts, team: s.team, launched: s.launched.length,
896
+ pending: s.pending, running: s.running, completed: s.completed, failed: s.failed,
897
+ }));
898
+ return;
899
+ }
900
+ console.log(`[${ts}] wave ${s.wave} team ${chalk.cyan(s.team)} ` +
901
+ `launched=${chalk.green(s.launched.length)} running=${chalk.yellow(s.running)} ` +
902
+ `pending=${chalk.blue(s.pending)} done=${chalk.green(s.completed)} ` +
903
+ `failed=${s.failed > 0 ? chalk.red(s.failed) : '0'}`);
904
+ },
905
+ });
906
+ const elapsed = Math.floor(result.elapsed_ms / 1000);
907
+ if (result.stoppedBy === 'drained') {
908
+ console.log(chalk.green(`Factory drained in ${elapsed}s (${result.waves} waves).`));
909
+ }
910
+ else if (result.stoppedBy === 'max-waves') {
911
+ console.error(chalk.yellow(`Hit --max-waves=${maxWaves}; stopping. Re-run to continue.`));
912
+ }
913
+ else if (result.stoppedBy === 'signal') {
914
+ console.error(chalk.yellow(`Stopped by signal after ${result.waves} waves.`));
915
+ }
916
+ });
917
+ // remove
918
+ teams
919
+ .command('remove [team] [teammate]')
920
+ .alias('rm')
921
+ .description("Remove a teammate from the team. Stops them cleanly if still working. Accepts name, UUID, or UUID prefix.")
922
+ .option('--keep-logs', 'Keep their log files on disk (default: delete them)')
923
+ .option('--json', 'Output machine-readable JSON')
924
+ .action(async (team, ref, opts) => {
925
+ const mgr = mkManager();
926
+ if (!team) {
927
+ const { names } = await loadTeamRows(mgr);
928
+ requireDestructiveArg({
929
+ argName: 'team',
930
+ command: 'agents teams remove',
931
+ itemNoun: 'team',
932
+ available: names,
933
+ emptyHint: "You don't have any teams yet.",
934
+ });
935
+ }
936
+ if (!ref) {
937
+ const roster = await mgr.listByTask(team);
938
+ requireDestructiveArg({
939
+ argName: 'teammate',
940
+ command: `agents teams remove ${team}`,
941
+ itemNoun: 'teammate',
942
+ available: roster.map((a) => a.name || shortId(a.agentId)),
943
+ emptyHint: `Team ${team} has no teammates.`,
944
+ });
945
+ }
946
+ const lookup = await mgr.resolveAgentIdInTask(team, ref);
947
+ if (lookup.kind === 'none') {
948
+ die(`No teammate matching '${ref}' in team ${team}`, 2);
949
+ }
950
+ if (lookup.kind === 'ambiguous') {
951
+ const shorts = lookup.matches.map(shortId).join(', ');
952
+ die(`'${ref}' matches multiple teammates: ${shorts}. Use more characters or a name.`, 2);
953
+ }
954
+ const agentId = lookup.agentId;
955
+ // Look up the display handle (name if they had one) before we tear down.
956
+ const agent = await mgr.get(agentId);
957
+ const display = agent?.name || shortId(agentId);
958
+ const stopRes = await handleStop(mgr, team, agentId);
959
+ if ('error' in stopRes)
960
+ die(stopRes.error);
961
+ if (!opts.keepLogs && stopRes.not_found.length === 0) {
962
+ try {
963
+ const dir = path.join(await getAgentsDir(), agentId);
964
+ await fs.rm(dir, { recursive: true, force: true });
965
+ }
966
+ catch {
967
+ // best-effort cleanup
968
+ }
969
+ }
970
+ if (isJsonMode(opts)) {
971
+ console.log(JSON.stringify({ team, agent_id: agentId, name: agent?.name ?? null, result: stopRes }, null, 2));
972
+ return;
973
+ }
974
+ if (stopRes.stopped.length) {
975
+ console.log(chalk.green(`${display} has left team ${chalk.cyan(team)} (was working, now stopped).`));
976
+ }
977
+ else {
978
+ console.log(chalk.green(`${display} has left team ${chalk.cyan(team)}.`));
979
+ }
980
+ });
981
+ // disband
982
+ teams
983
+ .command('disband [team]')
984
+ .alias('d')
985
+ .description('Disband the team. Stops all teammates cleanly and removes the team registry entry.')
986
+ .option('--keep-logs', 'Keep all teammate logs on disk (default: delete them)')
987
+ .option('--json', 'Output machine-readable JSON')
988
+ .action(async (team, opts) => {
989
+ const mgr = mkManager();
990
+ if (!team) {
991
+ const { names } = await loadTeamRows(mgr);
992
+ requireDestructiveArg({
993
+ argName: 'team',
994
+ command: 'agents teams disband',
995
+ itemNoun: 'team',
996
+ available: names,
997
+ emptyHint: "You don't have any teams to disband.",
998
+ });
999
+ }
1000
+ const stopRes = await handleStop(mgr, team);
1001
+ if ('error' in stopRes)
1002
+ die(stopRes.error);
1003
+ const status = await handleStatus(mgr, team, 'all');
1004
+ const removedIds = [];
1005
+ if (!opts.keepLogs) {
1006
+ const base = await getAgentsDir();
1007
+ for (const a of status.agents) {
1008
+ try {
1009
+ await fs.rm(path.join(base, a.agent_id), { recursive: true, force: true });
1010
+ removedIds.push(a.agent_id);
1011
+ }
1012
+ catch { /* best-effort */ }
1013
+ }
1014
+ }
1015
+ const existed = await removeTeam(team);
1016
+ if (isJsonMode(opts)) {
1017
+ console.log(JSON.stringify({ team, existed, stopped: stopRes.stopped, removed_members: removedIds }, null, 2));
1018
+ return;
1019
+ }
1020
+ if (!existed && stopRes.stopped.length === 0 && status.agents.length === 0) {
1021
+ die(`No team called '${team}'`, 2);
1022
+ }
1023
+ console.log(chalk.green(`Team ${chalk.cyan(team)} disbanded.`));
1024
+ if (stopRes.stopped.length)
1025
+ console.log(chalk.gray(` Stopped ${stopRes.stopped.length} working teammate(s).`));
1026
+ if (removedIds.length)
1027
+ console.log(chalk.gray(` Cleared ${removedIds.length} teammate log(s).`));
1028
+ });
1029
+ // logs
1030
+ teams
1031
+ .command('logs [teammate]')
1032
+ .alias('log')
1033
+ .description("Read a teammate's raw log output. Accepts name, UUID, or UUID prefix.")
1034
+ .option('-n, --tail <n>', 'Show only the last N lines instead of the full log')
1035
+ .option('--team <team>', 'Disambiguate when the same name appears in multiple teams')
1036
+ .action(async (ref, opts) => {
1037
+ const base = await getAgentsDir();
1038
+ // No teammate → picker in TTY, hard fail outside.
1039
+ let agentId;
1040
+ if (!ref) {
1041
+ const mgr = mkManager();
1042
+ const picked = await pickTeammateOr(mgr, 'agents teams logs');
1043
+ if (!picked)
1044
+ return;
1045
+ agentId = picked.agentId;
1046
+ }
1047
+ else {
1048
+ const resolved = await resolveTeammateAcrossTeams(base, ref, opts.team);
1049
+ if (resolved.kind === 'none') {
1050
+ die(`No notes on record for teammate '${ref}'`, 2);
1051
+ }
1052
+ if (resolved.kind === 'ambiguous') {
1053
+ const hints = resolved.candidates.map((c) => `${c.team}/${c.display}`).join(', ');
1054
+ die(`'${ref}' matches multiple teammates: ${hints}.\n` +
1055
+ ` Narrow it with --team <team>, or pass a UUID prefix.`, 2);
1056
+ }
1057
+ agentId = resolved.agentId;
1058
+ }
1059
+ const logPath = path.join(base, agentId, 'stdout.log');
1060
+ try {
1061
+ const content = await fs.readFile(logPath, 'utf-8');
1062
+ if (!opts.tail) {
1063
+ process.stdout.write(content);
1064
+ return;
1065
+ }
1066
+ const n = Math.max(1, parseInt(opts.tail, 10) || 50);
1067
+ const lines = content.split('\n');
1068
+ process.stdout.write(lines.slice(-n).join('\n'));
1069
+ }
1070
+ catch {
1071
+ die(`No notes on record for teammate '${ref ?? agentId}' (looked in ${logPath})`, 2);
1072
+ }
1073
+ });
1074
+ // doctor
1075
+ teams
1076
+ .command('doctor')
1077
+ .alias('dr')
1078
+ .description('Check which agents are installed and available to join a team. Verifies CLI paths.')
1079
+ .option('--json', 'Output machine-readable JSON')
1080
+ .action(async (opts) => {
1081
+ const info = checkAllClis();
1082
+ if (isJsonMode(opts)) {
1083
+ console.log(JSON.stringify(info, null, 2));
1084
+ return;
1085
+ }
1086
+ console.log(chalk.bold('Who can join a team:'));
1087
+ for (const [name, entry] of Object.entries(info)) {
1088
+ const pretty = AGENT_NAMES[name] || name;
1089
+ if (entry.installed) {
1090
+ console.log(` ${chalk.green('ready')} ${pretty.padEnd(10)} ${chalk.gray(entry.path || '')}`);
1091
+ }
1092
+ else {
1093
+ console.log(` ${chalk.red('no ')} ${pretty.padEnd(10)} ${chalk.gray(entry.error || 'not installed')}`);
1094
+ }
1095
+ }
1096
+ });
1097
+ }
1098
+ //# sourceMappingURL=teams.js.map