@phnx-labs/agents-cli 0.1.0 → 1.14.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 (554) hide show
  1. package/CHANGELOG.md +7 -1
  2. package/README.md +283 -372
  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 +8 -1
  8. package/dist/commands/cloud.js +108 -22
  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 +96 -27
  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 +16 -4
  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 +9 -1
  38. package/dist/commands/profiles.js +56 -7
  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 +58 -128
  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 +8 -1
  56. package/dist/commands/secrets.js +235 -63
  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 +188 -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 +317 -24
  83. package/dist/index.d.ts +7 -2
  84. package/dist/index.js +172 -34
  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 +197 -21
  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 +9 -3
  104. package/dist/lib/cloud/codex.js +53 -13
  105. package/dist/lib/cloud/factory.d.ts +8 -3
  106. package/dist/lib/cloud/factory.js +19 -3
  107. package/dist/lib/cloud/registry.d.ts +10 -1
  108. package/dist/lib/cloud/registry.js +14 -3
  109. package/dist/lib/cloud/rush.d.ts +63 -3
  110. package/dist/lib/cloud/rush.js +273 -20
  111. package/dist/lib/cloud/store.d.ts +13 -1
  112. package/dist/lib/cloud/store.js +23 -4
  113. package/dist/lib/cloud/stream.d.ts +6 -1
  114. package/dist/lib/cloud/stream.js +95 -39
  115. package/dist/lib/cloud/types.d.ts +153 -8
  116. package/dist/lib/cloud/types.js +34 -2
  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 +23 -6
  128. package/dist/lib/exec.js +53 -17
  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 +119 -101
  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 +10 -4
  156. package/dist/lib/models.js +36 -15
  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 +10 -1
  168. package/dist/lib/profiles-presets.js +9 -1
  169. package/dist/lib/profiles.d.ts +35 -1
  170. package/dist/lib/profiles.js +36 -15
  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 +40 -13
  180. package/dist/lib/rotate.js +238 -40
  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 → secrets/bundles.d.ts} +12 -2
  195. package/dist/lib/{secrets-bundles.js → secrets/bundles.js} +38 -17
  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 +12 -1
  203. package/dist/lib/session/artifacts.js +25 -5
  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 +16 -2
  219. package/dist/lib/session/types.js +10 -2
  220. package/dist/lib/shims.d.ts +64 -5
  221. package/dist/lib/shims.js +309 -47
  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 +112 -27
  227. package/dist/lib/state.js +320 -148
  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 +32 -1
  257. package/dist/lib/usage.js +70 -6
  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 +33 -4
  261. package/dist/lib/versions.js +376 -108
  262. package/package.json +32 -17
  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/cloud.d.ts.map +0 -1
  269. package/dist/commands/cloud.js.map +0 -1
  270. package/dist/commands/commands.d.ts.map +0 -1
  271. package/dist/commands/commands.js.map +0 -1
  272. package/dist/commands/daemon.d.ts.map +0 -1
  273. package/dist/commands/daemon.js.map +0 -1
  274. package/dist/commands/drive.d.ts.map +0 -1
  275. package/dist/commands/drive.js.map +0 -1
  276. package/dist/commands/exec.d.ts.map +0 -1
  277. package/dist/commands/exec.js.map +0 -1
  278. package/dist/commands/fork.d.ts.map +0 -1
  279. package/dist/commands/fork.js.map +0 -1
  280. package/dist/commands/hooks.d.ts.map +0 -1
  281. package/dist/commands/hooks.js.map +0 -1
  282. package/dist/commands/init.d.ts.map +0 -1
  283. package/dist/commands/init.js.map +0 -1
  284. package/dist/commands/mcp.d.ts.map +0 -1
  285. package/dist/commands/mcp.js.map +0 -1
  286. package/dist/commands/models.d.ts.map +0 -1
  287. package/dist/commands/models.js.map +0 -1
  288. package/dist/commands/packages.d.ts.map +0 -1
  289. package/dist/commands/packages.js.map +0 -1
  290. package/dist/commands/permissions.d.ts.map +0 -1
  291. package/dist/commands/permissions.js.map +0 -1
  292. package/dist/commands/plugins.d.ts.map +0 -1
  293. package/dist/commands/plugins.js.map +0 -1
  294. package/dist/commands/profiles.d.ts.map +0 -1
  295. package/dist/commands/profiles.js.map +0 -1
  296. package/dist/commands/pty.d.ts.map +0 -1
  297. package/dist/commands/pty.js.map +0 -1
  298. package/dist/commands/pull.d.ts.map +0 -1
  299. package/dist/commands/pull.js.map +0 -1
  300. package/dist/commands/push.d.ts +0 -3
  301. package/dist/commands/push.d.ts.map +0 -1
  302. package/dist/commands/push.js +0 -180
  303. package/dist/commands/push.js.map +0 -1
  304. package/dist/commands/refresh-memory.d.ts.map +0 -1
  305. package/dist/commands/refresh-memory.js.map +0 -1
  306. package/dist/commands/resource-view.d.ts.map +0 -1
  307. package/dist/commands/resource-view.js.map +0 -1
  308. package/dist/commands/routines.d.ts.map +0 -1
  309. package/dist/commands/routines.js.map +0 -1
  310. package/dist/commands/rules.d.ts.map +0 -1
  311. package/dist/commands/rules.js.map +0 -1
  312. package/dist/commands/secrets.d.ts.map +0 -1
  313. package/dist/commands/secrets.js.map +0 -1
  314. package/dist/commands/sessions-picker.d.ts.map +0 -1
  315. package/dist/commands/sessions-picker.js.map +0 -1
  316. package/dist/commands/sessions.d.ts.map +0 -1
  317. package/dist/commands/sessions.js.map +0 -1
  318. package/dist/commands/skills.d.ts.map +0 -1
  319. package/dist/commands/skills.js.map +0 -1
  320. package/dist/commands/status.d.ts.map +0 -1
  321. package/dist/commands/status.js.map +0 -1
  322. package/dist/commands/subagents.d.ts.map +0 -1
  323. package/dist/commands/subagents.js.map +0 -1
  324. package/dist/commands/sync.d.ts.map +0 -1
  325. package/dist/commands/sync.js.map +0 -1
  326. package/dist/commands/teams-picker.d.ts.map +0 -1
  327. package/dist/commands/teams-picker.js.map +0 -1
  328. package/dist/commands/teams.d.ts.map +0 -1
  329. package/dist/commands/teams.js.map +0 -1
  330. package/dist/commands/utils.d.ts.map +0 -1
  331. package/dist/commands/utils.js.map +0 -1
  332. package/dist/commands/versions.d.ts.map +0 -1
  333. package/dist/commands/versions.js.map +0 -1
  334. package/dist/commands/view.d.ts.map +0 -1
  335. package/dist/commands/view.js.map +0 -1
  336. package/dist/index.d.ts.map +0 -1
  337. package/dist/index.js.map +0 -1
  338. package/dist/lib/__tests__/bugfixes.test.d.ts +0 -2
  339. package/dist/lib/__tests__/bugfixes.test.d.ts.map +0 -1
  340. package/dist/lib/__tests__/bugfixes.test.js +0 -192
  341. package/dist/lib/__tests__/bugfixes.test.js.map +0 -1
  342. package/dist/lib/__tests__/exec.test.d.ts +0 -2
  343. package/dist/lib/__tests__/exec.test.d.ts.map +0 -1
  344. package/dist/lib/__tests__/exec.test.js +0 -446
  345. package/dist/lib/__tests__/exec.test.js.map +0 -1
  346. package/dist/lib/__tests__/git-sync.test.d.ts +0 -2
  347. package/dist/lib/__tests__/git-sync.test.d.ts.map +0 -1
  348. package/dist/lib/__tests__/git-sync.test.js +0 -138
  349. package/dist/lib/__tests__/git-sync.test.js.map +0 -1
  350. package/dist/lib/__tests__/hooks.test.d.ts +0 -2
  351. package/dist/lib/__tests__/hooks.test.d.ts.map +0 -1
  352. package/dist/lib/__tests__/hooks.test.js +0 -203
  353. package/dist/lib/__tests__/hooks.test.js.map +0 -1
  354. package/dist/lib/__tests__/memory-compile.test.d.ts +0 -2
  355. package/dist/lib/__tests__/memory-compile.test.d.ts.map +0 -1
  356. package/dist/lib/__tests__/memory-compile.test.js +0 -95
  357. package/dist/lib/__tests__/memory-compile.test.js.map +0 -1
  358. package/dist/lib/__tests__/models.test.d.ts +0 -2
  359. package/dist/lib/__tests__/models.test.d.ts.map +0 -1
  360. package/dist/lib/__tests__/models.test.js +0 -239
  361. package/dist/lib/__tests__/models.test.js.map +0 -1
  362. package/dist/lib/__tests__/rotate.test.d.ts +0 -2
  363. package/dist/lib/__tests__/rotate.test.d.ts.map +0 -1
  364. package/dist/lib/__tests__/rotate.test.js +0 -80
  365. package/dist/lib/__tests__/rotate.test.js.map +0 -1
  366. package/dist/lib/__tests__/secrets-bundles.test.d.ts +0 -2
  367. package/dist/lib/__tests__/secrets-bundles.test.d.ts.map +0 -1
  368. package/dist/lib/__tests__/secrets-bundles.test.js +0 -104
  369. package/dist/lib/__tests__/secrets-bundles.test.js.map +0 -1
  370. package/dist/lib/__tests__/secrets.test.d.ts +0 -2
  371. package/dist/lib/__tests__/secrets.test.d.ts.map +0 -1
  372. package/dist/lib/__tests__/secrets.test.js +0 -90
  373. package/dist/lib/__tests__/secrets.test.js.map +0 -1
  374. package/dist/lib/__tests__/shims.test.d.ts +0 -2
  375. package/dist/lib/__tests__/shims.test.d.ts.map +0 -1
  376. package/dist/lib/__tests__/shims.test.js +0 -39
  377. package/dist/lib/__tests__/shims.test.js.map +0 -1
  378. package/dist/lib/__tests__/usage.test.d.ts +0 -2
  379. package/dist/lib/__tests__/usage.test.d.ts.map +0 -1
  380. package/dist/lib/__tests__/usage.test.js +0 -220
  381. package/dist/lib/__tests__/usage.test.js.map +0 -1
  382. package/dist/lib/__tests__/versions.test.d.ts +0 -2
  383. package/dist/lib/__tests__/versions.test.d.ts.map +0 -1
  384. package/dist/lib/__tests__/versions.test.js +0 -63
  385. package/dist/lib/__tests__/versions.test.js.map +0 -1
  386. package/dist/lib/agents.d.ts.map +0 -1
  387. package/dist/lib/agents.js.map +0 -1
  388. package/dist/lib/artifact-actions.d.ts.map +0 -1
  389. package/dist/lib/artifact-actions.js.map +0 -1
  390. package/dist/lib/cloud/codex.d.ts.map +0 -1
  391. package/dist/lib/cloud/codex.js.map +0 -1
  392. package/dist/lib/cloud/factory.d.ts.map +0 -1
  393. package/dist/lib/cloud/factory.js.map +0 -1
  394. package/dist/lib/cloud/registry.d.ts.map +0 -1
  395. package/dist/lib/cloud/registry.js.map +0 -1
  396. package/dist/lib/cloud/rush.d.ts.map +0 -1
  397. package/dist/lib/cloud/rush.js.map +0 -1
  398. package/dist/lib/cloud/store.d.ts.map +0 -1
  399. package/dist/lib/cloud/store.js.map +0 -1
  400. package/dist/lib/cloud/stream.d.ts.map +0 -1
  401. package/dist/lib/cloud/stream.js.map +0 -1
  402. package/dist/lib/cloud/types.d.ts.map +0 -1
  403. package/dist/lib/cloud/types.js.map +0 -1
  404. package/dist/lib/commands.d.ts.map +0 -1
  405. package/dist/lib/commands.js.map +0 -1
  406. package/dist/lib/convert.d.ts.map +0 -1
  407. package/dist/lib/convert.js.map +0 -1
  408. package/dist/lib/daemon.d.ts.map +0 -1
  409. package/dist/lib/daemon.js.map +0 -1
  410. package/dist/lib/drive-sync.d.ts.map +0 -1
  411. package/dist/lib/drive-sync.js.map +0 -1
  412. package/dist/lib/exec.d.ts.map +0 -1
  413. package/dist/lib/exec.js.map +0 -1
  414. package/dist/lib/factory.d.ts +0 -57
  415. package/dist/lib/factory.d.ts.map +0 -1
  416. package/dist/lib/factory.js +0 -110
  417. package/dist/lib/factory.js.map +0 -1
  418. package/dist/lib/git.d.ts.map +0 -1
  419. package/dist/lib/git.js.map +0 -1
  420. package/dist/lib/help.d.ts.map +0 -1
  421. package/dist/lib/help.js.map +0 -1
  422. package/dist/lib/hooks.d.ts.map +0 -1
  423. package/dist/lib/hooks.js.map +0 -1
  424. package/dist/lib/manifest.d.ts.map +0 -1
  425. package/dist/lib/manifest.js.map +0 -1
  426. package/dist/lib/markdown.d.ts.map +0 -1
  427. package/dist/lib/markdown.js.map +0 -1
  428. package/dist/lib/mcp.d.ts.map +0 -1
  429. package/dist/lib/mcp.js.map +0 -1
  430. package/dist/lib/memory-compile.d.ts.map +0 -1
  431. package/dist/lib/memory-compile.js.map +0 -1
  432. package/dist/lib/memory.d.ts.map +0 -1
  433. package/dist/lib/memory.js.map +0 -1
  434. package/dist/lib/models.d.ts.map +0 -1
  435. package/dist/lib/models.js.map +0 -1
  436. package/dist/lib/permissions.d.ts.map +0 -1
  437. package/dist/lib/permissions.js.map +0 -1
  438. package/dist/lib/picker.d.ts.map +0 -1
  439. package/dist/lib/picker.js.map +0 -1
  440. package/dist/lib/plugins.d.ts.map +0 -1
  441. package/dist/lib/plugins.js.map +0 -1
  442. package/dist/lib/profiles-keychain.d.ts +0 -3
  443. package/dist/lib/profiles-keychain.d.ts.map +0 -1
  444. package/dist/lib/profiles-keychain.js +0 -10
  445. package/dist/lib/profiles-keychain.js.map +0 -1
  446. package/dist/lib/profiles-presets.d.ts.map +0 -1
  447. package/dist/lib/profiles-presets.js.map +0 -1
  448. package/dist/lib/profiles.d.ts.map +0 -1
  449. package/dist/lib/profiles.js.map +0 -1
  450. package/dist/lib/pty-client.d.ts.map +0 -1
  451. package/dist/lib/pty-client.js.map +0 -1
  452. package/dist/lib/pty-server.d.ts.map +0 -1
  453. package/dist/lib/pty-server.js.map +0 -1
  454. package/dist/lib/registry.d.ts.map +0 -1
  455. package/dist/lib/registry.js.map +0 -1
  456. package/dist/lib/resources.d.ts.map +0 -1
  457. package/dist/lib/resources.js.map +0 -1
  458. package/dist/lib/rotate.d.ts.map +0 -1
  459. package/dist/lib/rotate.js.map +0 -1
  460. package/dist/lib/routines.d.ts.map +0 -1
  461. package/dist/lib/routines.js.map +0 -1
  462. package/dist/lib/runner.d.ts.map +0 -1
  463. package/dist/lib/runner.js.map +0 -1
  464. package/dist/lib/sandbox.d.ts.map +0 -1
  465. package/dist/lib/sandbox.js.map +0 -1
  466. package/dist/lib/scheduler.d.ts.map +0 -1
  467. package/dist/lib/scheduler.js.map +0 -1
  468. package/dist/lib/secrets-bundles.d.ts.map +0 -1
  469. package/dist/lib/secrets-bundles.js.map +0 -1
  470. package/dist/lib/secrets.d.ts +0 -27
  471. package/dist/lib/secrets.d.ts.map +0 -1
  472. package/dist/lib/secrets.js +0 -127
  473. package/dist/lib/secrets.js.map +0 -1
  474. package/dist/lib/session/__tests__/db.test.d.ts +0 -2
  475. package/dist/lib/session/__tests__/db.test.d.ts.map +0 -1
  476. package/dist/lib/session/__tests__/db.test.js +0 -54
  477. package/dist/lib/session/__tests__/db.test.js.map +0 -1
  478. package/dist/lib/session/__tests__/discover.test.d.ts +0 -2
  479. package/dist/lib/session/__tests__/discover.test.d.ts.map +0 -1
  480. package/dist/lib/session/__tests__/discover.test.js +0 -63
  481. package/dist/lib/session/__tests__/discover.test.js.map +0 -1
  482. package/dist/lib/session/__tests__/prompt.test.d.ts +0 -2
  483. package/dist/lib/session/__tests__/prompt.test.d.ts.map +0 -1
  484. package/dist/lib/session/__tests__/prompt.test.js +0 -44
  485. package/dist/lib/session/__tests__/prompt.test.js.map +0 -1
  486. package/dist/lib/session/__tests__/render.test.d.ts +0 -2
  487. package/dist/lib/session/__tests__/render.test.d.ts.map +0 -1
  488. package/dist/lib/session/__tests__/render.test.js +0 -602
  489. package/dist/lib/session/__tests__/render.test.js.map +0 -1
  490. package/dist/lib/session/artifacts.d.ts.map +0 -1
  491. package/dist/lib/session/artifacts.js.map +0 -1
  492. package/dist/lib/session/db.d.ts.map +0 -1
  493. package/dist/lib/session/db.js.map +0 -1
  494. package/dist/lib/session/discover.d.ts.map +0 -1
  495. package/dist/lib/session/discover.js.map +0 -1
  496. package/dist/lib/session/parse.d.ts.map +0 -1
  497. package/dist/lib/session/parse.js.map +0 -1
  498. package/dist/lib/session/prompt.d.ts.map +0 -1
  499. package/dist/lib/session/prompt.js.map +0 -1
  500. package/dist/lib/session/prompt.test.d.ts +0 -2
  501. package/dist/lib/session/prompt.test.d.ts.map +0 -1
  502. package/dist/lib/session/prompt.test.js +0 -57
  503. package/dist/lib/session/prompt.test.js.map +0 -1
  504. package/dist/lib/session/render.d.ts.map +0 -1
  505. package/dist/lib/session/render.js.map +0 -1
  506. package/dist/lib/session/team-filter.d.ts.map +0 -1
  507. package/dist/lib/session/team-filter.js.map +0 -1
  508. package/dist/lib/session/team-filter.test.d.ts +0 -2
  509. package/dist/lib/session/team-filter.test.d.ts.map +0 -1
  510. package/dist/lib/session/team-filter.test.js +0 -157
  511. package/dist/lib/session/team-filter.test.js.map +0 -1
  512. package/dist/lib/session/types.d.ts.map +0 -1
  513. package/dist/lib/session/types.js.map +0 -1
  514. package/dist/lib/shims.d.ts.map +0 -1
  515. package/dist/lib/shims.js.map +0 -1
  516. package/dist/lib/skills.d.ts.map +0 -1
  517. package/dist/lib/skills.js.map +0 -1
  518. package/dist/lib/state.d.ts.map +0 -1
  519. package/dist/lib/state.js.map +0 -1
  520. package/dist/lib/subagents.d.ts.map +0 -1
  521. package/dist/lib/subagents.js.map +0 -1
  522. package/dist/lib/teams/agents.d.ts.map +0 -1
  523. package/dist/lib/teams/agents.js.map +0 -1
  524. package/dist/lib/teams/api.d.ts.map +0 -1
  525. package/dist/lib/teams/api.js.map +0 -1
  526. package/dist/lib/teams/cloud.d.ts +0 -11
  527. package/dist/lib/teams/cloud.d.ts.map +0 -1
  528. package/dist/lib/teams/cloud.js +0 -169
  529. package/dist/lib/teams/cloud.js.map +0 -1
  530. package/dist/lib/teams/debug.d.ts.map +0 -1
  531. package/dist/lib/teams/debug.js.map +0 -1
  532. package/dist/lib/teams/file_ops.d.ts.map +0 -1
  533. package/dist/lib/teams/file_ops.js.map +0 -1
  534. package/dist/lib/teams/parsers.d.ts.map +0 -1
  535. package/dist/lib/teams/parsers.js.map +0 -1
  536. package/dist/lib/teams/persistence.d.ts.map +0 -1
  537. package/dist/lib/teams/persistence.js.map +0 -1
  538. package/dist/lib/teams/ralph.d.ts +0 -8
  539. package/dist/lib/teams/ralph.d.ts.map +0 -1
  540. package/dist/lib/teams/ralph.js +0 -59
  541. package/dist/lib/teams/ralph.js.map +0 -1
  542. package/dist/lib/teams/registry.d.ts.map +0 -1
  543. package/dist/lib/teams/registry.js.map +0 -1
  544. package/dist/lib/teams/summarizer.d.ts.map +0 -1
  545. package/dist/lib/teams/summarizer.js.map +0 -1
  546. package/dist/lib/template.d.ts.map +0 -1
  547. package/dist/lib/template.js.map +0 -1
  548. package/dist/lib/types.d.ts.map +0 -1
  549. package/dist/lib/types.js.map +0 -1
  550. package/dist/lib/usage.d.ts.map +0 -1
  551. package/dist/lib/usage.js.map +0 -1
  552. package/dist/lib/versions.d.ts.map +0 -1
  553. package/dist/lib/versions.js.map +0 -1
  554. package/scripts/rebuild-sqlite.sh +0 -46
@@ -1,10 +1,18 @@
1
- import type { AgentId } from './types.js';
1
+ /**
2
+ * Account rotation across agent versions.
3
+ *
4
+ * Detects which installed versions have expired credentials and rotates
5
+ * authentication tokens so users maintain active sessions across version switches.
6
+ */
7
+ import type { AgentId, RunStrategy } from './types.js';
2
8
  import { type AccountInfo } from './agents.js';
9
+ import { type UsageSnapshot } from './usage.js';
3
10
  export interface RotateCandidate {
4
11
  agent: AgentId;
5
12
  version: string;
6
13
  email: string | null;
7
14
  usageStatus: AccountInfo['usageStatus'];
15
+ usageSnapshot: UsageSnapshot | null;
8
16
  authValid: boolean;
9
17
  lastActive: Date | null;
10
18
  }
@@ -16,19 +24,43 @@ export interface RotateResult {
16
24
  /** Candidates excluded (not signed in, or out of credits). */
17
25
  excluded: RotateCandidate[];
18
26
  }
27
+ export declare const RUN_STRATEGIES: RunStrategy[];
28
+ /** Return a run strategy when the input is valid, otherwise null. */
29
+ export declare function normalizeRunStrategy(value: unknown): RunStrategy | null;
30
+ /** Read project-local run strategy from the nearest agents.yaml, if present. */
31
+ export declare function getProjectRunStrategy(agent: AgentId, startPath: string): RunStrategy | null;
32
+ /** Resolve the configured strategy: project agents.yaml, then ~/.agents-system/agents.yaml, then pinned. */
33
+ export declare function getConfiguredRunStrategy(agent: AgentId, startPath?: string): RunStrategy;
34
+ /** Persist the global run strategy used by bare `agents run <agent>`. */
35
+ export declare function setGlobalRunStrategy(agent: AgentId, strategy: RunStrategy): void;
19
36
  /**
20
37
  * Pure selection: given a set of candidates, return the best one for the
21
38
  * next run. Kept separate from I/O so it can be unit-tested with fixtures.
22
39
  *
23
40
  * Eligibility: signed in (email present) and not out of credits.
24
- * Tie-break: least-recently-active wins. Never-used versions sort oldest
25
- * so fresh installs are tried before recently-used ones.
41
+ * Dedupe: when multiple versions share an email (same Anthropic account
42
+ * installed under several agent versions), collapse to one candidate per
43
+ * email — the least-recently-active version. Without this, two parallel
44
+ * pods could "rotate" to different versions but hit the same account and
45
+ * both 429 against the same Anthropic quota.
46
+ * Primary order: lowest live usage utilization wins. Least-recently-active is
47
+ * the tie-breaker when usage is equal or unavailable. Never-used versions sort
48
+ * oldest so fresh installs are tried before recently-used ones.
49
+ * Tie-break: random — when two candidates share a `lastActive` timestamp
50
+ * (common when N pods read the same snapshot), distribute across them so
51
+ * parallel callers fan out instead of all picking the same version.
26
52
  */
27
53
  export declare function pickRotateCandidate(candidates: RotateCandidate[]): RotateResult | null;
54
+ /**
55
+ * Pick an available candidate. Prefers the configured pinned version when that
56
+ * version has usage available; otherwise routes to the candidate with the most
57
+ * usage headroom.
58
+ */
59
+ export declare function pickAvailableCandidate(candidates: RotateCandidate[], preferredVersion?: string | null): RotateResult | null;
28
60
  /**
29
61
  * Rotate across installed versions of an agent and pick the best one for the
30
- * next run. "Best" means: signed in, not out of credits, and least-recently-
31
- * active (so two back-to-back runs hit different accounts automatically).
62
+ * next run. "Best" means: signed in, usage available, and lowest usage
63
+ * utilization, with least-recently-active as a tie-breaker.
32
64
  *
33
65
  * No external state: rotation and health are both read off per-version
34
66
  * AccountInfo — the same data `agents view` already surfaces. `lastActive`
@@ -39,14 +71,9 @@ export declare function pickRotateCandidate(candidates: RotateCandidate[]): Rota
39
71
  * global default so behavior stays predictable — we never refuse to run.
40
72
  */
41
73
  export declare function selectRotateVersion(agent: AgentId): Promise<RotateResult | null>;
42
- /**
43
- * Resolve the version `agents run` should use when the caller did not pin
44
- * one with `@version`. Rotation is the default; falls back to the global
45
- * default if no version is healthy, and to null if the agent isn't installed
46
- * under agents-cli at all (let exec surface its own error).
47
- */
48
- export declare function resolveRunVersion(agent: AgentId): Promise<{
74
+ /** Select the configured version if available, otherwise another available version. */
75
+ export declare function selectAvailableVersion(agent: AgentId, preferredVersion?: string | null): Promise<RotateResult | null>;
76
+ export declare function resolveRunVersion(agent: AgentId, strategy: RunStrategy, cwd?: string): Promise<{
49
77
  version: string | null;
50
78
  rotation: RotateResult | null;
51
79
  }>;
52
- //# sourceMappingURL=rotate.d.ts.map
@@ -1,27 +1,163 @@
1
+ /**
2
+ * Account rotation across agent versions.
3
+ *
4
+ * Detects which installed versions have expired credentials and rotates
5
+ * authentication tokens so users maintain active sessions across version switches.
6
+ */
7
+ import * as fs from 'fs';
8
+ import * as path from 'path';
9
+ import * as yaml from 'yaml';
1
10
  import { getAccountInfo } from './agents.js';
2
- import { listInstalledVersions, getVersionHomePath, getGlobalDefault } from './versions.js';
3
- import { isClaudeAuthValid } from './usage.js';
11
+ import { readMeta, writeMeta, getAgentsDir } from './state.js';
12
+ import { listInstalledVersions, getVersionHomePath, resolveVersion } from './versions.js';
13
+ import { getUsageInfoByIdentity, getUsageLookupKey, isClaudeAuthValid, } from './usage.js';
14
+ export const RUN_STRATEGIES = ['pinned', 'available', 'rotate'];
15
+ /** Return a run strategy when the input is valid, otherwise null. */
16
+ export function normalizeRunStrategy(value) {
17
+ return typeof value === 'string' && RUN_STRATEGIES.includes(value)
18
+ ? value
19
+ : null;
20
+ }
21
+ /** Read project-local run strategy from the nearest agents.yaml, if present. */
22
+ export function getProjectRunStrategy(agent, startPath) {
23
+ let dir = path.resolve(startPath);
24
+ const userAgentsYaml = path.join(getAgentsDir(), 'agents.yaml');
25
+ while (dir !== path.dirname(dir)) {
26
+ const manifestPath = path.join(dir, 'agents.yaml');
27
+ if (manifestPath !== userAgentsYaml && fs.existsSync(manifestPath)) {
28
+ try {
29
+ const parsed = yaml.parse(fs.readFileSync(manifestPath, 'utf-8'));
30
+ const strategy = normalizeRunStrategy(parsed?.run?.[agent]?.strategy);
31
+ if (strategy)
32
+ return strategy;
33
+ }
34
+ catch {
35
+ // Ignore malformed project config and keep walking, matching version resolution.
36
+ }
37
+ }
38
+ dir = path.dirname(dir);
39
+ }
40
+ return null;
41
+ }
42
+ /** Resolve the configured strategy: project agents.yaml, then ~/.agents-system/agents.yaml, then pinned. */
43
+ export function getConfiguredRunStrategy(agent, startPath = process.cwd()) {
44
+ return getProjectRunStrategy(agent, startPath)
45
+ ?? normalizeRunStrategy(readMeta().run?.[agent]?.strategy)
46
+ ?? 'pinned';
47
+ }
48
+ /** Persist the global run strategy used by bare `agents run <agent>`. */
49
+ export function setGlobalRunStrategy(agent, strategy) {
50
+ const meta = readMeta();
51
+ if (!meta.run)
52
+ meta.run = {};
53
+ meta.run[agent] = { ...(meta.run[agent] ?? {}), strategy };
54
+ writeMeta(meta);
55
+ }
56
+ function isRotationEligible(candidate) {
57
+ return !!candidate.email
58
+ && candidate.authValid
59
+ && hasUsageAvailable(candidate);
60
+ }
61
+ function isAvailableEligible(candidate) {
62
+ return !!candidate.email
63
+ && candidate.authValid
64
+ && hasUsageAvailable(candidate);
65
+ }
66
+ function hasUsageAvailable(candidate) {
67
+ const usedPercent = getRoutingUsedPercent(candidate.usageSnapshot);
68
+ if (usedPercent !== null) {
69
+ return usedPercent < 100;
70
+ }
71
+ if (candidate.usageStatus === 'out_of_credits' || candidate.usageStatus === 'rate_limited') {
72
+ return false;
73
+ }
74
+ return true;
75
+ }
76
+ function getRoutingUsedPercent(snapshot) {
77
+ if (!snapshot || snapshot.windows.length === 0)
78
+ return null;
79
+ const routingWindows = snapshot.windows.filter((window) => window.key !== 'session');
80
+ const windows = routingWindows.length > 0 ? routingWindows : snapshot.windows;
81
+ return Math.max(...windows.map((window) => window.usedPercent));
82
+ }
83
+ function compareCandidates(a, b) {
84
+ const au = getRoutingUsedPercent(a.usageSnapshot);
85
+ const bu = getRoutingUsedPercent(b.usageSnapshot);
86
+ if (au !== null || bu !== null) {
87
+ if (au === null)
88
+ return 1;
89
+ if (bu === null)
90
+ return -1;
91
+ if (au !== bu)
92
+ return au - bu;
93
+ }
94
+ const ta = a.lastActive ? a.lastActive.getTime() : 0;
95
+ const tb = b.lastActive ? b.lastActive.getTime() : 0;
96
+ if (ta !== tb)
97
+ return ta - tb;
98
+ return Math.random() - 0.5;
99
+ }
100
+ function dedupeAndSortCandidates(candidates) {
101
+ const byEmail = new Map();
102
+ for (const c of candidates) {
103
+ const email = c.email;
104
+ const existing = byEmail.get(email);
105
+ if (!existing) {
106
+ byEmail.set(email, c);
107
+ continue;
108
+ }
109
+ if (compareCandidates(c, existing) < 0)
110
+ byEmail.set(email, c);
111
+ }
112
+ return [...byEmail.values()].sort(compareCandidates);
113
+ }
4
114
  /**
5
115
  * Pure selection: given a set of candidates, return the best one for the
6
116
  * next run. Kept separate from I/O so it can be unit-tested with fixtures.
7
117
  *
8
118
  * Eligibility: signed in (email present) and not out of credits.
9
- * Tie-break: least-recently-active wins. Never-used versions sort oldest
10
- * so fresh installs are tried before recently-used ones.
119
+ * Dedupe: when multiple versions share an email (same Anthropic account
120
+ * installed under several agent versions), collapse to one candidate per
121
+ * email — the least-recently-active version. Without this, two parallel
122
+ * pods could "rotate" to different versions but hit the same account and
123
+ * both 429 against the same Anthropic quota.
124
+ * Primary order: lowest live usage utilization wins. Least-recently-active is
125
+ * the tie-breaker when usage is equal or unavailable. Never-used versions sort
126
+ * oldest so fresh installs are tried before recently-used ones.
127
+ * Tie-break: random — when two candidates share a `lastActive` timestamp
128
+ * (common when N pods read the same snapshot), distribute across them so
129
+ * parallel callers fan out instead of all picking the same version.
11
130
  */
12
131
  export function pickRotateCandidate(candidates) {
13
132
  const healthy = [];
14
133
  const excluded = [];
15
134
  for (const c of candidates) {
16
- if (!c.email) {
135
+ if (!isRotationEligible(c)) {
17
136
  excluded.push(c);
18
137
  continue;
19
138
  }
20
- if (c.usageStatus === 'out_of_credits') {
139
+ healthy.push(c);
140
+ }
141
+ if (healthy.length === 0)
142
+ return null;
143
+ const sorted = dedupeAndSortCandidates(healthy);
144
+ const deduped = new Set(sorted);
145
+ for (const c of healthy) {
146
+ if (!deduped.has(c))
21
147
  excluded.push(c);
22
- continue;
23
- }
24
- if (!c.authValid) {
148
+ }
149
+ return { picked: sorted[0], healthy: sorted, excluded };
150
+ }
151
+ /**
152
+ * Pick an available candidate. Prefers the configured pinned version when that
153
+ * version has usage available; otherwise routes to the candidate with the most
154
+ * usage headroom.
155
+ */
156
+ export function pickAvailableCandidate(candidates, preferredVersion) {
157
+ const healthy = [];
158
+ const excluded = [];
159
+ for (const c of candidates) {
160
+ if (!isAvailableEligible(c)) {
25
161
  excluded.push(c);
26
162
  continue;
27
163
  }
@@ -29,31 +165,20 @@ export function pickRotateCandidate(candidates) {
29
165
  }
30
166
  if (healthy.length === 0)
31
167
  return null;
32
- const sorted = [...healthy].sort((a, b) => {
33
- const ta = a.lastActive ? a.lastActive.getTime() : 0;
34
- const tb = b.lastActive ? b.lastActive.getTime() : 0;
35
- return ta - tb;
36
- });
37
- return { picked: sorted[0], healthy: sorted, excluded };
168
+ const sorted = dedupeAndSortCandidates(healthy);
169
+ const deduped = new Set(sorted);
170
+ for (const c of healthy) {
171
+ if (!deduped.has(c))
172
+ excluded.push(c);
173
+ }
174
+ const preferred = preferredVersion
175
+ ? sorted.find((candidate) => candidate.version === preferredVersion)
176
+ : undefined;
177
+ return { picked: preferred ?? sorted[0], healthy: sorted, excluded };
38
178
  }
39
- /**
40
- * Rotate across installed versions of an agent and pick the best one for the
41
- * next run. "Best" means: signed in, not out of credits, and least-recently-
42
- * active (so two back-to-back runs hit different accounts automatically).
43
- *
44
- * No external state: rotation and health are both read off per-version
45
- * AccountInfo — the same data `agents view` already surfaces. `lastActive`
46
- * advances naturally after each run, so the cursor is self-maintaining.
47
- *
48
- * Returns null if no installed version is eligible (either nothing installed
49
- * or every account is exhausted / not signed in). Callers fall back to the
50
- * global default so behavior stays predictable — we never refuse to run.
51
- */
52
- export async function selectRotateVersion(agent) {
179
+ async function collectRunCandidates(agent) {
53
180
  const versions = listInstalledVersions(agent);
54
- if (versions.length === 0)
55
- return null;
56
- const candidates = await Promise.all(versions.map(async (version) => {
181
+ const rows = await Promise.all(versions.map(async (version) => {
57
182
  const home = getVersionHomePath(agent, version);
58
183
  const info = await getAccountInfo(agent, home);
59
184
  const authValid = info.email
@@ -62,26 +187,99 @@ export async function selectRotateVersion(agent) {
62
187
  return {
63
188
  agent,
64
189
  version,
190
+ home,
191
+ info,
65
192
  email: info.email,
66
193
  usageStatus: info.usageStatus,
67
194
  authValid,
68
195
  lastActive: info.lastActive,
69
196
  };
70
197
  }));
71
- return pickRotateCandidate(candidates);
198
+ const { usageByKey } = await getUsageInfoByIdentity(rows.map(({ home, info, version }) => ({
199
+ agentId: agent,
200
+ home,
201
+ cliVersion: version,
202
+ info,
203
+ })));
204
+ return rows.map(({ home: _home, info, ...candidate }) => {
205
+ const usageKey = getUsageLookupKey(info);
206
+ const usageSnapshot = usageKey
207
+ ? usageByKey.get(usageKey)?.snapshot ?? null
208
+ : null;
209
+ return { ...candidate, usageSnapshot };
210
+ });
211
+ }
212
+ /**
213
+ * Rotate across installed versions of an agent and pick the best one for the
214
+ * next run. "Best" means: signed in, usage available, and lowest usage
215
+ * utilization, with least-recently-active as a tie-breaker.
216
+ *
217
+ * No external state: rotation and health are both read off per-version
218
+ * AccountInfo — the same data `agents view` already surfaces. `lastActive`
219
+ * advances naturally after each run, so the cursor is self-maintaining.
220
+ *
221
+ * Returns null if no installed version is eligible (either nothing installed
222
+ * or every account is exhausted / not signed in). Callers fall back to the
223
+ * global default so behavior stays predictable — we never refuse to run.
224
+ */
225
+ export async function selectRotateVersion(agent) {
226
+ return pickRotateCandidate(await collectRunCandidates(agent));
227
+ }
228
+ /** Select the configured version if available, otherwise another available version. */
229
+ export async function selectAvailableVersion(agent, preferredVersion) {
230
+ return pickAvailableCandidate(await collectRunCandidates(agent), preferredVersion);
72
231
  }
73
232
  /**
74
233
  * Resolve the version `agents run` should use when the caller did not pin
75
- * one with `@version`. Rotation is the default; falls back to the global
76
- * default if no version is healthy, and to null if the agent isn't installed
77
- * under agents-cli at all (let exec surface its own error).
234
+ * one with `@version`. The caller supplies the effective strategy; if that
235
+ * strategy cannot find a usable candidate, fall back to the pinned
236
+ * workspace/global version.
78
237
  */
79
- export async function resolveRunVersion(agent) {
80
- const rotation = await selectRotateVersion(agent);
238
+ /**
239
+ * Record a rotation pick so parallel callers see it as recently-used.
240
+ * Writes a stamp file per agent — lightweight, no locking needed since
241
+ * a torn write just means the next reader sees a stale timestamp (harmless).
242
+ */
243
+ function recordRotationPick(agent, version) {
244
+ const stampPath = path.join(getAgentsDir(), `rotate-stamp-${agent}.json`);
245
+ try {
246
+ fs.writeFileSync(stampPath, JSON.stringify({ version, ts: Date.now() }), 'utf-8');
247
+ }
248
+ catch { /* best effort — doesn't block the run */ }
249
+ }
250
+ /**
251
+ * Read the most recent rotation pick for an agent. Returns null if no stamp
252
+ * or stamp is older than 60 seconds (stale).
253
+ */
254
+ function readRotationStamp(agent) {
255
+ const stampPath = path.join(getAgentsDir(), `rotate-stamp-${agent}.json`);
256
+ try {
257
+ const raw = JSON.parse(fs.readFileSync(stampPath, 'utf-8'));
258
+ if (Date.now() - raw.ts < 60_000)
259
+ return raw.version;
260
+ }
261
+ catch { /* missing or corrupt — treat as no stamp */ }
262
+ return null;
263
+ }
264
+ export async function resolveRunVersion(agent, strategy, cwd = process.cwd()) {
265
+ const fallback = resolveVersion(agent, cwd);
266
+ if (strategy === 'pinned') {
267
+ return { version: fallback, rotation: null };
268
+ }
269
+ const rotation = strategy === 'available'
270
+ ? await selectAvailableVersion(agent, fallback)
271
+ : await selectRotateVersion(agent);
81
272
  if (rotation) {
273
+ // If another process just picked the same version (within 60s), try the
274
+ // next healthy candidate to distribute load across accounts.
275
+ const recentPick = readRotationStamp(agent);
276
+ if (recentPick === rotation.picked.version && rotation.healthy.length > 1) {
277
+ const alt = rotation.healthy.find(c => c.version !== recentPick);
278
+ if (alt)
279
+ rotation.picked = alt;
280
+ }
281
+ recordRotationPick(agent, rotation.picked.version);
82
282
  return { version: rotation.picked.version, rotation };
83
283
  }
84
- const fallback = getGlobalDefault(agent);
85
284
  return { version: fallback, rotation: null };
86
285
  }
87
- //# sourceMappingURL=rotate.js.map
@@ -1,9 +1,19 @@
1
+ /**
2
+ * Scheduled job (routine) configuration and run history management.
3
+ *
4
+ * Routines are YAML files in ~/.agents/routines/ that define recurring or
5
+ * one-shot agent tasks. This module handles CRUD operations on job configs,
6
+ * run metadata persistence, prompt variable expansion, and one-shot "at" time
7
+ * scheduling.
8
+ */
1
9
  import type { AgentId } from './types.js';
10
+ /** Tool/site/directory allow-list for sandboxed job execution. */
2
11
  export interface JobAllowConfig {
3
12
  tools?: string[];
4
13
  sites?: string[];
5
14
  dirs?: string[];
6
15
  }
16
+ /** Full configuration for a scheduled routine (persisted as YAML). */
7
17
  export interface JobConfig {
8
18
  name: string;
9
19
  schedule: string;
@@ -21,6 +31,7 @@ export interface JobConfig {
21
31
  version?: string;
22
32
  runOnce?: boolean;
23
33
  }
34
+ /** Metadata for a single job execution, persisted as JSON in the run directory. */
24
35
  export interface RunMeta {
25
36
  jobName: string;
26
37
  runId: string;
@@ -31,24 +42,40 @@ export interface RunMeta {
31
42
  completedAt: string | null;
32
43
  exitCode: number | null;
33
44
  }
45
+ /** List all job configs from ~/.agents/routines/. */
34
46
  export declare function listJobs(): JobConfig[];
47
+ /** Read a single job config by name. Returns null if not found. */
35
48
  export declare function readJob(name: string): JobConfig | null;
49
+ /** Write a job config to disk, omitting fields that match defaults. */
36
50
  export declare function writeJob(config: JobConfig): void;
51
+ /** Delete a job config file by name. Returns true if the file existed. */
37
52
  export declare function deleteJob(name: string): boolean;
53
+ /** Enable or disable a job by name. */
38
54
  export declare function setJobEnabled(name: string, enabled: boolean): void;
55
+ /** Validate a partial job config, returning a list of human-readable errors. */
39
56
  export declare function validateJob(config: Partial<JobConfig>): string[];
57
+ /** Expand built-in and user-defined template variables in a job's prompt string. */
40
58
  export declare function resolveJobPrompt(config: JobConfig): string;
59
+ /** Parse a human-readable timeout string (e.g. "30m", "2h", "1h30m") into milliseconds. */
41
60
  export declare function parseTimeout(timeout: string): number | null;
61
+ /** List all run metadata entries for a job, sorted chronologically. */
42
62
  export declare function listRuns(jobName: string): RunMeta[];
63
+ /** Get the most recent run for a job, or null if never run. */
43
64
  export declare function getLatestRun(jobName: string): RunMeta | null;
65
+ /** Persist run metadata to its run directory as meta.json. */
44
66
  export declare function writeRunMeta(meta: RunMeta): void;
67
+ /** Read run metadata from disk. Returns null if missing or corrupt. */
45
68
  export declare function readRunMeta(jobName: string, runId: string): RunMeta | null;
69
+ /** Get the filesystem path for a specific run's directory. */
46
70
  export declare function getRunDir(jobName: string, runId: string): string;
71
+ /** Discover routine YAML files in a repository's routines/ directory. */
47
72
  export declare function discoverJobsFromRepo(repoPath: string): Array<{
48
73
  name: string;
49
74
  path: string;
50
75
  }>;
76
+ /** Check whether a job with the given name exists on disk. */
51
77
  export declare function jobExists(name: string): boolean;
78
+ /** Get the filesystem path of a job's YAML config file, or null if not found. */
52
79
  export declare function getJobPath(name: string): string | null;
53
80
  /**
54
81
  * Parse an "at" time string into a one-shot cron expression.
@@ -62,9 +89,10 @@ export declare function parseAtTime(atTime: string): {
62
89
  schedule: string;
63
90
  runOnce: boolean;
64
91
  } | null;
92
+ /** Check if an installed job's normalized YAML matches the source file. */
65
93
  export declare function jobContentMatches(name: string, sourcePath: string): boolean;
94
+ /** Install a job by reading and validating a YAML source file. */
66
95
  export declare function installJobFromSource(sourcePath: string, name: string): {
67
96
  success: boolean;
68
97
  error?: string;
69
98
  };
70
- //# sourceMappingURL=routines.d.ts.map
@@ -1,15 +1,26 @@
1
+ /**
2
+ * Scheduled job (routine) configuration and run history management.
3
+ *
4
+ * Routines are YAML files in ~/.agents/routines/ that define recurring or
5
+ * one-shot agent tasks. This module handles CRUD operations on job configs,
6
+ * run metadata persistence, prompt variable expansion, and one-shot "at" time
7
+ * scheduling.
8
+ */
1
9
  import * as fs from 'fs';
2
10
  import * as path from 'path';
3
11
  import * as yaml from 'yaml';
4
12
  import { Cron } from 'croner';
5
13
  import { getRoutinesDir, getRunsDir, ensureAgentsDir } from './state.js';
14
+ import { safeJoin } from './paths.js';
6
15
  import { ALL_AGENT_IDS } from './agents.js';
16
+ /** Default values applied to every job config when fields are omitted. */
7
17
  const JOB_DEFAULTS = {
8
18
  mode: 'plan',
9
19
  effort: 'auto',
10
20
  timeout: '30m',
11
21
  enabled: true,
12
22
  };
23
+ /** List all job configs from ~/.agents/routines/. */
13
24
  export function listJobs() {
14
25
  ensureAgentsDir();
15
26
  const jobsDir = getRoutinesDir();
@@ -24,11 +35,12 @@ export function listJobs() {
24
35
  }
25
36
  return jobs;
26
37
  }
38
+ /** Read a single job config by name. Returns null if not found. */
27
39
  export function readJob(name) {
28
40
  ensureAgentsDir();
29
41
  const jobsDir = getRoutinesDir();
30
42
  for (const ext of ['.yml', '.yaml']) {
31
- const filePath = path.join(jobsDir, name + ext);
43
+ const filePath = safeJoin(jobsDir, name + ext);
32
44
  if (fs.existsSync(filePath)) {
33
45
  return readJobFile(filePath);
34
46
  }
@@ -51,10 +63,11 @@ function readJobFile(filePath) {
51
63
  return null;
52
64
  }
53
65
  }
66
+ /** Write a job config to disk, omitting fields that match defaults. */
54
67
  export function writeJob(config) {
55
68
  ensureAgentsDir();
56
69
  const jobsDir = getRoutinesDir();
57
- const filePath = path.join(jobsDir, config.name + '.yml');
70
+ const filePath = safeJoin(jobsDir, config.name + '.yml');
58
71
  const output = { ...config };
59
72
  if (output.mode === 'plan')
60
73
  delete output.mode;
@@ -68,10 +81,11 @@ export function writeJob(config) {
68
81
  delete output.runOnce;
69
82
  fs.writeFileSync(filePath, yaml.stringify(output), 'utf-8');
70
83
  }
84
+ /** Delete a job config file by name. Returns true if the file existed. */
71
85
  export function deleteJob(name) {
72
86
  const jobsDir = getRoutinesDir();
73
87
  for (const ext of ['.yml', '.yaml']) {
74
- const filePath = path.join(jobsDir, name + ext);
88
+ const filePath = safeJoin(jobsDir, name + ext);
75
89
  if (fs.existsSync(filePath)) {
76
90
  fs.unlinkSync(filePath);
77
91
  return true;
@@ -79,6 +93,7 @@ export function deleteJob(name) {
79
93
  }
80
94
  return false;
81
95
  }
96
+ /** Enable or disable a job by name. */
82
97
  export function setJobEnabled(name, enabled) {
83
98
  const job = readJob(name);
84
99
  if (!job)
@@ -86,6 +101,7 @@ export function setJobEnabled(name, enabled) {
86
101
  job.enabled = enabled;
87
102
  writeJob(job);
88
103
  }
104
+ /** Validate a partial job config, returning a list of human-readable errors. */
89
105
  export function validateJob(config) {
90
106
  const errors = [];
91
107
  if (!config.name || typeof config.name !== 'string') {
@@ -123,6 +139,7 @@ export function validateJob(config) {
123
139
  }
124
140
  return errors;
125
141
  }
142
+ /** Expand built-in and user-defined template variables in a job's prompt string. */
126
143
  export function resolveJobPrompt(config) {
127
144
  const now = new Date();
128
145
  const tz = config.timezone || Intl.DateTimeFormat().resolvedOptions().timeZone;
@@ -162,6 +179,7 @@ export function resolveJobPrompt(config) {
162
179
  }
163
180
  return prompt;
164
181
  }
182
+ /** Parse a human-readable timeout string (e.g. "30m", "2h", "1h30m") into milliseconds. */
165
183
  export function parseTimeout(timeout) {
166
184
  const match = timeout.match(/^(?:(\d+)h)?(?:(\d+)m)?$/);
167
185
  if (!match)
@@ -171,6 +189,7 @@ export function parseTimeout(timeout) {
171
189
  const ms = (hours * 60 + minutes) * 60 * 1000;
172
190
  return ms > 0 ? ms : null;
173
191
  }
192
+ /** List all run metadata entries for a job, sorted chronologically. */
174
193
  export function listRuns(jobName) {
175
194
  const runsDir = getRunsDir();
176
195
  const jobRunsDir = path.join(runsDir, jobName);
@@ -188,16 +207,19 @@ export function listRuns(jobName) {
188
207
  }
189
208
  return runs;
190
209
  }
210
+ /** Get the most recent run for a job, or null if never run. */
191
211
  export function getLatestRun(jobName) {
192
212
  const runs = listRuns(jobName);
193
213
  return runs.length > 0 ? runs[runs.length - 1] : null;
194
214
  }
215
+ /** Persist run metadata to its run directory as meta.json. */
195
216
  export function writeRunMeta(meta) {
196
217
  ensureAgentsDir();
197
218
  const runDir = path.join(getRunsDir(), meta.jobName, meta.runId);
198
219
  fs.mkdirSync(runDir, { recursive: true });
199
220
  fs.writeFileSync(path.join(runDir, 'meta.json'), JSON.stringify(meta, null, 2), 'utf-8');
200
221
  }
222
+ /** Read run metadata from disk. Returns null if missing or corrupt. */
201
223
  export function readRunMeta(jobName, runId) {
202
224
  const metaPath = path.join(getRunsDir(), jobName, runId, 'meta.json');
203
225
  if (!fs.existsSync(metaPath))
@@ -209,9 +231,11 @@ export function readRunMeta(jobName, runId) {
209
231
  return null;
210
232
  }
211
233
  }
234
+ /** Get the filesystem path for a specific run's directory. */
212
235
  export function getRunDir(jobName, runId) {
213
236
  return path.join(getRunsDir(), jobName, runId);
214
237
  }
238
+ /** Discover routine YAML files in a repository's routines/ directory. */
215
239
  export function discoverJobsFromRepo(repoPath) {
216
240
  const jobsPath = path.join(repoPath, 'routines');
217
241
  if (!fs.existsSync(jobsPath))
@@ -223,13 +247,15 @@ export function discoverJobsFromRepo(repoPath) {
223
247
  path: path.join(jobsPath, f),
224
248
  }));
225
249
  }
250
+ /** Check whether a job with the given name exists on disk. */
226
251
  export function jobExists(name) {
227
252
  return readJob(name) !== null;
228
253
  }
254
+ /** Get the filesystem path of a job's YAML config file, or null if not found. */
229
255
  export function getJobPath(name) {
230
256
  const jobsDir = getRoutinesDir();
231
257
  for (const ext of ['.yml', '.yaml']) {
232
- const filePath = path.join(jobsDir, name + ext);
258
+ const filePath = safeJoin(jobsDir, name + ext);
233
259
  if (fs.existsSync(filePath)) {
234
260
  return filePath;
235
261
  }
@@ -282,6 +308,7 @@ export function parseAtTime(atTime) {
282
308
  }
283
309
  return null;
284
310
  }
311
+ /** Check if an installed job's normalized YAML matches the source file. */
285
312
  export function jobContentMatches(name, sourcePath) {
286
313
  const existing = readJob(name);
287
314
  if (!existing)
@@ -300,6 +327,7 @@ export function jobContentMatches(name, sourcePath) {
300
327
  return false;
301
328
  }
302
329
  }
330
+ /** Install a job by reading and validating a YAML source file. */
303
331
  export function installJobFromSource(sourcePath, name) {
304
332
  try {
305
333
  const content = fs.readFileSync(sourcePath, 'utf-8');
@@ -322,4 +350,3 @@ export function installJobFromSource(sourcePath, name) {
322
350
  return { success: false, error: err.message };
323
351
  }
324
352
  }
325
- //# sourceMappingURL=routines.js.map