@phnx-labs/agents-cli 1.12.0 → 1.14.2

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 (496) hide show
  1. package/CHANGELOG.md +7 -1
  2. package/README.md +308 -297
  3. package/dist/commands/alias.d.ts +11 -0
  4. package/dist/commands/alias.js +117 -0
  5. package/dist/commands/beta.d.ts +2 -0
  6. package/dist/commands/beta.js +53 -0
  7. package/dist/commands/cloud.d.ts +10 -0
  8. package/dist/commands/cloud.js +408 -0
  9. package/dist/commands/commands.d.ts +9 -1
  10. package/dist/commands/commands.js +24 -172
  11. package/dist/commands/daemon.d.ts +8 -1
  12. package/dist/commands/daemon.js +13 -5
  13. package/dist/commands/doctor.d.ts +15 -0
  14. package/dist/commands/doctor.js +132 -0
  15. package/dist/commands/drive.d.ts +8 -1
  16. package/dist/commands/drive.js +20 -3
  17. package/dist/commands/exec.d.ts +8 -1
  18. package/dist/commands/exec.js +207 -20
  19. package/dist/commands/factory.d.ts +19 -0
  20. package/dist/commands/factory.js +71 -0
  21. package/dist/commands/fork.d.ts +8 -1
  22. package/dist/commands/fork.js +11 -4
  23. package/dist/commands/hooks.d.ts +9 -1
  24. package/dist/commands/hooks.js +30 -182
  25. package/dist/commands/init.d.ts +15 -1
  26. package/dist/commands/init.js +168 -74
  27. package/dist/commands/mcp.d.ts +9 -1
  28. package/dist/commands/mcp.js +11 -7
  29. package/dist/commands/models.d.ts +8 -1
  30. package/dist/commands/models.js +45 -6
  31. package/dist/commands/packages.d.ts +8 -1
  32. package/dist/commands/packages.js +13 -7
  33. package/dist/commands/permissions.d.ts +9 -1
  34. package/dist/commands/permissions.js +3 -3
  35. package/dist/commands/plugins.d.ts +8 -1
  36. package/dist/commands/plugins.js +13 -2
  37. package/dist/commands/profiles.d.ts +11 -0
  38. package/dist/commands/profiles.js +291 -0
  39. package/dist/commands/prune.d.ts +22 -0
  40. package/dist/commands/prune.js +191 -0
  41. package/dist/commands/pty.d.ts +1 -1
  42. package/dist/commands/pty.js +2 -1
  43. package/dist/commands/pull.d.ts +8 -1
  44. package/dist/commands/pull.js +93 -129
  45. package/dist/commands/refresh-memory.d.ts +7 -1
  46. package/dist/commands/refresh-memory.js +7 -1
  47. package/dist/commands/repo.d.ts +15 -0
  48. package/dist/commands/repo.js +570 -0
  49. package/dist/commands/resource-view.d.ts +10 -3
  50. package/dist/commands/resource-view.js +18 -5
  51. package/dist/commands/routines.d.ts +8 -1
  52. package/dist/commands/routines.js +17 -4
  53. package/dist/commands/rules.d.ts +9 -1
  54. package/dist/commands/rules.js +16 -11
  55. package/dist/commands/secrets.d.ts +10 -0
  56. package/dist/commands/secrets.js +518 -0
  57. package/dist/commands/sessions-picker.d.ts +2 -1
  58. package/dist/commands/sessions-picker.js +88 -11
  59. package/dist/commands/sessions-tail.d.ts +19 -0
  60. package/dist/commands/sessions-tail.js +235 -0
  61. package/dist/commands/sessions.d.ts +2 -1
  62. package/dist/commands/sessions.js +288 -7
  63. package/dist/commands/skills.d.ts +9 -1
  64. package/dist/commands/skills.js +28 -178
  65. package/dist/commands/status.d.ts +7 -1
  66. package/dist/commands/status.js +7 -1
  67. package/dist/commands/subagents.d.ts +8 -1
  68. package/dist/commands/subagents.js +11 -1
  69. package/dist/commands/sync.d.ts +8 -1
  70. package/dist/commands/sync.js +8 -1
  71. package/dist/commands/teams-picker.d.ts +4 -1
  72. package/dist/commands/teams-picker.js +55 -3
  73. package/dist/commands/teams.d.ts +15 -1
  74. package/dist/commands/teams.js +323 -69
  75. package/dist/commands/usage.d.ts +11 -0
  76. package/dist/commands/usage.js +60 -0
  77. package/dist/commands/utils.d.ts +6 -1
  78. package/dist/commands/utils.js +6 -1
  79. package/dist/commands/versions.d.ts +8 -1
  80. package/dist/commands/versions.js +4 -3
  81. package/dist/commands/view.d.ts +47 -2
  82. package/dist/commands/view.js +353 -20
  83. package/dist/index.d.ts +7 -2
  84. package/dist/index.js +205 -38
  85. package/dist/lib/acp/client.d.ts +31 -0
  86. package/dist/lib/acp/client.js +117 -0
  87. package/dist/lib/acp/harnesses.d.ts +26 -0
  88. package/dist/lib/acp/harnesses.js +65 -0
  89. package/dist/lib/acp/run.d.ts +18 -0
  90. package/dist/lib/acp/run.js +39 -0
  91. package/dist/lib/agents.d.ts +74 -2
  92. package/dist/lib/agents.js +207 -23
  93. package/dist/lib/artifact-actions.d.ts +8 -4
  94. package/dist/lib/artifact-actions.js +8 -6
  95. package/dist/lib/auto-pull-worker.d.ts +11 -0
  96. package/dist/lib/auto-pull-worker.js +121 -0
  97. package/dist/lib/auto-pull.d.ts +31 -0
  98. package/dist/lib/auto-pull.js +97 -0
  99. package/dist/lib/beta.d.ts +23 -0
  100. package/dist/lib/beta.js +90 -0
  101. package/dist/lib/capabilities.d.ts +29 -0
  102. package/dist/lib/capabilities.js +74 -0
  103. package/dist/lib/cloud/codex.d.ts +25 -0
  104. package/dist/lib/cloud/codex.js +250 -0
  105. package/dist/lib/cloud/factory.d.ts +31 -0
  106. package/dist/lib/cloud/factory.js +53 -0
  107. package/dist/lib/cloud/registry.d.ts +15 -0
  108. package/dist/lib/cloud/registry.js +67 -0
  109. package/dist/lib/cloud/rush.d.ts +75 -0
  110. package/dist/lib/cloud/rush.js +438 -0
  111. package/dist/lib/cloud/store.d.ts +22 -0
  112. package/dist/lib/cloud/store.js +115 -0
  113. package/dist/lib/cloud/stream.d.ts +23 -0
  114. package/dist/lib/cloud/stream.js +194 -0
  115. package/dist/lib/cloud/types.d.ts +205 -0
  116. package/dist/lib/cloud/types.js +34 -0
  117. package/dist/lib/command-skills.d.ts +20 -0
  118. package/dist/lib/command-skills.js +142 -0
  119. package/dist/lib/commands.d.ts +22 -2
  120. package/dist/lib/commands.js +51 -11
  121. package/dist/lib/convert.d.ts +10 -1
  122. package/dist/lib/convert.js +9 -1
  123. package/dist/lib/daemon.d.ts +21 -1
  124. package/dist/lib/daemon.js +97 -4
  125. package/dist/lib/drive-sync.d.ts +18 -1
  126. package/dist/lib/drive-sync.js +57 -15
  127. package/dist/lib/exec.d.ts +25 -5
  128. package/dist/lib/exec.js +72 -27
  129. package/dist/lib/fs-walk.d.ts +2 -0
  130. package/dist/lib/fs-walk.js +40 -0
  131. package/dist/lib/fuzzy.d.ts +53 -0
  132. package/dist/lib/fuzzy.js +72 -0
  133. package/dist/lib/gemini-settings.d.ts +4 -0
  134. package/dist/lib/gemini-settings.js +33 -0
  135. package/dist/lib/git.d.ts +12 -2
  136. package/dist/lib/git.js +17 -6
  137. package/dist/lib/help.d.ts +20 -1
  138. package/dist/lib/help.js +45 -6
  139. package/dist/lib/hooks/match.d.ts +32 -0
  140. package/dist/lib/hooks/match.js +120 -0
  141. package/dist/lib/hooks.d.ts +17 -4
  142. package/dist/lib/hooks.js +191 -21
  143. package/dist/lib/manifest.d.ts +6 -1
  144. package/dist/lib/manifest.js +15 -4
  145. package/dist/lib/markdown.d.ts +0 -1
  146. package/dist/lib/markdown.js +6 -1
  147. package/dist/lib/mcp.d.ts +0 -1
  148. package/dist/lib/mcp.js +29 -33
  149. package/dist/lib/memory-compile.d.ts +13 -3
  150. package/dist/lib/memory-compile.js +31 -9
  151. package/dist/lib/memory.d.ts +14 -7
  152. package/dist/lib/memory.js +67 -38
  153. package/dist/lib/migrate.d.ts +8 -0
  154. package/dist/lib/migrate.js +85 -0
  155. package/dist/lib/models.d.ts +25 -11
  156. package/dist/lib/models.js +405 -16
  157. package/dist/lib/onepassword.d.ts +63 -0
  158. package/dist/lib/onepassword.js +186 -0
  159. package/dist/lib/paths.d.ts +8 -0
  160. package/dist/lib/paths.js +20 -0
  161. package/dist/lib/permissions.d.ts +24 -2
  162. package/dist/lib/permissions.js +117 -48
  163. package/dist/lib/picker.d.ts +10 -1
  164. package/dist/lib/picker.js +15 -1
  165. package/dist/lib/plugins.d.ts +7 -1
  166. package/dist/lib/plugins.js +10 -1
  167. package/dist/lib/profiles-presets.d.ts +24 -0
  168. package/dist/lib/profiles-presets.js +103 -0
  169. package/dist/lib/profiles.d.ts +69 -0
  170. package/dist/lib/profiles.js +144 -0
  171. package/dist/lib/pty-client.d.ts +1 -1
  172. package/dist/lib/pty-client.js +0 -1
  173. package/dist/lib/pty-server.d.ts +16 -2
  174. package/dist/lib/pty-server.js +92 -3
  175. package/dist/lib/registry.d.ts +23 -3
  176. package/dist/lib/registry.js +153 -8
  177. package/dist/lib/resources.d.ts +28 -1
  178. package/dist/lib/resources.js +79 -1
  179. package/dist/lib/rotate.d.ts +89 -0
  180. package/dist/lib/rotate.js +327 -0
  181. package/dist/lib/routines.d.ts +29 -1
  182. package/dist/lib/routines.js +32 -5
  183. package/dist/lib/runner.d.ts +14 -1
  184. package/dist/lib/runner.js +22 -3
  185. package/dist/lib/sandbox.d.ts +16 -1
  186. package/dist/lib/sandbox.js +39 -16
  187. package/dist/lib/scheduler.d.ts +8 -1
  188. package/dist/lib/scheduler.js +8 -1
  189. package/dist/lib/secrets/AgentsKeychain.app/Contents/CodeResources +0 -0
  190. package/dist/lib/secrets/AgentsKeychain.app/Contents/Info.plist +22 -0
  191. package/dist/lib/secrets/AgentsKeychain.app/Contents/MacOS/AgentsKeychain +0 -0
  192. package/dist/lib/secrets/AgentsKeychain.app/Contents/_CodeSignature/CodeResources +123 -0
  193. package/dist/lib/secrets/AgentsKeychain.app/Contents/embedded.provisionprofile +0 -0
  194. package/dist/lib/secrets/bundles.d.ts +39 -0
  195. package/dist/lib/secrets/bundles.js +189 -0
  196. package/dist/lib/secrets/index.d.ts +55 -0
  197. package/dist/lib/secrets/index.js +211 -0
  198. package/dist/lib/secrets/profiles.d.ts +10 -0
  199. package/dist/lib/secrets/profiles.js +13 -0
  200. package/dist/lib/session/active.d.ts +43 -0
  201. package/dist/lib/session/active.js +392 -0
  202. package/dist/lib/session/artifacts.d.ts +16 -0
  203. package/dist/lib/session/artifacts.js +95 -0
  204. package/dist/lib/session/cloud.d.ts +30 -0
  205. package/dist/lib/session/cloud.js +121 -0
  206. package/dist/lib/session/db.d.ts +23 -2
  207. package/dist/lib/session/db.js +76 -12
  208. package/dist/lib/session/discover.d.ts +19 -4
  209. package/dist/lib/session/discover.js +344 -48
  210. package/dist/lib/session/parse.d.ts +28 -1
  211. package/dist/lib/session/parse.js +267 -9
  212. package/dist/lib/session/prompt.d.ts +9 -1
  213. package/dist/lib/session/prompt.js +17 -3
  214. package/dist/lib/session/render.d.ts +13 -1
  215. package/dist/lib/session/render.js +20 -1
  216. package/dist/lib/session/team-filter.d.ts +9 -1
  217. package/dist/lib/session/team-filter.js +11 -2
  218. package/dist/lib/session/types.d.ts +24 -2
  219. package/dist/lib/session/types.js +10 -2
  220. package/dist/lib/shims.d.ts +93 -5
  221. package/dist/lib/shims.js +380 -67
  222. package/dist/lib/skills.d.ts +27 -2
  223. package/dist/lib/skills.js +127 -65
  224. package/dist/lib/sqlite.d.ts +43 -0
  225. package/dist/lib/sqlite.js +94 -0
  226. package/dist/lib/state.d.ts +114 -22
  227. package/dist/lib/state.js +323 -138
  228. package/dist/lib/subagents.d.ts +9 -1
  229. package/dist/lib/subagents.js +70 -63
  230. package/dist/lib/sync-manifest.d.ts +81 -0
  231. package/dist/lib/sync-manifest.js +450 -0
  232. package/dist/lib/teams/agents.d.ts +103 -5
  233. package/dist/lib/teams/agents.js +414 -91
  234. package/dist/lib/teams/api.d.ts +26 -3
  235. package/dist/lib/teams/api.js +63 -3
  236. package/dist/lib/teams/debug.d.ts +6 -1
  237. package/dist/lib/teams/debug.js +6 -1
  238. package/dist/lib/teams/file_ops.d.ts +7 -1
  239. package/dist/lib/teams/file_ops.js +7 -1
  240. package/dist/lib/teams/index.d.ts +15 -0
  241. package/dist/lib/teams/index.js +14 -0
  242. package/dist/lib/teams/parsers.d.ts +4 -1
  243. package/dist/lib/teams/parsers.js +11 -1
  244. package/dist/lib/teams/persistence.d.ts +15 -1
  245. package/dist/lib/teams/persistence.js +102 -20
  246. package/dist/lib/teams/registry.d.ts +12 -1
  247. package/dist/lib/teams/registry.js +116 -33
  248. package/dist/lib/teams/summarizer.d.ts +15 -1
  249. package/dist/lib/teams/summarizer.js +14 -1
  250. package/dist/lib/teams/supervisor.d.ts +48 -0
  251. package/dist/lib/teams/supervisor.js +73 -0
  252. package/dist/lib/template.d.ts +8 -6
  253. package/dist/lib/template.js +8 -6
  254. package/dist/lib/types.d.ts +147 -8
  255. package/dist/lib/types.js +26 -3
  256. package/dist/lib/usage.d.ts +48 -1
  257. package/dist/lib/usage.js +97 -16
  258. package/dist/lib/version-duplicates.d.ts +21 -0
  259. package/dist/lib/version-duplicates.js +90 -0
  260. package/dist/lib/versions.d.ts +39 -4
  261. package/dist/lib/versions.js +401 -111
  262. package/package.json +33 -18
  263. package/scripts/postinstall.js +126 -30
  264. package/dist/commands/__tests__/sessions.test.d.ts +0 -2
  265. package/dist/commands/__tests__/sessions.test.d.ts.map +0 -1
  266. package/dist/commands/__tests__/sessions.test.js +0 -636
  267. package/dist/commands/__tests__/sessions.test.js.map +0 -1
  268. package/dist/commands/commands.d.ts.map +0 -1
  269. package/dist/commands/commands.js.map +0 -1
  270. package/dist/commands/daemon.d.ts.map +0 -1
  271. package/dist/commands/daemon.js.map +0 -1
  272. package/dist/commands/drive.d.ts.map +0 -1
  273. package/dist/commands/drive.js.map +0 -1
  274. package/dist/commands/exec.d.ts.map +0 -1
  275. package/dist/commands/exec.js.map +0 -1
  276. package/dist/commands/fork.d.ts.map +0 -1
  277. package/dist/commands/fork.js.map +0 -1
  278. package/dist/commands/hooks.d.ts.map +0 -1
  279. package/dist/commands/hooks.js.map +0 -1
  280. package/dist/commands/init.d.ts.map +0 -1
  281. package/dist/commands/init.js.map +0 -1
  282. package/dist/commands/mcp.d.ts.map +0 -1
  283. package/dist/commands/mcp.js.map +0 -1
  284. package/dist/commands/models.d.ts.map +0 -1
  285. package/dist/commands/models.js.map +0 -1
  286. package/dist/commands/packages.d.ts.map +0 -1
  287. package/dist/commands/packages.js.map +0 -1
  288. package/dist/commands/permissions.d.ts.map +0 -1
  289. package/dist/commands/permissions.js.map +0 -1
  290. package/dist/commands/plugins.d.ts.map +0 -1
  291. package/dist/commands/plugins.js.map +0 -1
  292. package/dist/commands/pty.d.ts.map +0 -1
  293. package/dist/commands/pty.js.map +0 -1
  294. package/dist/commands/pull.d.ts.map +0 -1
  295. package/dist/commands/pull.js.map +0 -1
  296. package/dist/commands/push.d.ts +0 -3
  297. package/dist/commands/push.d.ts.map +0 -1
  298. package/dist/commands/push.js +0 -180
  299. package/dist/commands/push.js.map +0 -1
  300. package/dist/commands/refresh-memory.d.ts.map +0 -1
  301. package/dist/commands/refresh-memory.js.map +0 -1
  302. package/dist/commands/resource-view.d.ts.map +0 -1
  303. package/dist/commands/resource-view.js.map +0 -1
  304. package/dist/commands/routines.d.ts.map +0 -1
  305. package/dist/commands/routines.js.map +0 -1
  306. package/dist/commands/rules.d.ts.map +0 -1
  307. package/dist/commands/rules.js.map +0 -1
  308. package/dist/commands/sessions-picker.d.ts.map +0 -1
  309. package/dist/commands/sessions-picker.js.map +0 -1
  310. package/dist/commands/sessions.d.ts.map +0 -1
  311. package/dist/commands/sessions.js.map +0 -1
  312. package/dist/commands/skills.d.ts.map +0 -1
  313. package/dist/commands/skills.js.map +0 -1
  314. package/dist/commands/status.d.ts.map +0 -1
  315. package/dist/commands/status.js.map +0 -1
  316. package/dist/commands/subagents.d.ts.map +0 -1
  317. package/dist/commands/subagents.js.map +0 -1
  318. package/dist/commands/sync.d.ts.map +0 -1
  319. package/dist/commands/sync.js.map +0 -1
  320. package/dist/commands/teams-picker.d.ts.map +0 -1
  321. package/dist/commands/teams-picker.js.map +0 -1
  322. package/dist/commands/teams.d.ts.map +0 -1
  323. package/dist/commands/teams.js.map +0 -1
  324. package/dist/commands/utils.d.ts.map +0 -1
  325. package/dist/commands/utils.js.map +0 -1
  326. package/dist/commands/versions.d.ts.map +0 -1
  327. package/dist/commands/versions.js.map +0 -1
  328. package/dist/commands/view.d.ts.map +0 -1
  329. package/dist/commands/view.js.map +0 -1
  330. package/dist/index.d.ts.map +0 -1
  331. package/dist/index.js.map +0 -1
  332. package/dist/lib/__tests__/bugfixes.test.d.ts +0 -2
  333. package/dist/lib/__tests__/bugfixes.test.d.ts.map +0 -1
  334. package/dist/lib/__tests__/bugfixes.test.js +0 -192
  335. package/dist/lib/__tests__/bugfixes.test.js.map +0 -1
  336. package/dist/lib/__tests__/exec.test.d.ts +0 -2
  337. package/dist/lib/__tests__/exec.test.d.ts.map +0 -1
  338. package/dist/lib/__tests__/exec.test.js +0 -446
  339. package/dist/lib/__tests__/exec.test.js.map +0 -1
  340. package/dist/lib/__tests__/git-sync.test.d.ts +0 -2
  341. package/dist/lib/__tests__/git-sync.test.d.ts.map +0 -1
  342. package/dist/lib/__tests__/git-sync.test.js +0 -138
  343. package/dist/lib/__tests__/git-sync.test.js.map +0 -1
  344. package/dist/lib/__tests__/hooks.test.d.ts +0 -2
  345. package/dist/lib/__tests__/hooks.test.d.ts.map +0 -1
  346. package/dist/lib/__tests__/hooks.test.js +0 -203
  347. package/dist/lib/__tests__/hooks.test.js.map +0 -1
  348. package/dist/lib/__tests__/memory-compile.test.d.ts +0 -2
  349. package/dist/lib/__tests__/memory-compile.test.d.ts.map +0 -1
  350. package/dist/lib/__tests__/memory-compile.test.js +0 -95
  351. package/dist/lib/__tests__/memory-compile.test.js.map +0 -1
  352. package/dist/lib/__tests__/models.test.d.ts +0 -2
  353. package/dist/lib/__tests__/models.test.d.ts.map +0 -1
  354. package/dist/lib/__tests__/models.test.js +0 -184
  355. package/dist/lib/__tests__/models.test.js.map +0 -1
  356. package/dist/lib/__tests__/usage.test.d.ts +0 -2
  357. package/dist/lib/__tests__/usage.test.d.ts.map +0 -1
  358. package/dist/lib/__tests__/usage.test.js +0 -218
  359. package/dist/lib/__tests__/usage.test.js.map +0 -1
  360. package/dist/lib/agents.d.ts.map +0 -1
  361. package/dist/lib/agents.js.map +0 -1
  362. package/dist/lib/artifact-actions.d.ts.map +0 -1
  363. package/dist/lib/artifact-actions.js.map +0 -1
  364. package/dist/lib/commands.d.ts.map +0 -1
  365. package/dist/lib/commands.js.map +0 -1
  366. package/dist/lib/convert.d.ts.map +0 -1
  367. package/dist/lib/convert.js.map +0 -1
  368. package/dist/lib/daemon.d.ts.map +0 -1
  369. package/dist/lib/daemon.js.map +0 -1
  370. package/dist/lib/drive-sync.d.ts.map +0 -1
  371. package/dist/lib/drive-sync.js.map +0 -1
  372. package/dist/lib/exec.d.ts.map +0 -1
  373. package/dist/lib/exec.js.map +0 -1
  374. package/dist/lib/factory.d.ts +0 -57
  375. package/dist/lib/factory.d.ts.map +0 -1
  376. package/dist/lib/factory.js +0 -110
  377. package/dist/lib/factory.js.map +0 -1
  378. package/dist/lib/git.d.ts.map +0 -1
  379. package/dist/lib/git.js.map +0 -1
  380. package/dist/lib/help.d.ts.map +0 -1
  381. package/dist/lib/help.js.map +0 -1
  382. package/dist/lib/hooks.d.ts.map +0 -1
  383. package/dist/lib/hooks.js.map +0 -1
  384. package/dist/lib/manifest.d.ts.map +0 -1
  385. package/dist/lib/manifest.js.map +0 -1
  386. package/dist/lib/markdown.d.ts.map +0 -1
  387. package/dist/lib/markdown.js.map +0 -1
  388. package/dist/lib/mcp.d.ts.map +0 -1
  389. package/dist/lib/mcp.js.map +0 -1
  390. package/dist/lib/memory-compile.d.ts.map +0 -1
  391. package/dist/lib/memory-compile.js.map +0 -1
  392. package/dist/lib/memory.d.ts.map +0 -1
  393. package/dist/lib/memory.js.map +0 -1
  394. package/dist/lib/models.d.ts.map +0 -1
  395. package/dist/lib/models.js.map +0 -1
  396. package/dist/lib/permissions.d.ts.map +0 -1
  397. package/dist/lib/permissions.js.map +0 -1
  398. package/dist/lib/picker.d.ts.map +0 -1
  399. package/dist/lib/picker.js.map +0 -1
  400. package/dist/lib/plugins.d.ts.map +0 -1
  401. package/dist/lib/plugins.js.map +0 -1
  402. package/dist/lib/pty-client.d.ts.map +0 -1
  403. package/dist/lib/pty-client.js.map +0 -1
  404. package/dist/lib/pty-server.d.ts.map +0 -1
  405. package/dist/lib/pty-server.js.map +0 -1
  406. package/dist/lib/registry.d.ts.map +0 -1
  407. package/dist/lib/registry.js.map +0 -1
  408. package/dist/lib/resources.d.ts.map +0 -1
  409. package/dist/lib/resources.js.map +0 -1
  410. package/dist/lib/routines.d.ts.map +0 -1
  411. package/dist/lib/routines.js.map +0 -1
  412. package/dist/lib/runner.d.ts.map +0 -1
  413. package/dist/lib/runner.js.map +0 -1
  414. package/dist/lib/sandbox.d.ts.map +0 -1
  415. package/dist/lib/sandbox.js.map +0 -1
  416. package/dist/lib/scheduler.d.ts.map +0 -1
  417. package/dist/lib/scheduler.js.map +0 -1
  418. package/dist/lib/session/__tests__/db.test.d.ts +0 -2
  419. package/dist/lib/session/__tests__/db.test.d.ts.map +0 -1
  420. package/dist/lib/session/__tests__/db.test.js +0 -54
  421. package/dist/lib/session/__tests__/db.test.js.map +0 -1
  422. package/dist/lib/session/__tests__/discover.test.d.ts +0 -2
  423. package/dist/lib/session/__tests__/discover.test.d.ts.map +0 -1
  424. package/dist/lib/session/__tests__/discover.test.js +0 -63
  425. package/dist/lib/session/__tests__/discover.test.js.map +0 -1
  426. package/dist/lib/session/__tests__/prompt.test.d.ts +0 -2
  427. package/dist/lib/session/__tests__/prompt.test.d.ts.map +0 -1
  428. package/dist/lib/session/__tests__/prompt.test.js +0 -44
  429. package/dist/lib/session/__tests__/prompt.test.js.map +0 -1
  430. package/dist/lib/session/__tests__/render.test.d.ts +0 -2
  431. package/dist/lib/session/__tests__/render.test.d.ts.map +0 -1
  432. package/dist/lib/session/__tests__/render.test.js +0 -602
  433. package/dist/lib/session/__tests__/render.test.js.map +0 -1
  434. package/dist/lib/session/db.d.ts.map +0 -1
  435. package/dist/lib/session/db.js.map +0 -1
  436. package/dist/lib/session/discover.d.ts.map +0 -1
  437. package/dist/lib/session/discover.js.map +0 -1
  438. package/dist/lib/session/parse.d.ts.map +0 -1
  439. package/dist/lib/session/parse.js.map +0 -1
  440. package/dist/lib/session/prompt.d.ts.map +0 -1
  441. package/dist/lib/session/prompt.js.map +0 -1
  442. package/dist/lib/session/prompt.test.d.ts +0 -2
  443. package/dist/lib/session/prompt.test.d.ts.map +0 -1
  444. package/dist/lib/session/prompt.test.js +0 -57
  445. package/dist/lib/session/prompt.test.js.map +0 -1
  446. package/dist/lib/session/render.d.ts.map +0 -1
  447. package/dist/lib/session/render.js.map +0 -1
  448. package/dist/lib/session/team-filter.d.ts.map +0 -1
  449. package/dist/lib/session/team-filter.js.map +0 -1
  450. package/dist/lib/session/team-filter.test.d.ts +0 -2
  451. package/dist/lib/session/team-filter.test.d.ts.map +0 -1
  452. package/dist/lib/session/team-filter.test.js +0 -157
  453. package/dist/lib/session/team-filter.test.js.map +0 -1
  454. package/dist/lib/session/types.d.ts.map +0 -1
  455. package/dist/lib/session/types.js.map +0 -1
  456. package/dist/lib/shims.d.ts.map +0 -1
  457. package/dist/lib/shims.js.map +0 -1
  458. package/dist/lib/skills.d.ts.map +0 -1
  459. package/dist/lib/skills.js.map +0 -1
  460. package/dist/lib/state.d.ts.map +0 -1
  461. package/dist/lib/state.js.map +0 -1
  462. package/dist/lib/subagents.d.ts.map +0 -1
  463. package/dist/lib/subagents.js.map +0 -1
  464. package/dist/lib/teams/agents.d.ts.map +0 -1
  465. package/dist/lib/teams/agents.js.map +0 -1
  466. package/dist/lib/teams/api.d.ts.map +0 -1
  467. package/dist/lib/teams/api.js.map +0 -1
  468. package/dist/lib/teams/cloud.d.ts +0 -11
  469. package/dist/lib/teams/cloud.d.ts.map +0 -1
  470. package/dist/lib/teams/cloud.js +0 -169
  471. package/dist/lib/teams/cloud.js.map +0 -1
  472. package/dist/lib/teams/debug.d.ts.map +0 -1
  473. package/dist/lib/teams/debug.js.map +0 -1
  474. package/dist/lib/teams/file_ops.d.ts.map +0 -1
  475. package/dist/lib/teams/file_ops.js.map +0 -1
  476. package/dist/lib/teams/parsers.d.ts.map +0 -1
  477. package/dist/lib/teams/parsers.js.map +0 -1
  478. package/dist/lib/teams/persistence.d.ts.map +0 -1
  479. package/dist/lib/teams/persistence.js.map +0 -1
  480. package/dist/lib/teams/ralph.d.ts +0 -8
  481. package/dist/lib/teams/ralph.d.ts.map +0 -1
  482. package/dist/lib/teams/ralph.js +0 -59
  483. package/dist/lib/teams/ralph.js.map +0 -1
  484. package/dist/lib/teams/registry.d.ts.map +0 -1
  485. package/dist/lib/teams/registry.js.map +0 -1
  486. package/dist/lib/teams/summarizer.d.ts.map +0 -1
  487. package/dist/lib/teams/summarizer.js.map +0 -1
  488. package/dist/lib/template.d.ts.map +0 -1
  489. package/dist/lib/template.js.map +0 -1
  490. package/dist/lib/types.d.ts.map +0 -1
  491. package/dist/lib/types.js.map +0 -1
  492. package/dist/lib/usage.d.ts.map +0 -1
  493. package/dist/lib/usage.js.map +0 -1
  494. package/dist/lib/versions.d.ts.map +0 -1
  495. package/dist/lib/versions.js.map +0 -1
  496. package/scripts/rebuild-sqlite.sh +0 -46
@@ -1,5 +1,15 @@
1
- import { spawn, execSync } from 'child_process';
1
+ /**
2
+ * Teams agent lifecycle management.
3
+ *
4
+ * Defines the AgentProcess and AgentManager classes that handle spawning,
5
+ * monitoring, stopping, and persisting teammate processes across all supported
6
+ * agent CLIs (Claude, Codex, Gemini, Cursor, OpenCode). Supports DAG-based
7
+ * dependency scheduling via --after, per-teammate model/effort overrides, and
8
+ * multiple permission modes (plan, edit, full).
9
+ */
10
+ import { spawn, execSync, execFileSync } from 'child_process';
2
11
  import * as fs from 'fs/promises';
12
+ import * as fsSync from 'fs';
3
13
  import * as path from 'path';
4
14
  import * as os from 'os';
5
15
  import { randomUUID } from 'crypto';
@@ -7,6 +17,53 @@ import { resolveAgentsDir } from './persistence.js';
7
17
  import { normalizeEvents } from './parsers.js';
8
18
  import { debug } from './debug.js';
9
19
  import { buildReasoningFlags } from '../models.js';
20
+ import { setGeminiAutoUpdateDisabled, updateGeminiSettings } from '../gemini-settings.js';
21
+ import { getAgentsDir as getSystemAgentsDir } from '../state.js';
22
+ let lastMemoryWarnAt = 0;
23
+ // On macOS, os.freemem() returns only the truly-free pool and ignores the
24
+ // large inactive+purgeable cache the kernel will reclaim under pressure, so
25
+ // it always looks alarmingly low on a healthy Mac. Parse vm_stat to get the
26
+ // real "available" figure: free + inactive + purgeable + speculative.
27
+ function availableMemoryBytes() {
28
+ if (process.platform !== 'darwin')
29
+ return os.freemem();
30
+ try {
31
+ const out = execSync('vm_stat', { encoding: 'utf8', timeout: 1000 });
32
+ const pageSizeMatch = out.match(/page size of (\d+) bytes/);
33
+ const pageSize = pageSizeMatch ? Number(pageSizeMatch[1]) : 4096;
34
+ const grab = (label) => {
35
+ const m = out.match(new RegExp(`${label}:\\s+(\\d+)\\.`));
36
+ return m ? Number(m[1]) : 0;
37
+ };
38
+ const pages = grab('Pages free') +
39
+ grab('Pages inactive') +
40
+ grab('Pages purgeable') +
41
+ grab('Pages speculative');
42
+ if (pages <= 0)
43
+ return os.freemem();
44
+ return pages * pageSize;
45
+ }
46
+ catch {
47
+ return os.freemem();
48
+ }
49
+ }
50
+ function warnIfMemoryLow(runningCount) {
51
+ const total = os.totalmem();
52
+ if (total <= 0)
53
+ return;
54
+ const available = availableMemoryBytes();
55
+ const freeRatio = available / total;
56
+ if (freeRatio >= 0.15)
57
+ return;
58
+ const now = Date.now();
59
+ if (now - lastMemoryWarnAt < 60_000)
60
+ return;
61
+ lastMemoryWarnAt = now;
62
+ const freeGb = (available / 1024 ** 3).toFixed(1);
63
+ const totalGb = (total / 1024 ** 3).toFixed(1);
64
+ process.stderr.write(`Heads up: only ${freeGb}GB of ${totalGb}GB free with ${runningCount} teammates already running. ` +
65
+ `Spawning more may slow your machine.\n`);
66
+ }
10
67
  /**
11
68
  * Compute the Lowest Common Ancestor (LCA) of multiple file paths.
12
69
  * Returns the deepest common directory shared by all paths.
@@ -44,6 +101,7 @@ export function computePathLCA(paths) {
44
101
  const lca = path.sep + commonSegments.join(path.sep);
45
102
  return lca;
46
103
  }
104
+ /** Lifecycle status of a teammate process. */
47
105
  export var AgentStatus;
48
106
  (function (AgentStatus) {
49
107
  AgentStatus["PENDING"] = "pending";
@@ -52,6 +110,9 @@ export var AgentStatus;
52
110
  AgentStatus["FAILED"] = "failed";
53
111
  AgentStatus["STOPPED"] = "stopped";
54
112
  })(AgentStatus || (AgentStatus = {}));
113
+ export const VALID_TASK_TYPES = [
114
+ 'plan', 'implement', 'test', 'review', 'bugfix', 'docs',
115
+ ];
55
116
  /**
56
117
  * Walk the `after` chain from `startName` within the given map; returns true
57
118
  * if `targetName` appears anywhere in the transitive dependency closure.
@@ -72,14 +133,129 @@ function hasTransitiveDep(byName, startName, targetName, seen = new Set()) {
72
133
  }
73
134
  return false;
74
135
  }
75
- // Base commands for plan mode (read-only, may prompt for confirmation)
136
+ /**
137
+ * Capture a stable identifier for a process at the moment it was started.
138
+ * Used to defeat PID reuse: a kill(pid, ...) is only safe when the process
139
+ * still occupies the PID we observed at spawn time. A bare kill(pid, 0)
140
+ * probe cannot tell whether the OS has recycled the slot to an unrelated
141
+ * process — combined with detached spawns and unref(), that's exactly how
142
+ * `agents teams stop` ends up SIGKILLing random process groups.
143
+ *
144
+ * Linux: field 22 of /proc/<pid>/stat (starttime in clock ticks since boot).
145
+ * macOS: output of `ps -o lstart= -p <pid>` (start time in human format).
146
+ * Returns null on any error so callers can skip the guard rather than crash.
147
+ */
148
+ export function captureProcessStartTime(pid) {
149
+ if (!pid || pid <= 0)
150
+ return null;
151
+ try {
152
+ if (process.platform === 'linux') {
153
+ const stat = fsSync.readFileSync(`/proc/${pid}/stat`, 'utf-8');
154
+ const lastParen = stat.lastIndexOf(')');
155
+ if (lastParen < 0)
156
+ return null;
157
+ const tail = stat.slice(lastParen + 2);
158
+ const fields = tail.split(' ');
159
+ // After comm we are at field 3; starttime is field 22, so index 19 here.
160
+ return fields[19] || null;
161
+ }
162
+ const out = execFileSync('ps', ['-o', 'lstart=', '-p', String(pid)], {
163
+ encoding: 'utf-8',
164
+ stdio: ['ignore', 'pipe', 'ignore'],
165
+ });
166
+ const trimmed = out.trim();
167
+ return trimmed.length > 0 ? trimmed : null;
168
+ }
169
+ catch {
170
+ return null;
171
+ }
172
+ }
173
+ // Base commands for plan mode (read-only). applyEditMode / applyFullMode
174
+ // rewrite these for write-capable modes. Each agent's read-only flag MUST be
175
+ // here so a plan-mode teammate truly cannot write — even if the teammate
176
+ // prompt tries to ignore the instruction. See agents.test.ts for the contract.
76
177
  export const AGENT_COMMANDS = {
77
- codex: ['codex', 'exec', '--sandbox', 'workspace-write', '{prompt}', '--json'],
178
+ codex: ['codex', 'exec', '--sandbox', 'read-only', '{prompt}', '--json'],
78
179
  cursor: ['cursor-agent', '-p', '--output-format', 'stream-json', '{prompt}'],
79
180
  gemini: ['gemini', '{prompt}', '--output-format', 'stream-json', '--approval-mode', 'plan'],
80
181
  claude: ['claude', '-p', '--verbose', '{prompt}', '--output-format', 'stream-json', '--permission-mode', 'plan'],
81
182
  opencode: ['opencode', 'run', '--format', 'json', '{prompt}'],
82
183
  };
184
+ /**
185
+ * Rewrite a plan-mode command into edit mode (writes inside cwd allowed,
186
+ * approval prompts may still appear). Pure function — exported for tests.
187
+ */
188
+ export function applyEditMode(agentType, cmd) {
189
+ const editCmd = [...cmd];
190
+ switch (agentType) {
191
+ case 'codex': {
192
+ // Swap --sandbox read-only -> --sandbox workspace-write so the codex
193
+ // sandbox actually permits writes. --full-auto then disables approvals.
194
+ const sandboxIndex = editCmd.indexOf('--sandbox');
195
+ if (sandboxIndex !== -1 && sandboxIndex + 1 < editCmd.length) {
196
+ editCmd[sandboxIndex + 1] = 'workspace-write';
197
+ }
198
+ editCmd.push('--full-auto');
199
+ break;
200
+ }
201
+ case 'cursor':
202
+ editCmd.push('-f');
203
+ break;
204
+ case 'gemini': {
205
+ const approvalIndex = editCmd.indexOf('--approval-mode');
206
+ if (approvalIndex !== -1) {
207
+ editCmd.splice(approvalIndex, 2);
208
+ }
209
+ editCmd.push('--yolo');
210
+ break;
211
+ }
212
+ case 'claude': {
213
+ const permModeIndex = editCmd.indexOf('--permission-mode');
214
+ if (permModeIndex !== -1 && permModeIndex + 1 < editCmd.length) {
215
+ editCmd[permModeIndex + 1] = 'acceptEdits';
216
+ }
217
+ break;
218
+ }
219
+ }
220
+ return editCmd;
221
+ }
222
+ /**
223
+ * Rewrite a plan-mode command into full mode (writes + approval gates
224
+ * bypassed). Pure function — exported for tests.
225
+ */
226
+ export function applyFullMode(agentType, cmd) {
227
+ const fullCmd = [...cmd];
228
+ switch (agentType) {
229
+ case 'codex': {
230
+ const sandboxIndex = fullCmd.indexOf('--sandbox');
231
+ if (sandboxIndex !== -1 && sandboxIndex + 1 < fullCmd.length) {
232
+ fullCmd[sandboxIndex + 1] = 'workspace-write';
233
+ }
234
+ fullCmd.push('--full-auto');
235
+ break;
236
+ }
237
+ case 'cursor':
238
+ fullCmd.push('-f');
239
+ break;
240
+ case 'gemini': {
241
+ const approvalIndex = fullCmd.indexOf('--approval-mode');
242
+ if (approvalIndex !== -1) {
243
+ fullCmd.splice(approvalIndex, 2);
244
+ }
245
+ fullCmd.push('--yolo');
246
+ break;
247
+ }
248
+ case 'claude': {
249
+ const permModeIndex = fullCmd.indexOf('--permission-mode');
250
+ if (permModeIndex !== -1) {
251
+ fullCmd.splice(permModeIndex, 2);
252
+ }
253
+ fullCmd.push('--dangerously-skip-permissions');
254
+ break;
255
+ }
256
+ }
257
+ return fullCmd;
258
+ }
83
259
  // Minimal defaults — no per-effort model map. Configs on disk may still have
84
260
  // a model pinned; launchProcess picks it up from agent.model when set.
85
261
  function loadDefaultAgentConfigs() {
@@ -168,6 +344,7 @@ function extractTimestamp(raw) {
168
344
  }
169
345
  return null;
170
346
  }
347
+ /** Resolve a mode string to a validated Mode, falling back to the given default. */
171
348
  export function resolveMode(requestedMode, defaultMode = 'plan') {
172
349
  const normalizedDefault = normalizeModeValue(defaultMode);
173
350
  if (!normalizedDefault) {
@@ -182,28 +359,31 @@ export function resolveMode(requestedMode, defaultMode = 'plan') {
182
359
  }
183
360
  return normalizedDefault;
184
361
  }
362
+ /** Ensure Gemini's settings.json has experimental.plan enabled for headless plan mode. */
185
363
  export async function ensureGeminiPlanMode() {
186
364
  const settingsPath = path.join(os.homedir(), '.gemini', 'settings.json');
187
365
  try {
188
- let settings = {};
189
- try {
190
- const raw = await fs.readFile(settingsPath, 'utf-8');
191
- settings = JSON.parse(raw);
192
- }
193
- catch {
194
- // No settings file or invalid JSON
366
+ let changed = false;
367
+ const settings = updateGeminiSettings(settingsPath, (nextSettings) => {
368
+ setGeminiAutoUpdateDisabled(nextSettings);
369
+ const experimental = typeof nextSettings.experimental === 'object' && nextSettings.experimental !== null
370
+ ? nextSettings.experimental
371
+ : {};
372
+ if (experimental.plan === true) {
373
+ return;
374
+ }
375
+ nextSettings.experimental = { ...experimental, plan: true };
376
+ changed = true;
377
+ });
378
+ if (changed && settings.experimental && typeof settings.experimental === 'object' && settings.experimental.plan === true) {
379
+ console.error('[Swarm] Enabled Gemini experimental.plan in', settingsPath);
195
380
  }
196
- if (settings.experimental?.plan === true)
197
- return;
198
- settings.experimental = { ...settings.experimental, plan: true };
199
- await fs.mkdir(path.dirname(settingsPath), { recursive: true });
200
- await fs.writeFile(settingsPath, JSON.stringify(settings, null, 2) + '\n');
201
- console.error('[Swarm] Enabled Gemini experimental.plan in', settingsPath);
202
381
  }
203
382
  catch (err) {
204
383
  console.warn('[Swarm] Could not enable Gemini plan mode:', err);
205
384
  }
206
385
  }
386
+ /** Check whether the CLI binary for a given agent type exists in PATH. Returns [available, pathOrError]. */
207
387
  export function checkCliAvailable(agentType) {
208
388
  const cmdTemplate = AGENT_COMMANDS[agentType];
209
389
  if (!cmdTemplate) {
@@ -218,6 +398,7 @@ export function checkCliAvailable(agentType) {
218
398
  return [false, `CLI tool '${executable}' not found in PATH. Install it first.`];
219
399
  }
220
400
  }
401
+ /** Check availability of all known agent CLIs. Returns a map of agent type to install status. */
221
402
  export function checkAllClis() {
222
403
  const results = {};
223
404
  for (const agentType of Object.keys(AGENT_COMMANDS)) {
@@ -232,12 +413,20 @@ export function checkAllClis() {
232
413
  return results;
233
414
  }
234
415
  let AGENTS_DIR = null;
416
+ /** Resolve and cache the base directory where teammate process data is stored. */
235
417
  export async function getAgentsDir() {
236
418
  if (!AGENTS_DIR) {
237
419
  AGENTS_DIR = await resolveAgentsDir();
238
420
  }
239
421
  return AGENTS_DIR;
240
422
  }
423
+ /**
424
+ * Represents a single teammate process within a team.
425
+ *
426
+ * Tracks process metadata (PID, status, timestamps), reads incremental
427
+ * stdout events, persists state to disk as meta.json, and can be
428
+ * reconstituted from disk via loadFromDisk().
429
+ */
241
430
  export class AgentProcess {
242
431
  agentId;
243
432
  taskName;
@@ -247,6 +436,9 @@ export class AgentProcess {
247
436
  workspaceDir;
248
437
  mode = 'plan';
249
438
  pid = null;
439
+ // Captured at spawn time so we can detect PID reuse before signaling.
440
+ // Compared against the live /proc or `ps` value at every kill() call.
441
+ startTime = null;
250
442
  status = AgentStatus.RUNNING;
251
443
  startedAt = new Date();
252
444
  completedAt = null;
@@ -269,10 +461,17 @@ export class AgentProcess {
269
461
  model = null;
270
462
  // Extra env vars passed through to the child process (from --env KEY=VALUE).
271
463
  envOverrides = null;
464
+ // Factory task-type label. Drives planner fan-out. Null for plain teammates — no behavioral change.
465
+ taskType = null;
466
+ // Repo/branch for cloud dispatches that stage behind --after. Captured
467
+ // at spawn time so startReady() can invoke the dispatcher with the same
468
+ // options the user originally supplied.
469
+ cloudRepo = null;
470
+ cloudBranch = null;
272
471
  eventsCache = [];
273
472
  lastReadPos = 0;
274
473
  baseDir = null;
275
- constructor(agentId, taskName, agentType, prompt, cwd = null, mode = 'plan', pid = null, status = AgentStatus.RUNNING, startedAt = new Date(), completedAt = null, baseDir = null, parentSessionId = null, workspaceDir = null, cloudSessionId = null, cloudProvider = null, prUrl = null, version = null, remoteSessionId = null, name = null, after = [], effort = null, model = null, envOverrides = null) {
474
+ constructor(agentId, taskName, agentType, prompt, cwd = null, mode = 'plan', pid = null, status = AgentStatus.RUNNING, startedAt = new Date(), completedAt = null, baseDir = null, parentSessionId = null, workspaceDir = null, cloudSessionId = null, cloudProvider = null, prUrl = null, version = null, remoteSessionId = null, name = null, after = [], effort = null, model = null, envOverrides = null, taskType = null, cloudRepo = null, cloudBranch = null) {
276
475
  this.agentId = agentId;
277
476
  this.remoteSessionId = remoteSessionId;
278
477
  this.name = name;
@@ -280,6 +479,9 @@ export class AgentProcess {
280
479
  this.effort = effort;
281
480
  this.model = model;
282
481
  this.envOverrides = envOverrides;
482
+ this.taskType = taskType;
483
+ this.cloudRepo = cloudRepo;
484
+ this.cloudBranch = cloudBranch;
283
485
  this.taskName = taskName;
284
486
  this.agentType = agentType;
285
487
  this.prompt = prompt;
@@ -304,6 +506,29 @@ export class AgentProcess {
304
506
  const base = this.baseDir || await getAgentsDir();
305
507
  return path.join(base, this.agentId);
306
508
  }
509
+ /**
510
+ * Dump the subset of state the Ledger sync hook needs. Keeps sync.ts
511
+ * free of any teams-internal imports.
512
+ */
513
+ async toSnapshot() {
514
+ return {
515
+ agent_id: this.agentId,
516
+ team_id: this.taskName,
517
+ teammate_name: this.name,
518
+ agent_type: this.agentType,
519
+ task_type: this.taskType,
520
+ status: this.status,
521
+ started_at: this.startedAt.toISOString(),
522
+ completed_at: this.completedAt?.toISOString() ?? null,
523
+ after: this.after,
524
+ cloud_provider: this.cloudProvider,
525
+ cloud_session_id: this.cloudSessionId,
526
+ cloud_repo: this.cloudRepo,
527
+ cloud_branch: this.cloudBranch,
528
+ agent_dir: await this.getAgentDir(),
529
+ cwd: this.cwd,
530
+ };
531
+ }
307
532
  async getStdoutPath() {
308
533
  return path.join(await this.getAgentDir(), 'stdout.log');
309
534
  }
@@ -333,6 +558,9 @@ export class AgentProcess {
333
558
  effort: this.effort,
334
559
  model: this.model,
335
560
  env_overrides: this.envOverrides,
561
+ task_type: this.taskType,
562
+ cloud_repo: this.cloudRepo,
563
+ cloud_branch: this.cloudBranch,
336
564
  };
337
565
  }
338
566
  duration() {
@@ -445,6 +673,7 @@ export class AgentProcess {
445
673
  workspace_dir: this.workspaceDir,
446
674
  mode: this.mode,
447
675
  pid: this.pid,
676
+ start_time: this.startTime,
448
677
  status: this.status,
449
678
  started_at: this.startedAt.toISOString(),
450
679
  completed_at: this.completedAt?.toISOString() || null,
@@ -459,6 +688,9 @@ export class AgentProcess {
459
688
  effort: this.effort,
460
689
  model: this.model,
461
690
  env_overrides: this.envOverrides,
691
+ task_type: this.taskType,
692
+ cloud_repo: this.cloudRepo,
693
+ cloud_branch: this.cloudBranch,
462
694
  };
463
695
  const metaPath = await this.getMetaPath();
464
696
  await fs.writeFile(metaPath, JSON.stringify(meta, null, 2));
@@ -492,7 +724,10 @@ export class AgentProcess {
492
724
  const resolvedStatus = validStatuses.includes(meta.status)
493
725
  ? meta.status
494
726
  : AgentStatus.RUNNING;
495
- const agent = new AgentProcess(meta.agent_id, meta.task_name || 'default', meta.agent_type, meta.prompt, meta.cwd || null, resolvedMode, meta.pid || null, resolvedStatus, new Date(meta.started_at), meta.completed_at ? new Date(meta.completed_at) : null, baseDir, meta.parent_session_id || null, meta.workspace_dir || null, meta.cloud_session_id || null, meta.cloud_provider || null, meta.pr_url || null, meta.version || null, meta.remote_session_id || null, meta.name || null, Array.isArray(meta.after) ? meta.after : [], meta.effort || null, meta.model || null, meta.env_overrides || null);
727
+ const agent = new AgentProcess(meta.agent_id, meta.task_name || 'default', meta.agent_type, meta.prompt, meta.cwd || null, resolvedMode, meta.pid || null, resolvedStatus, new Date(meta.started_at), meta.completed_at ? new Date(meta.completed_at) : null, baseDir, meta.parent_session_id || null, meta.workspace_dir || null, meta.cloud_session_id || null, meta.cloud_provider || null, meta.pr_url || null, meta.version || null, meta.remote_session_id || null, meta.name || null, Array.isArray(meta.after) ? meta.after : [], meta.effort || null, meta.model || null, meta.env_overrides || null, meta.task_type && VALID_TASK_TYPES.includes(meta.task_type)
728
+ ? meta.task_type
729
+ : null, meta.cloud_repo || null, meta.cloud_branch || null);
730
+ agent.startTime = typeof meta.start_time === 'string' ? meta.start_time : null;
496
731
  return agent;
497
732
  }
498
733
  catch {
@@ -504,15 +739,61 @@ export class AgentProcess {
504
739
  return false;
505
740
  try {
506
741
  process.kill(this.pid, 0);
507
- return true;
508
742
  }
509
743
  catch {
510
744
  return false;
511
745
  }
746
+ // PID is occupied — but is it still OUR process? If we captured a
747
+ // start-time at spawn, refuse to claim aliveness when the live value
748
+ // differs. A null startTime means we never captured one (legacy
749
+ // teammates loaded from disk before this field existed) — fall back to
750
+ // the bare kill(pid, 0) result for those.
751
+ if (this.startTime !== null) {
752
+ const current = captureProcessStartTime(this.pid);
753
+ if (current === null || current !== this.startTime) {
754
+ return false;
755
+ }
756
+ }
757
+ return true;
512
758
  }
513
759
  async updateStatusFromProcess() {
514
- if (!this.pid)
760
+ if (!this.pid) {
761
+ await this.readNewEvents();
762
+ // Cloud-backed teammates have no local PID by design; their lifecycle
763
+ // is driven by the remote provider instead of a local process.
764
+ if (this.cloudProvider) {
765
+ if (!this.completedAt && this.status !== AgentStatus.RUNNING) {
766
+ const fallbackCompletion = this.getLatestEventTime() || this.startedAt || new Date();
767
+ this.completedAt = fallbackCompletion;
768
+ await this.saveMeta();
769
+ }
770
+ return;
771
+ }
772
+ // Pending teammates with unresolved --after deps also have no PID yet.
773
+ // Leave them alone until startReady() launches them.
774
+ if (this.status === AgentStatus.PENDING) {
775
+ return;
776
+ }
777
+ // A local teammate marked RUNNING without a PID is an impossible state:
778
+ // launch never produced a durable process identity, so it cannot still
779
+ // be doing work. Keep any terminal event parsed from stdout; otherwise
780
+ // fail it and stamp completion so team rollups stop showing it as live.
781
+ if (this.status === AgentStatus.RUNNING) {
782
+ const fallbackCompletion = this.getLatestEventTime() || this.startedAt || new Date();
783
+ if (this.status === AgentStatus.RUNNING) {
784
+ this.status = AgentStatus.FAILED;
785
+ this.completedAt = fallbackCompletion;
786
+ }
787
+ await this.saveMeta();
788
+ return;
789
+ }
790
+ if (!this.completedAt) {
791
+ const fallbackCompletion = this.getLatestEventTime() || this.startedAt || new Date();
792
+ this.completedAt = fallbackCompletion;
793
+ await this.saveMeta();
794
+ }
515
795
  return;
796
+ }
516
797
  if (this.isProcessAlive()) {
517
798
  await this.readNewEvents();
518
799
  return;
@@ -553,7 +834,6 @@ export class AgentProcess {
553
834
  export class AgentManager {
554
835
  agents = new Map();
555
836
  maxAgents;
556
- maxConcurrent;
557
837
  agentsDir = '';
558
838
  filterByCwd;
559
839
  cleanupAgeDays;
@@ -561,10 +841,10 @@ export class AgentManager {
561
841
  agentConfigs;
562
842
  constructorAgentConfigs = null;
563
843
  initPromise = null;
844
+ cloudDispatcher = null;
564
845
  constructorAgentsDir = null;
565
- constructor(maxAgents = 50, maxConcurrent = 10, agentsDir = null, defaultMode = null, filterByCwd = null, cleanupAgeDays = 7, agentConfigs = null) {
846
+ constructor(maxAgents = 50, agentsDir = null, defaultMode = null, filterByCwd = null, cleanupAgeDays = 7, agentConfigs = null) {
566
847
  this.maxAgents = maxAgents;
567
- this.maxConcurrent = maxConcurrent;
568
848
  this.constructorAgentsDir = agentsDir;
569
849
  this.filterByCwd = filterByCwd;
570
850
  this.cleanupAgeDays = cleanupAgeDays;
@@ -594,9 +874,53 @@ export class AgentManager {
594
874
  setModelOverrides(agentConfigs) {
595
875
  this.agentConfigs = agentConfigs;
596
876
  }
877
+ /**
878
+ * Register the callback used to dispatch cloud-backed teammates when their
879
+ * --after deps resolve. Called once at CLI startup by `agents teams`.
880
+ */
881
+ setCloudDispatcher(fn) {
882
+ this.cloudDispatcher = fn;
883
+ }
597
884
  registerAgent(agent) {
598
885
  this.agents.set(agent.agentId, agent);
599
886
  }
887
+ /**
888
+ * Scan the agents dir for meta.json files not already in the in-memory
889
+ * cache and load them. Needed when another process (e.g. a Planner
890
+ * teammate running `agents teams add`) creates new teammates while this
891
+ * manager is alive — the supervisor loop calls this each wave so
892
+ * dynamically-added teammates get picked up.
893
+ *
894
+ * Does not modify or re-load agents already in the cache; that path is
895
+ * covered by updateStatusFromProcess() which re-reads stdout.log.
896
+ */
897
+ async rescanFromDisk() {
898
+ await this.initialize();
899
+ try {
900
+ await fs.access(this.agentsDir);
901
+ }
902
+ catch {
903
+ return 0;
904
+ }
905
+ const entries = await fs.readdir(this.agentsDir);
906
+ let added = 0;
907
+ for (const entry of entries) {
908
+ if (this.agents.has(entry))
909
+ continue;
910
+ const agentDir = path.join(this.agentsDir, entry);
911
+ const stat = await fs.stat(agentDir).catch(() => null);
912
+ if (!stat || !stat.isDirectory())
913
+ continue;
914
+ const agent = await AgentProcess.loadFromDisk(entry, this.agentsDir);
915
+ if (!agent)
916
+ continue;
917
+ if (this.filterByCwd !== null && agent.cwd !== this.filterByCwd)
918
+ continue;
919
+ this.agents.set(entry, agent);
920
+ added++;
921
+ }
922
+ return added;
923
+ }
600
924
  async loadExistingAgents() {
601
925
  try {
602
926
  await fs.access(this.agentsDir);
@@ -647,7 +971,7 @@ export class AgentManager {
647
971
  }
648
972
  debug(`Loaded ${loadedCount} agents from disk`);
649
973
  }
650
- async spawn(taskName, agentType, prompt, cwd = null, mode = null, effort = 'medium', parentSessionId = null, workspaceDir = null, version = null, name = null, after = [], model = null, envOverrides = null) {
974
+ async spawn(taskName, agentType, prompt, cwd = null, mode = null, effort = 'medium', parentSessionId = null, workspaceDir = null, version = null, name = null, after = [], model = null, envOverrides = null, taskType = null, cloudProvider = null, cloudSessionId = null, cloudRepo = null, cloudBranch = null) {
651
975
  await this.initialize();
652
976
  const resolvedMode = resolveMode(mode, this.defaultMode);
653
977
  // Enforce: teammate names are unique within a team.
@@ -689,15 +1013,24 @@ export class AgentManager {
689
1013
  throw new Error(`Working directory is not a directory: ${cwd}`);
690
1014
  }
691
1015
  }
692
- const [available, pathOrError] = checkCliAvailable(agentType);
693
- if (!available) {
694
- throw new Error(pathOrError || 'CLI tool not available');
1016
+ // Cloud-backed teammates run on remote infrastructure; we don't need the
1017
+ // local CLI for them (the pod has its own). The caller has already
1018
+ // dispatched via the cloud provider and passed us the provider + session.
1019
+ const isCloudBacked = Boolean(cloudProvider);
1020
+ if (!isCloudBacked) {
1021
+ const [available, pathOrError] = checkCliAvailable(agentType);
1022
+ if (!available) {
1023
+ throw new Error(pathOrError || 'CLI tool not available');
1024
+ }
695
1025
  }
696
1026
  // Use a full UUIDv4 as the canonical agent_id. For Claude, we pass it via
697
1027
  // --session-id so it's also Claude's session id (unified identity).
698
1028
  const agentId = randomUUID();
699
1029
  const isStaged = cleanAfter.length > 0;
700
- const agent = new AgentProcess(agentId, taskName, agentType, prompt, resolvedCwd, resolvedMode, null, isStaged ? AgentStatus.PENDING : AgentStatus.RUNNING, new Date(), null, this.agentsDir, parentSessionId, workspaceDir, null, null, null, version, null, name, cleanAfter, effort, model, envOverrides && Object.keys(envOverrides).length > 0 ? envOverrides : null);
1030
+ const initialStatus = isStaged || !isCloudBacked
1031
+ ? AgentStatus.PENDING
1032
+ : AgentStatus.RUNNING;
1033
+ const agent = new AgentProcess(agentId, taskName, agentType, prompt, resolvedCwd, resolvedMode, null, initialStatus, new Date(), null, this.agentsDir, parentSessionId, workspaceDir, cloudSessionId, cloudProvider, null, version, null, name, cleanAfter, effort, model, envOverrides && Object.keys(envOverrides).length > 0 ? envOverrides : null, taskType, cloudRepo, cloudBranch);
701
1034
  const agentDir = await agent.getAgentDir();
702
1035
  try {
703
1036
  await fs.mkdir(agentDir, { recursive: true });
@@ -705,13 +1038,19 @@ export class AgentManager {
705
1038
  catch (err) {
706
1039
  throw new Error(`Failed to create agent directory: ${err.message}`);
707
1040
  }
708
- await agent.saveMeta();
709
1041
  this.agents.set(agentId, agent);
710
- if (!isStaged) {
711
- await this.launchProcess(agent);
1042
+ if (isStaged) {
1043
+ await agent.saveMeta();
1044
+ debug(`Staged ${agentType} teammate '${name}' in team '${taskName}' (after: ${cleanAfter.join(', ')})`);
1045
+ }
1046
+ else if (isCloudBacked) {
1047
+ // Cloud-backed teammate: the provider already dispatched a remote task.
1048
+ // No local process to launch; status polling walks the provider instead.
1049
+ await agent.saveMeta();
1050
+ debug(`Cloud-backed ${agentType} teammate via ${cloudProvider} (session=${cloudSessionId})`);
712
1051
  }
713
1052
  else {
714
- debug(`Staged ${agentType} teammate '${name}' in team '${taskName}' (after: ${cleanAfter.join(', ')})`);
1053
+ await this.launchProcess(agent);
715
1054
  }
716
1055
  await this.cleanupOldAgents();
717
1056
  return agent;
@@ -722,9 +1061,7 @@ export class AgentManager {
722
1061
  */
723
1062
  async launchProcess(agent) {
724
1063
  const running = await this.listRunning();
725
- if (running.length >= this.maxConcurrent) {
726
- throw new Error(`Maximum concurrent agents (${this.maxConcurrent}) reached. Wait for an agent to complete or stop one first.`);
727
- }
1064
+ warnIfMemoryLow(running.length);
728
1065
  const effort = agent.effort ?? 'medium';
729
1066
  // Falls back to the pinned model in agentConfigs; null means "let the
730
1067
  // CLI pick its own default" (no --model flag forwarded). Effort is a
@@ -750,6 +1087,11 @@ export class AgentManager {
750
1087
  childProcess.unref();
751
1088
  stdoutFile.close().catch(() => { });
752
1089
  agent.pid = childProcess.pid || null;
1090
+ // Capture start-time NOW, while we know the PID is ours. Once the
1091
+ // OS reuses this PID slot, /proc and `ps` will report a different
1092
+ // value — that's the signal stop() uses to refuse to signal an
1093
+ // unrelated process.
1094
+ agent.startTime = agent.pid ? captureProcessStartTime(agent.pid) : null;
753
1095
  agent.status = AgentStatus.RUNNING;
754
1096
  agent.startedAt = new Date();
755
1097
  await agent.saveMeta();
@@ -782,8 +1124,22 @@ export class AgentManager {
782
1124
  if (!depsReady)
783
1125
  continue;
784
1126
  try {
785
- await this.launchProcess(agent);
786
- launched.push(agent);
1127
+ if (agent.cloudProvider) {
1128
+ if (!this.cloudDispatcher) {
1129
+ console.error(`Cannot start cloud-backed teammate ${agent.agentId}: no dispatcher registered.`);
1130
+ continue;
1131
+ }
1132
+ const { cloudSessionId } = await this.cloudDispatcher(agent);
1133
+ agent.cloudSessionId = cloudSessionId;
1134
+ agent.status = AgentStatus.RUNNING;
1135
+ agent.startedAt = new Date();
1136
+ await agent.saveMeta();
1137
+ launched.push(agent);
1138
+ }
1139
+ else {
1140
+ await this.launchProcess(agent);
1141
+ launched.push(agent);
1142
+ }
787
1143
  }
788
1144
  catch (err) {
789
1145
  console.error(`Could not launch ${agent.agentId}:`, err);
@@ -821,6 +1177,14 @@ export class AgentManager {
821
1177
  // ~/.claude/settings.json would override that and bind settings to the
822
1178
  // *default* version rather than the one this teammate is running.
823
1179
  }
1180
+ if (agentType === 'codex') {
1181
+ // Codex's workspace-write sandbox blocks writes outside cwd. Factory
1182
+ // teammates need to run further `agents teams add` commands,
1183
+ // which write to ~/.agents/. Grant that root so subprocess-issued
1184
+ // `agents teams add` calls hit the real store instead of the tmp
1185
+ // fallback (which the supervisor does not watch).
1186
+ cmd.push('--add-dir', getSystemAgentsDir());
1187
+ }
824
1188
  // Add model flag for each agent type only when the teammate has a pinned
825
1189
  // model. When null, the agent's CLI picks its own default.
826
1190
  if (model) {
@@ -870,61 +1234,10 @@ export class AgentManager {
870
1234
  return cmd;
871
1235
  }
872
1236
  applyEditMode(agentType, cmd) {
873
- const editCmd = [...cmd];
874
- switch (agentType) {
875
- case 'codex':
876
- editCmd.push('--full-auto');
877
- break;
878
- case 'cursor':
879
- editCmd.push('-f');
880
- break;
881
- case 'gemini': {
882
- const approvalIndex = editCmd.indexOf('--approval-mode');
883
- if (approvalIndex !== -1) {
884
- editCmd.splice(approvalIndex, 2);
885
- }
886
- editCmd.push('--yolo');
887
- break;
888
- }
889
- case 'claude':
890
- const permModeIndex = editCmd.indexOf('--permission-mode');
891
- if (permModeIndex !== -1 && permModeIndex + 1 < editCmd.length) {
892
- editCmd[permModeIndex + 1] = 'acceptEdits';
893
- }
894
- break;
895
- }
896
- return editCmd;
1237
+ return applyEditMode(agentType, cmd);
897
1238
  }
898
- // "full" mode: edit-level write access with permission gates bypassed.
899
- // For Claude that's --dangerously-skip-permissions; other agents already
900
- // lack gates in edit mode so their commands match applyEditMode.
901
1239
  applyFullMode(agentType, cmd) {
902
- const fullCmd = [...cmd];
903
- switch (agentType) {
904
- case 'codex':
905
- fullCmd.push('--full-auto');
906
- break;
907
- case 'cursor':
908
- fullCmd.push('-f');
909
- break;
910
- case 'gemini': {
911
- const approvalIndex = fullCmd.indexOf('--approval-mode');
912
- if (approvalIndex !== -1) {
913
- fullCmd.splice(approvalIndex, 2);
914
- }
915
- fullCmd.push('--yolo');
916
- break;
917
- }
918
- case 'claude':
919
- // Replace --permission-mode plan with --dangerously-skip-permissions
920
- const permModeIndex = fullCmd.indexOf('--permission-mode');
921
- if (permModeIndex !== -1) {
922
- fullCmd.splice(permModeIndex, 2); // Remove --permission-mode and its value
923
- }
924
- fullCmd.push('--dangerously-skip-permissions');
925
- break;
926
- }
927
- return fullCmd;
1240
+ return applyFullMode(agentType, cmd);
928
1241
  }
929
1242
  async get(agentId) {
930
1243
  await this.initialize();
@@ -1019,6 +1332,17 @@ export class AgentManager {
1019
1332
  return false;
1020
1333
  }
1021
1334
  if (agent.pid && agent.status === AgentStatus.RUNNING) {
1335
+ // PID-reuse guard: if the PID we recorded at spawn no longer maps to
1336
+ // our process (start-time mismatch), the OS has recycled it. Sending
1337
+ // SIGTERM/SIGKILL to -pid here would kill an unrelated process group.
1338
+ // Treat as already gone and just record the stop without signaling.
1339
+ if (!agent.isProcessAlive()) {
1340
+ debug(`Agent ${agentId} PID ${agent.pid} no longer ours (start-time mismatch or exited); skipping signal`);
1341
+ agent.status = AgentStatus.STOPPED;
1342
+ agent.completedAt = new Date();
1343
+ await agent.saveMeta();
1344
+ return true;
1345
+ }
1022
1346
  try {
1023
1347
  process.kill(-agent.pid, 'SIGTERM');
1024
1348
  debug(`Sent SIGTERM to agent ${agentId} (PID ${agent.pid})`);
@@ -1069,4 +1393,3 @@ export class AgentManager {
1069
1393
  }
1070
1394
  }
1071
1395
  }
1072
- //# sourceMappingURL=agents.js.map