@phnx-labs/agents-cli 1.12.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 (496) hide show
  1. package/CHANGELOG.md +7 -1
  2. package/README.md +293 -300
  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 +511 -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 +79 -0
  180. package/dist/lib/rotate.js +285 -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
@@ -0,0 +1,285 @@
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';
10
+ import { getAccountInfo } from './agents.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
+ }
114
+ /**
115
+ * Pure selection: given a set of candidates, return the best one for the
116
+ * next run. Kept separate from I/O so it can be unit-tested with fixtures.
117
+ *
118
+ * Eligibility: signed in (email present) and not out of credits.
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.
130
+ */
131
+ export function pickRotateCandidate(candidates) {
132
+ const healthy = [];
133
+ const excluded = [];
134
+ for (const c of candidates) {
135
+ if (!isRotationEligible(c)) {
136
+ excluded.push(c);
137
+ continue;
138
+ }
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))
147
+ excluded.push(c);
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)) {
161
+ excluded.push(c);
162
+ continue;
163
+ }
164
+ healthy.push(c);
165
+ }
166
+ if (healthy.length === 0)
167
+ return null;
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 };
178
+ }
179
+ async function collectRunCandidates(agent) {
180
+ const versions = listInstalledVersions(agent);
181
+ const rows = await Promise.all(versions.map(async (version) => {
182
+ const home = getVersionHomePath(agent, version);
183
+ const info = await getAccountInfo(agent, home);
184
+ const authValid = info.email
185
+ ? agent === 'claude' ? await isClaudeAuthValid(home) : true
186
+ : false;
187
+ return {
188
+ agent,
189
+ version,
190
+ home,
191
+ info,
192
+ email: info.email,
193
+ usageStatus: info.usageStatus,
194
+ authValid,
195
+ lastActive: info.lastActive,
196
+ };
197
+ }));
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);
231
+ }
232
+ /**
233
+ * Resolve the version `agents run` should use when the caller did not pin
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.
237
+ */
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);
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);
282
+ return { version: rotation.picked.version, rotation };
283
+ }
284
+ return { version: fallback, rotation: null };
285
+ }
@@ -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
@@ -1,12 +1,25 @@
1
+ /**
2
+ * Job execution engine for routines.
3
+ *
4
+ * Builds agent-specific CLI commands from job configs, spawns them with
5
+ * sandboxed or unsandboxed environments, captures stdout to log files,
6
+ * enforces timeouts, and extracts the final assistant report from the
7
+ * agent's stream-JSON output.
8
+ */
1
9
  import type { JobConfig, RunMeta } from './routines.js';
2
10
  import type { AgentId } from './types.js';
11
+ /** Result of a completed job execution, including metadata and optional report. */
3
12
  export interface RunResult {
4
13
  meta: RunMeta;
5
14
  reportPath: string | null;
6
15
  }
16
+ /** Build the full CLI argv for executing a job, applying mode, model, and permission flags. */
7
17
  export declare function buildJobCommand(config: JobConfig, resolvedPrompt: string): string[];
18
+ /** Execute a job synchronously (waits for completion or timeout before resolving). */
8
19
  export declare function executeJob(config: JobConfig): Promise<RunResult>;
20
+ /** Spawn a job as a detached process and return immediately with run metadata. */
9
21
  export declare function executeJobDetached(config: JobConfig): Promise<RunMeta>;
22
+ /** Extract the final assistant message from a stream-JSON log file as a markdown report. */
10
23
  export declare function extractReport(stdoutPath: string, agentType: AgentId): string | null;
24
+ /** Scan all runs marked "running" and finalize any whose process has exited. */
11
25
  export declare function monitorRunningJobs(): void;
12
- //# sourceMappingURL=runner.d.ts.map
@@ -1,3 +1,11 @@
1
+ /**
2
+ * Job execution engine for routines.
3
+ *
4
+ * Builds agent-specific CLI commands from job configs, spawns them with
5
+ * sandboxed or unsandboxed environments, captures stdout to log files,
6
+ * enforces timeouts, and extracts the final assistant report from the
7
+ * agent's stream-JSON output.
8
+ */
1
9
  import { spawn } from 'child_process';
2
10
  import * as fs from 'fs';
3
11
  import * as path from 'path';
@@ -6,11 +14,13 @@ import { resolveJobPrompt, parseTimeout, writeRunMeta, getRunDir, } from './rout
6
14
  import { getRunsDir } from './state.js';
7
15
  import { prepareJobHome, buildSpawnEnv } from './sandbox.js';
8
16
  import { resolveModel, buildReasoningFlags } from './models.js';
17
+ /** CLI command templates per agent, with {prompt} as a placeholder. */
9
18
  const AGENT_COMMANDS = {
10
19
  claude: ['claude', '-p', '--verbose', '{prompt}', '--output-format', 'stream-json', '--permission-mode', 'plan'],
11
20
  codex: ['codex', 'exec', '--sandbox', 'workspace-write', '{prompt}', '--json'],
12
21
  gemini: ['gemini', '{prompt}', '--output-format', 'stream-json'],
13
22
  };
23
+ /** Build the full CLI argv for executing a job, applying mode, model, and permission flags. */
14
24
  export function buildJobCommand(config, resolvedPrompt) {
15
25
  const template = AGENT_COMMANDS[config.agent];
16
26
  if (!template) {
@@ -31,6 +41,12 @@ export function buildJobCommand(config, resolvedPrompt) {
31
41
  }
32
42
  if (config.allow?.dirs) {
33
43
  for (const dir of config.allow.dirs) {
44
+ // Reject leading '-' so a routine YAML can't smuggle an argv flag like
45
+ // `--dangerously-skip-permissions` past the sandbox by hiding it as an
46
+ // allow.dirs entry.
47
+ if (dir.startsWith('-')) {
48
+ throw new Error(`allow.dirs entries must not start with '-': ${JSON.stringify(dir)}`);
49
+ }
34
50
  const resolved = dir.replace(/^~/, os.homedir());
35
51
  cmd.push('--add-dir', resolved);
36
52
  }
@@ -89,6 +105,7 @@ function appendModelAndReasoning(cmd, config) {
89
105
  function generateRunId() {
90
106
  return new Date().toISOString().replace(/[:.]/g, '-');
91
107
  }
108
+ /** Execute a job synchronously (waits for completion or timeout before resolving). */
92
109
  export async function executeJob(config) {
93
110
  const resolvedPrompt = resolveJobPrompt(config);
94
111
  const cmd = buildJobCommand(config, resolvedPrompt);
@@ -98,7 +115,7 @@ export async function executeJob(config) {
98
115
  const runDir = getRunDir(config.name, runId);
99
116
  fs.mkdirSync(runDir, { recursive: true });
100
117
  const stdoutPath = path.join(runDir, 'stdout.log');
101
- const stdoutFd = fs.openSync(stdoutPath, 'w');
118
+ const stdoutFd = fs.openSync(stdoutPath, 'w', 0o600);
102
119
  let spawnEnv = useSandbox ? buildSpawnEnv(overlayHome) : { ...process.env };
103
120
  if (config.timezone) {
104
121
  spawnEnv.TZ = config.timezone;
@@ -179,6 +196,7 @@ export async function executeJob(config) {
179
196
  child.unref();
180
197
  });
181
198
  }
199
+ /** Spawn a job as a detached process and return immediately with run metadata. */
182
200
  export async function executeJobDetached(config) {
183
201
  const resolvedPrompt = resolveJobPrompt(config);
184
202
  const cmd = buildJobCommand(config, resolvedPrompt);
@@ -188,7 +206,7 @@ export async function executeJobDetached(config) {
188
206
  const runDir = getRunDir(config.name, runId);
189
207
  fs.mkdirSync(runDir, { recursive: true });
190
208
  const stdoutPath = path.join(runDir, 'stdout.log');
191
- const stdoutFd = fs.openSync(stdoutPath, 'w');
209
+ const stdoutFd = fs.openSync(stdoutPath, 'w', 0o600);
192
210
  let spawnEnv = useSandbox ? buildSpawnEnv(overlayHome) : { ...process.env };
193
211
  if (config.timezone) {
194
212
  spawnEnv.TZ = config.timezone;
@@ -233,6 +251,7 @@ function extractAndSaveReport(stdoutPath, agentType, runDir) {
233
251
  }
234
252
  return null;
235
253
  }
254
+ /** Extract the final assistant message from a stream-JSON log file as a markdown report. */
236
255
  export function extractReport(stdoutPath, agentType) {
237
256
  if (!fs.existsSync(stdoutPath))
238
257
  return null;
@@ -273,6 +292,7 @@ export function extractReport(stdoutPath, agentType) {
273
292
  return null;
274
293
  }
275
294
  }
295
+ /** Scan all runs marked "running" and finalize any whose process has exited. */
276
296
  export function monitorRunningJobs() {
277
297
  const runsDir = getRunsDir();
278
298
  if (!fs.existsSync(runsDir))
@@ -308,4 +328,3 @@ export function monitorRunningJobs() {
308
328
  }
309
329
  }
310
330
  }
311
- //# sourceMappingURL=runner.js.map
@@ -1,10 +1,25 @@
1
+ /**
2
+ * Sandbox environment for routine job execution.
3
+ *
4
+ * Creates an overlay HOME directory per job with symlinked allowed
5
+ * directories and agent-specific config files (permissions, settings).
6
+ * The spawned agent process sees only the overlay, limiting filesystem
7
+ * access to explicitly allowed paths.
8
+ */
1
9
  import type { JobConfig } from './routines.js';
10
+ /** Build a restricted environment for a sandboxed process, setting HOME to the overlay. */
2
11
  export declare function buildSpawnEnv(overlayHome: string, extraEnv?: Record<string, string>): Record<string, string>;
12
+ /** Get the overlay HOME directory path for a named job. */
3
13
  export declare function getJobHomePath(name: string): string;
14
+ /** Create a fresh overlay HOME for a job, including agent config and allowed-dir symlinks. */
4
15
  export declare function prepareJobHome(config: JobConfig): string;
16
+ /** Remove a job's overlay HOME directory entirely. */
5
17
  export declare function cleanJobHome(name: string): void;
18
+ /** Symlink allowed directories into the overlay HOME, skipping paths outside the real HOME. */
6
19
  export declare function symlinkAllowedDirs(overlayHome: string, dirs: string[]): void;
20
+ /** Generate a Claude settings.json in the overlay with scoped permissions from the job config. */
7
21
  export declare function generateClaudeConfig(overlayHome: string, config: JobConfig): void;
22
+ /** Generate a Codex config.toml in the overlay with model and approval-mode settings. */
8
23
  export declare function generateCodexConfig(overlayHome: string, config: JobConfig): void;
24
+ /** Generate a Gemini settings.json in the overlay from the job's config block. */
9
25
  export declare function generateGeminiConfig(overlayHome: string, config: JobConfig): void;
10
- //# sourceMappingURL=sandbox.d.ts.map