@phnx-labs/agents-cli 1.22.39 → 1.22.41

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 (569) hide show
  1. package/CHANGELOG.md +316 -0
  2. package/README.md +116 -70
  3. package/dist/bin/agents +0 -0
  4. package/dist/bootstrap.js +45 -27
  5. package/dist/browser.js +2 -2
  6. package/dist/cli/command-registry.d.ts +135 -0
  7. package/dist/cli/command-registry.js +259 -0
  8. package/dist/commands/accounts.d.ts +20 -0
  9. package/dist/commands/accounts.js +186 -25
  10. package/dist/commands/apply.d.ts +3 -3
  11. package/dist/commands/apply.js +20 -63
  12. package/dist/commands/browser.d.ts +15 -0
  13. package/dist/commands/browser.js +318 -131
  14. package/dist/commands/budget.d.ts +7 -6
  15. package/dist/commands/budget.js +8 -7
  16. package/dist/commands/cloud.js +17 -20
  17. package/dist/commands/commands.js +1 -1
  18. package/dist/commands/computer-actions.d.ts +1 -35
  19. package/dist/commands/computer-actions.js +13 -181
  20. package/dist/commands/computer.d.ts +28 -3
  21. package/dist/commands/computer.js +93 -65
  22. package/dist/commands/config.js +16 -3
  23. package/dist/commands/cost.d.ts +2 -1
  24. package/dist/commands/cost.js +7 -6
  25. package/dist/commands/daemon.js +151 -4
  26. package/dist/commands/detach.js +1 -1
  27. package/dist/commands/doctor.js +19 -11
  28. package/dist/commands/events.js +1 -1
  29. package/dist/commands/exec.d.ts +2 -50
  30. package/dist/commands/exec.js +160 -215
  31. package/dist/commands/factory.js +1 -1
  32. package/dist/commands/feed.d.ts +2 -2
  33. package/dist/commands/feed.js +12 -23
  34. package/dist/commands/fleet-capture.js +25 -27
  35. package/dist/commands/focus.d.ts +2 -3
  36. package/dist/commands/focus.js +34 -9
  37. package/dist/commands/go.js +15 -5
  38. package/dist/commands/harness.d.ts +3 -3
  39. package/dist/commands/harness.js +53 -5
  40. package/dist/commands/hooks.js +1 -1
  41. package/dist/commands/import.js +2 -2
  42. package/dist/commands/insights.d.ts +5 -5
  43. package/dist/commands/insights.js +15 -9
  44. package/dist/commands/inspect.d.ts +2 -3
  45. package/dist/commands/inspect.js +4 -16
  46. package/dist/commands/logs.d.ts +2 -2
  47. package/dist/commands/logs.js +9 -9
  48. package/dist/commands/mcp.js +2 -2
  49. package/dist/commands/memory.js +1 -1
  50. package/dist/commands/message.d.ts +1 -1
  51. package/dist/commands/message.js +7 -7
  52. package/dist/commands/mine.d.ts +11 -8
  53. package/dist/commands/mine.js +11 -10
  54. package/dist/commands/models.js +1 -1
  55. package/dist/commands/modes.js +1 -1
  56. package/dist/commands/monitors.js +23 -6
  57. package/dist/commands/output.d.ts +7 -6
  58. package/dist/commands/output.js +11 -10
  59. package/dist/commands/packages.js +4 -4
  60. package/dist/commands/perf.js +1 -1
  61. package/dist/commands/permissions.js +49 -32
  62. package/dist/commands/plugins.d.ts +1 -1
  63. package/dist/commands/plugins.js +3 -3
  64. package/dist/commands/profiles.d.ts +6 -9
  65. package/dist/commands/profiles.js +8 -321
  66. package/dist/commands/projects.d.ts +9 -0
  67. package/dist/commands/projects.js +140 -8
  68. package/dist/commands/prune.js +5 -13
  69. package/dist/commands/refresh-rules.js +1 -1
  70. package/dist/commands/repo.d.ts +5 -7
  71. package/dist/commands/repo.js +34 -18
  72. package/dist/commands/resource-view.js +4 -0
  73. package/dist/commands/resume.d.ts +11 -7
  74. package/dist/commands/resume.js +82 -98
  75. package/dist/commands/route.d.ts +12 -0
  76. package/dist/commands/route.js +261 -0
  77. package/dist/commands/routines.d.ts +2 -3
  78. package/dist/commands/routines.js +120 -145
  79. package/dist/commands/rules.js +1 -1
  80. package/dist/commands/run-account-picker.d.ts +1 -1
  81. package/dist/commands/run-account-picker.js +2 -2
  82. package/dist/commands/run-broadcast.d.ts +21 -0
  83. package/dist/commands/run-broadcast.js +89 -0
  84. package/dist/commands/run-cloud.js +1 -1
  85. package/dist/commands/secrets-vault.d.ts +10 -0
  86. package/dist/commands/{login.js → secrets-vault.js} +34 -14
  87. package/dist/commands/secrets.d.ts +4 -4
  88. package/dist/commands/secrets.js +158 -159
  89. package/dist/commands/sessions-backfill.js +1 -1
  90. package/dist/commands/sessions-browser.d.ts +1 -1
  91. package/dist/commands/sessions-browser.js +9 -5
  92. package/dist/commands/sessions-export.js +2 -2
  93. package/dist/commands/sessions-inject.js +4 -5
  94. package/dist/commands/sessions-migrate.js +16 -27
  95. package/dist/commands/sessions-picker.d.ts +14 -0
  96. package/dist/commands/sessions-picker.js +209 -13
  97. package/dist/commands/sessions-resume.d.ts +7 -3
  98. package/dist/commands/sessions-resume.js +81 -33
  99. package/dist/commands/sessions-share.d.ts +25 -0
  100. package/dist/commands/sessions-share.js +166 -0
  101. package/dist/commands/sessions-stats.js +2 -2
  102. package/dist/commands/sessions.d.ts +75 -68
  103. package/dist/commands/sessions.js +144 -180
  104. package/dist/commands/setup-browser.js +1 -1
  105. package/dist/commands/setup-computer.js +1 -1
  106. package/dist/commands/setup-fleet.js +3 -0
  107. package/dist/commands/setup-mine.d.ts +7 -3
  108. package/dist/commands/setup-mine.js +13 -8
  109. package/dist/commands/setup-preferences.js +2 -2
  110. package/dist/commands/setup-secrets.js +2 -2
  111. package/dist/commands/setup-watchdog.js +2 -2
  112. package/dist/commands/setup.js +7 -2
  113. package/dist/commands/share.d.ts +65 -0
  114. package/dist/commands/share.js +253 -20
  115. package/dist/commands/skills.js +3 -3
  116. package/dist/commands/snapshot.d.ts +2 -2
  117. package/dist/commands/snapshot.js +9 -9
  118. package/dist/commands/ssh.d.ts +1 -1
  119. package/dist/commands/ssh.js +186 -64
  120. package/dist/commands/subagents.js +1 -1
  121. package/dist/commands/sync.js +24 -9
  122. package/dist/commands/teams.d.ts +2 -2
  123. package/dist/commands/teams.js +9 -18
  124. package/dist/commands/tmux.js +5 -1
  125. package/dist/commands/trash.js +1 -1
  126. package/dist/commands/usage.d.ts +1 -1
  127. package/dist/commands/usage.js +2 -2
  128. package/dist/commands/utils.d.ts +4 -14
  129. package/dist/commands/utils.js +6 -27
  130. package/dist/commands/versions.js +2 -2
  131. package/dist/commands/view.d.ts +9 -77
  132. package/dist/commands/view.js +23 -8
  133. package/dist/commands/watchdog.js +1 -1
  134. package/dist/commands/webhook.js +25 -34
  135. package/dist/commands/workflows.js +1 -1
  136. package/dist/index.js +1 -1
  137. package/dist/lib/account-capabilities.d.ts +39 -0
  138. package/dist/lib/account-capabilities.js +59 -0
  139. package/dist/lib/account-catalog.js +1 -1
  140. package/dist/lib/account-registry.d.ts +66 -0
  141. package/dist/lib/account-registry.js +151 -5
  142. package/dist/lib/{rotate.d.ts → accounting/rotate.d.ts} +4 -4
  143. package/dist/lib/{rotate.js → accounting/rotate.js} +8 -8
  144. package/dist/lib/{usage.d.ts → accounting/usage.d.ts} +4 -4
  145. package/dist/lib/{usage.js → accounting/usage.js} +11 -11
  146. package/dist/lib/agent-spec/provider.js +1 -1
  147. package/dist/lib/agents.d.ts +72 -4
  148. package/dist/lib/agents.js +231 -199
  149. package/dist/lib/answer-router.d.ts +2 -2
  150. package/dist/lib/ask-classifier.d.ts +1 -1
  151. package/dist/lib/ask-classifier.js +1 -1
  152. package/dist/lib/audit/log.js +1 -1
  153. package/dist/lib/auth-health.d.ts +1 -1
  154. package/dist/lib/auth-health.js +2 -2
  155. package/dist/lib/brand.js +1 -1
  156. package/dist/lib/browser/caller-identity.d.ts +28 -0
  157. package/dist/lib/browser/caller-identity.js +156 -0
  158. package/dist/lib/browser/cdp.js +5 -1
  159. package/dist/lib/browser/chrome.js +12 -1
  160. package/dist/lib/browser/drivers/ssh.d.ts +1 -1
  161. package/dist/lib/browser/drivers/ssh.js +3 -2
  162. package/dist/lib/browser/hygiene.d.ts +10 -2
  163. package/dist/lib/browser/hygiene.js +7 -4
  164. package/dist/lib/browser/ipc.d.ts +22 -2
  165. package/dist/lib/browser/ipc.js +185 -21
  166. package/dist/lib/browser/profiles.d.ts +69 -5
  167. package/dist/lib/browser/profiles.js +135 -13
  168. package/dist/lib/browser/remote-control.d.ts +2 -2
  169. package/dist/lib/browser/remote-control.js +3 -3
  170. package/dist/lib/browser/runtime-state.d.ts +79 -0
  171. package/dist/lib/browser/runtime-state.js +119 -1
  172. package/dist/lib/browser/service.d.ts +137 -2
  173. package/dist/lib/browser/service.js +492 -54
  174. package/dist/lib/browser/sessions-list.d.ts +2 -1
  175. package/dist/lib/browser/sessions-list.js +4 -13
  176. package/dist/lib/browser/types.d.ts +19 -1
  177. package/dist/lib/budget/config.js +1 -1
  178. package/dist/lib/budget/ledger.js +1 -1
  179. package/dist/lib/byok-usage.js +1 -1
  180. package/dist/lib/capabilities.js +3 -15
  181. package/dist/lib/catchup.d.ts +1 -1
  182. package/dist/lib/catchup.js +1 -1
  183. package/dist/lib/cloud/dispatch.js +1 -1
  184. package/dist/lib/cloud/host.d.ts +3 -3
  185. package/dist/lib/cloud/host.js +5 -5
  186. package/dist/lib/cloud/rush.d.ts +9 -21
  187. package/dist/lib/cloud/rush.js +33 -120
  188. package/dist/lib/cloud/types.d.ts +2 -2
  189. package/dist/lib/commands.js +3 -13
  190. package/dist/lib/computer/actions.d.ts +36 -0
  191. package/dist/lib/computer/actions.js +162 -0
  192. package/dist/lib/computer/dispatch.d.ts +2 -2
  193. package/dist/lib/computer/dispatch.js +2 -2
  194. package/dist/lib/computer/sessions-list.d.ts +3 -3
  195. package/dist/lib/computer/sessions-list.js +2 -2
  196. package/dist/lib/config-keys.d.ts +2 -1
  197. package/dist/lib/config-keys.js +8 -4
  198. package/dist/lib/config-machine-keys.d.ts +4 -2
  199. package/dist/lib/config-machine-keys.js +5 -2
  200. package/dist/lib/crabbox/lease.js +9 -1
  201. package/dist/lib/crabbox/runtimes.d.ts +32 -7
  202. package/dist/lib/crabbox/runtimes.js +72 -30
  203. package/dist/lib/{daemon.d.ts → daemon/daemon.d.ts} +59 -1
  204. package/dist/lib/{daemon.js → daemon/daemon.js} +237 -49
  205. package/dist/lib/daemon-services.d.ts +1 -1
  206. package/dist/lib/daemon-services.js +5 -0
  207. package/dist/lib/daemon-ticks.d.ts +25 -0
  208. package/dist/lib/daemon-ticks.js +31 -1
  209. package/dist/lib/daemon-webhooks.d.ts +104 -0
  210. package/dist/lib/daemon-webhooks.js +215 -0
  211. package/dist/lib/device-config.d.ts +85 -75
  212. package/dist/lib/device-config.js +280 -142
  213. package/dist/lib/devices/config-migration.d.ts +29 -34
  214. package/dist/lib/devices/config-migration.js +209 -130
  215. package/dist/lib/devices/connect.d.ts +2 -2
  216. package/dist/lib/devices/connect.js +2 -2
  217. package/dist/lib/devices/discovery-policy.d.ts +30 -0
  218. package/dist/lib/devices/discovery-policy.js +101 -0
  219. package/dist/lib/devices/fleet-inventory.js +8 -3
  220. package/dist/lib/devices/harness-inventory.d.ts +1 -1
  221. package/dist/lib/devices/harness-inventory.js +12 -3
  222. package/dist/lib/devices/known-hosts.js +1 -1
  223. package/dist/lib/devices/pool.d.ts +10 -5
  224. package/dist/lib/devices/pool.js +5 -7
  225. package/dist/lib/devices/registry.d.ts +1 -1
  226. package/dist/lib/devices/registry.js +1 -1
  227. package/dist/lib/devices/resolve-profile.d.ts +2 -2
  228. package/dist/lib/devices/resolve-profile.js +2 -2
  229. package/dist/lib/devices/resolve-target.d.ts +1 -1
  230. package/dist/lib/devices/resolve-target.js +4 -4
  231. package/dist/lib/devices/self-host.d.ts +1 -1
  232. package/dist/lib/devices/self-host.js +3 -3
  233. package/dist/lib/devices/ssh-config.d.ts +1 -1
  234. package/dist/lib/devices/stats-cache.js +1 -1
  235. package/dist/lib/devices/sync.d.ts +3 -1
  236. package/dist/lib/devices/sync.js +3 -3
  237. package/dist/lib/doctor-diff.js +4 -4
  238. package/dist/lib/drift-sync.js +2 -2
  239. package/dist/lib/drift.js +2 -2
  240. package/dist/lib/event-families.d.ts +1 -1
  241. package/dist/lib/event-stream.d.ts +1 -1
  242. package/dist/lib/event-stream.js +2 -2
  243. package/dist/lib/events-ingest.js +2 -2
  244. package/dist/lib/exec.d.ts +4 -4
  245. package/dist/lib/exec.js +11 -11
  246. package/dist/lib/factory/snapshot.d.ts +1 -1
  247. package/dist/lib/factory/snapshot.js +1 -1
  248. package/dist/lib/{activity.d.ts → feed/activity.d.ts} +1 -1
  249. package/dist/lib/{activity.js → feed/activity.js} +7 -7
  250. package/dist/lib/{events.d.ts → feed/events.d.ts} +2 -2
  251. package/dist/lib/{events.js → feed/events.js} +5 -5
  252. package/dist/lib/{feed.js → feed/feed.js} +4 -4
  253. package/dist/lib/feed-outcome.d.ts +1 -1
  254. package/dist/lib/feed-policy.d.ts +1 -1
  255. package/dist/lib/feed-policy.js +1 -1
  256. package/dist/lib/feed-post.d.ts +1 -1
  257. package/dist/lib/feed-post.js +1 -1
  258. package/dist/lib/feed-ranking.d.ts +1 -1
  259. package/dist/lib/fleet/apply.d.ts +0 -6
  260. package/dist/lib/fleet/apply.js +18 -45
  261. package/dist/lib/fleet/auth-sync.d.ts +16 -35
  262. package/dist/lib/fleet/auth-sync.js +16 -75
  263. package/dist/lib/fleet/capture.js +8 -6
  264. package/dist/lib/fleet/manifest.js +23 -11
  265. package/dist/lib/fleet/types.d.ts +19 -7
  266. package/dist/lib/fleet-cache.d.ts +1 -1
  267. package/dist/lib/fleet-cache.js +1 -1
  268. package/dist/lib/format.d.ts +19 -0
  269. package/dist/lib/format.js +44 -1
  270. package/dist/lib/friction-heuristics.d.ts +1 -1
  271. package/dist/lib/git.d.ts +24 -1
  272. package/dist/lib/git.js +82 -38
  273. package/dist/lib/heal.js +3 -3
  274. package/dist/lib/hooks.d.ts +18 -0
  275. package/dist/lib/hooks.js +113 -1
  276. package/dist/lib/hosts/credentials.d.ts +30 -10
  277. package/dist/lib/hosts/credentials.js +38 -26
  278. package/dist/lib/hosts/dispatch.d.ts +3 -3
  279. package/dist/lib/hosts/dispatch.js +3 -3
  280. package/dist/lib/hosts/option.d.ts +3 -3
  281. package/dist/lib/hosts/option.js +7 -8
  282. package/dist/lib/hosts/passthrough.d.ts +17 -17
  283. package/dist/lib/hosts/passthrough.js +67 -50
  284. package/dist/lib/hosts/providers/devices.d.ts +1 -1
  285. package/dist/lib/hosts/providers/devices.js +1 -1
  286. package/dist/lib/hosts/reconcile.d.ts +1 -1
  287. package/dist/lib/hosts/reconcile.js +1 -1
  288. package/dist/lib/hosts/reconnect.d.ts +1 -1
  289. package/dist/lib/hosts/reconnect.js +2 -2
  290. package/dist/lib/hosts/registry.d.ts +5 -5
  291. package/dist/lib/hosts/registry.js +5 -5
  292. package/dist/lib/hosts/remote-cmd.d.ts +10 -10
  293. package/dist/lib/hosts/remote-cmd.js +25 -18
  294. package/dist/lib/hosts/remote-os.d.ts +4 -4
  295. package/dist/lib/hosts/remote-os.js +4 -4
  296. package/dist/lib/hosts/remote-session-id.d.ts +2 -2
  297. package/dist/lib/hosts/remote-session-id.js +2 -2
  298. package/dist/lib/hosts/routing-flag.d.ts +3 -3
  299. package/dist/lib/hosts/routing-flag.js +4 -5
  300. package/dist/lib/hosts/run-target.d.ts +4 -4
  301. package/dist/lib/hosts/run-target.js +4 -4
  302. package/dist/lib/hosts/session-index.d.ts +2 -2
  303. package/dist/lib/hosts/session-index.js +1 -1
  304. package/dist/lib/hosts/session-marker.d.ts +1 -1
  305. package/dist/lib/hosts/session-marker.js +1 -1
  306. package/dist/lib/hosts/types.d.ts +2 -2
  307. package/dist/lib/hosts/types.js +2 -2
  308. package/dist/lib/import.js +1 -1
  309. package/dist/lib/{migrate.d.ts → installations/migrate.d.ts} +13 -1
  310. package/dist/lib/{migrate.js → installations/migrate.js} +160 -40
  311. package/dist/lib/installations/resolve.js +1 -1
  312. package/dist/lib/installations/strategies.js +1 -1
  313. package/dist/lib/installations/update.js +2 -2
  314. package/dist/lib/{versions.d.ts → installations/versions.d.ts} +12 -3
  315. package/dist/lib/{versions.js → installations/versions.js} +51 -31
  316. package/dist/lib/isolation-boundary-report.js +1 -1
  317. package/dist/lib/linear-projects.d.ts +28 -0
  318. package/dist/lib/linear-projects.js +30 -0
  319. package/dist/lib/loop.js +1 -1
  320. package/dist/lib/mailbox-gc.js +1 -1
  321. package/dist/lib/mailbox.js +1 -1
  322. package/dist/lib/mcp-registry.d.ts +62 -0
  323. package/dist/lib/mcp-registry.js +177 -0
  324. package/dist/lib/mcp.d.ts +5 -0
  325. package/dist/lib/mcp.js +124 -307
  326. package/dist/lib/menubar/MenubarHelper.app/Contents/CodeResources +0 -0
  327. package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
  328. package/dist/lib/menubar/install-menubar.d.ts +7 -0
  329. package/dist/lib/menubar/install-menubar.js +24 -6
  330. package/dist/lib/menubar/snapshot.d.ts +7 -0
  331. package/dist/lib/menubar/snapshot.js +8 -6
  332. package/dist/lib/models.js +1 -1
  333. package/dist/lib/monitors/config.d.ts +12 -0
  334. package/dist/lib/monitors/config.js +3 -0
  335. package/dist/lib/monitors/dispatch.js +26 -5
  336. package/dist/lib/monitors/engine.js +10 -0
  337. package/dist/lib/monitors/sources/webhook.d.ts +1 -1
  338. package/dist/lib/monitors/state.d.ts +42 -0
  339. package/dist/lib/monitors/state.js +30 -0
  340. package/dist/lib/notify.d.ts +1 -1
  341. package/dist/lib/observe-aliases.d.ts +3 -3
  342. package/dist/lib/observe-aliases.js +3 -21
  343. package/dist/lib/output/git-output.js +2 -2
  344. package/dist/lib/overdue.d.ts +1 -1
  345. package/dist/lib/overdue.js +1 -1
  346. package/dist/lib/permissions-registry.d.ts +65 -0
  347. package/dist/lib/permissions-registry.js +599 -0
  348. package/dist/lib/permissions.d.ts +24 -13
  349. package/dist/lib/permissions.js +52 -271
  350. package/dist/lib/picker.d.ts +16 -0
  351. package/dist/lib/picker.js +33 -3
  352. package/dist/lib/placement.d.ts +1 -1
  353. package/dist/lib/placement.js +4 -4
  354. package/dist/lib/platform/paths.d.ts +8 -0
  355. package/dist/lib/platform/paths.js +11 -0
  356. package/dist/lib/platform/posixpath.js +3 -3
  357. package/dist/lib/{plugin-marketplace.d.ts → plugins/plugin-marketplace.d.ts} +1 -1
  358. package/dist/lib/{plugin-marketplace.js → plugins/plugin-marketplace.js} +2 -2
  359. package/dist/lib/{plugins.d.ts → plugins/plugins.d.ts} +1 -1
  360. package/dist/lib/{plugins.js → plugins/plugins.js} +7 -7
  361. package/dist/lib/{skills.d.ts → plugins/skills.d.ts} +1 -1
  362. package/dist/lib/{skills.js → plugins/skills.js} +7 -7
  363. package/dist/lib/pricing/cost.d.ts +1 -1
  364. package/dist/lib/pricing/cost.js +1 -1
  365. package/dist/lib/profiles-presets.d.ts +1 -1
  366. package/dist/lib/profiles-presets.js +1 -1
  367. package/dist/lib/profiles.js +2 -2
  368. package/dist/lib/project-import.js +4 -1
  369. package/dist/lib/project-key.js +7 -0
  370. package/dist/lib/project-launch.d.ts +1 -1
  371. package/dist/lib/project-launch.js +3 -3
  372. package/dist/lib/project-pull.d.ts +128 -0
  373. package/dist/lib/project-pull.js +384 -0
  374. package/dist/lib/project-root.d.ts +2 -2
  375. package/dist/lib/project-root.js +2 -2
  376. package/dist/lib/project-status.js +1 -1
  377. package/dist/lib/projects.d.ts +23 -0
  378. package/dist/lib/projects.js +29 -6
  379. package/dist/lib/refresh.d.ts +12 -1
  380. package/dist/lib/refresh.js +16 -9
  381. package/dist/lib/registry.d.ts +9 -2
  382. package/dist/lib/registry.js +11 -4
  383. package/dist/lib/resources.d.ts +2 -2
  384. package/dist/lib/resources.js +2 -2
  385. package/dist/lib/routers.d.ts +81 -0
  386. package/dist/lib/routers.js +153 -0
  387. package/dist/lib/routine-context.d.ts +1 -0
  388. package/dist/lib/routine-context.js +7 -2
  389. package/dist/lib/routine-notify-owner.d.ts +1 -1
  390. package/dist/lib/routine-notify.d.ts +1 -1
  391. package/dist/lib/routine-notify.js +1 -1
  392. package/dist/lib/routine-process-cleanup.d.ts +1 -1
  393. package/dist/lib/routine-readiness.d.ts +1 -1
  394. package/dist/lib/routine-readiness.js +11 -4
  395. package/dist/lib/routines-placement.d.ts +12 -2
  396. package/dist/lib/routines-placement.js +20 -3
  397. package/dist/lib/routines-project.d.ts +1 -1
  398. package/dist/lib/routines-project.js +1 -1
  399. package/dist/lib/rules/compile.d.ts +1 -0
  400. package/dist/lib/rules/compile.js +10 -2
  401. package/dist/lib/rules/rules.js +1 -1
  402. package/dist/lib/run-notify.js +1 -1
  403. package/dist/lib/runner.d.ts +80 -2
  404. package/dist/lib/runner.js +261 -67
  405. package/dist/lib/sandbox.d.ts +1 -1
  406. package/dist/lib/scheduler.d.ts +1 -1
  407. package/dist/lib/scheduler.js +1 -1
  408. package/dist/lib/{routines.d.ts → scheduling/routines.d.ts} +54 -9
  409. package/dist/lib/{routines.js → scheduling/routines.js} +173 -14
  410. package/dist/lib/secrets/Agents CLI.app/Contents/CodeResources +0 -0
  411. package/dist/lib/secrets/Agents CLI.app/Contents/MacOS/Agents CLI +0 -0
  412. package/dist/lib/secrets/agent.js +2 -2
  413. package/dist/lib/secrets/audit.js +1 -1
  414. package/dist/lib/secrets/bundles.d.ts +4 -4
  415. package/dist/lib/secrets/bundles.js +8 -8
  416. package/dist/lib/secrets/headless.d.ts +16 -0
  417. package/dist/lib/secrets/headless.js +21 -0
  418. package/dist/lib/secrets/index.js +1 -1
  419. package/dist/lib/secrets/list-filter.d.ts +1 -1
  420. package/dist/lib/secrets/list-filter.js +2 -2
  421. package/dist/lib/secrets/push.d.ts +1 -1
  422. package/dist/lib/secrets/push.js +10 -12
  423. package/dist/lib/secrets/remote.d.ts +21 -17
  424. package/dist/lib/secrets/remote.js +39 -23
  425. package/dist/lib/secrets/vault.js +2 -2
  426. package/dist/lib/self-heal/checks/shadowing.js +1 -1
  427. package/dist/lib/self-heal/checks/shims.js +1 -1
  428. package/dist/lib/self-update.d.ts +39 -4
  429. package/dist/lib/self-update.js +78 -25
  430. package/dist/lib/serve/control.d.ts +1 -1
  431. package/dist/lib/serve/control.js +4 -4
  432. package/dist/lib/serve/data.d.ts +1 -1
  433. package/dist/lib/serve/data.js +1 -1
  434. package/dist/lib/serve/stream.js +1 -1
  435. package/dist/lib/service-manifest.d.ts +29 -0
  436. package/dist/lib/service-manifest.js +80 -0
  437. package/dist/lib/session/active.d.ts +59 -7
  438. package/dist/lib/session/active.js +158 -17
  439. package/dist/lib/session/bash-command.js +1 -1
  440. package/dist/lib/session/claude-accounts.d.ts +1 -1
  441. package/dist/lib/session/claude-accounts.js +1 -1
  442. package/dist/lib/session/db.d.ts +10 -2
  443. package/dist/lib/session/db.js +25 -6
  444. package/dist/lib/session/discover.d.ts +77 -0
  445. package/dist/lib/session/discover.js +130 -25
  446. package/dist/lib/session/fork.js +1 -1
  447. package/dist/lib/session/inject.d.ts +1 -1
  448. package/dist/lib/session/insights.d.ts +1 -1
  449. package/dist/lib/session/insights.js +1 -1
  450. package/dist/lib/session/live-metadata.d.ts +15 -0
  451. package/dist/lib/session/live-metadata.js +76 -0
  452. package/dist/lib/session/migrate-targets.d.ts +1 -1
  453. package/dist/lib/session/recovery.d.ts +1 -1
  454. package/dist/lib/session/recovery.js +2 -2
  455. package/dist/lib/session/remote-active.d.ts +10 -1
  456. package/dist/lib/session/remote-active.js +8 -3
  457. package/dist/lib/session/remote-bundle.d.ts +1 -1
  458. package/dist/lib/session/remote-bundle.js +2 -2
  459. package/dist/lib/session/remote-list.d.ts +15 -4
  460. package/dist/lib/session/remote-list.js +40 -3
  461. package/dist/lib/session/remote.d.ts +5 -5
  462. package/dist/lib/session/remote.js +13 -17
  463. package/dist/lib/session/resume-command.d.ts +3 -2
  464. package/dist/lib/session/resume-command.js +4 -3
  465. package/dist/lib/session/resume-owner.d.ts +3 -3
  466. package/dist/lib/session/resume-owner.js +3 -3
  467. package/dist/lib/session/session-cache.d.ts +12 -0
  468. package/dist/lib/session/session-cache.js +2 -0
  469. package/dist/lib/session/share-html.d.ts +55 -0
  470. package/dist/lib/session/share-html.js +319 -0
  471. package/dist/lib/session/shell-programs.js +1 -1
  472. package/dist/lib/session/state.js +5 -5
  473. package/dist/lib/session/team-filter.d.ts +1 -1
  474. package/dist/lib/session/team-filter.js +1 -1
  475. package/dist/lib/session/types.d.ts +3 -3
  476. package/dist/lib/session/width.d.ts +2 -2
  477. package/dist/lib/session/width.js +2 -2
  478. package/dist/lib/settings-manifest.d.ts +2 -0
  479. package/dist/lib/settings-manifest.js +81 -3
  480. package/dist/lib/share/delete.d.ts +21 -0
  481. package/dist/lib/share/delete.js +42 -0
  482. package/dist/lib/share/publish.d.ts +120 -0
  483. package/dist/lib/share/publish.js +243 -18
  484. package/dist/lib/share/worker-template.js +172 -9
  485. package/dist/lib/shims.js +35 -7
  486. package/dist/lib/smart-launch.d.ts +4 -4
  487. package/dist/lib/smart-launch.js +6 -4
  488. package/dist/lib/snapshot.d.ts +4 -4
  489. package/dist/lib/snapshot.js +2 -2
  490. package/dist/lib/ssh-exec.d.ts +1 -1
  491. package/dist/lib/ssh-exec.js +2 -2
  492. package/dist/lib/ssh-tunnel.d.ts +10 -10
  493. package/dist/lib/ssh-tunnel.js +12 -12
  494. package/dist/lib/staleness/checkers/hooks.d.ts +1 -1
  495. package/dist/lib/staleness/checkers/hooks.js +1 -1
  496. package/dist/lib/staleness/detectors/permissions.js +0 -23
  497. package/dist/lib/staleness/detectors/plugins.js +1 -1
  498. package/dist/lib/staleness/fingerprint.js +1 -1
  499. package/dist/lib/staleness/layers.d.ts +1 -1
  500. package/dist/lib/staleness/layers.js +1 -1
  501. package/dist/lib/staleness/writers/mcp.js +3 -1
  502. package/dist/lib/staleness/writers/plugins.js +1 -1
  503. package/dist/lib/staleness/writers/types.d.ts +8 -0
  504. package/dist/lib/startup/command-registry.d.ts +6 -147
  505. package/dist/lib/startup/command-registry.js +40 -303
  506. package/dist/lib/startup/dev-build.d.ts +0 -21
  507. package/dist/lib/startup/dev-build.js +29 -8
  508. package/dist/lib/state.d.ts +19 -1
  509. package/dist/lib/state.js +120 -51
  510. package/dist/lib/subagents.js +1 -1
  511. package/dist/lib/sync-status.js +1 -1
  512. package/dist/lib/sync-umbrella.d.ts +6 -1
  513. package/dist/lib/sync-umbrella.js +9 -4
  514. package/dist/lib/teams/agents.js +2 -2
  515. package/dist/lib/teams/registry.js +1 -1
  516. package/dist/lib/terminal/backends/vscodium-agent.js +1 -1
  517. package/dist/lib/terminal/engine.js +1 -1
  518. package/dist/lib/terminal/index.d.ts +4 -0
  519. package/dist/lib/terminal/index.js +3 -0
  520. package/dist/lib/terminal/inject.d.ts +2 -2
  521. package/dist/lib/terminal/inject.js +2 -2
  522. package/dist/lib/terminal/transport.js +1 -1
  523. package/dist/lib/tmux/index.d.ts +1 -1
  524. package/dist/lib/tmux/index.js +1 -1
  525. package/dist/lib/tmux/session.d.ts +21 -5
  526. package/dist/lib/tmux/session.js +76 -22
  527. package/dist/lib/triggers/handlers.d.ts +38 -3
  528. package/dist/lib/triggers/handlers.js +58 -7
  529. package/dist/lib/triggers/webhook.d.ts +113 -5
  530. package/dist/lib/triggers/webhook.js +223 -44
  531. package/dist/lib/types.d.ts +19 -7
  532. package/dist/lib/usage-fleet.d.ts +1 -1
  533. package/dist/lib/usage-fleet.js +1 -1
  534. package/dist/lib/usage-refresh.d.ts +1 -1
  535. package/dist/lib/usage-refresh.js +3 -3
  536. package/dist/lib/version-duplicates.js +2 -2
  537. package/dist/lib/view-types.d.ts +56 -0
  538. package/dist/lib/view-types.js +1 -0
  539. package/dist/lib/watchdog/rotate.d.ts +2 -2
  540. package/dist/lib/watchdog/rotate.js +3 -3
  541. package/dist/lib/watchdog/runner.d.ts +2 -3
  542. package/dist/lib/watchdog/runner.js +3 -4
  543. package/dist/lib/workflows.js +1 -1
  544. package/dist/lib/wrap.d.ts +33 -0
  545. package/dist/lib/wrap.js +70 -0
  546. package/package.json +2 -1
  547. package/scripts/postinstall.js +2 -2
  548. package/dist/commands/bench.d.ts +0 -2
  549. package/dist/commands/bench.js +0 -101
  550. package/dist/commands/cp.d.ts +0 -84
  551. package/dist/commands/cp.js +0 -231
  552. package/dist/commands/login.d.ts +0 -2
  553. package/dist/lib/resources/commands.d.ts +0 -46
  554. package/dist/lib/resources/commands.js +0 -211
  555. package/dist/lib/resources/hooks.d.ts +0 -16
  556. package/dist/lib/resources/hooks.js +0 -153
  557. package/dist/lib/resources/mcp.d.ts +0 -34
  558. package/dist/lib/resources/mcp.js +0 -250
  559. package/dist/lib/resources/memory.d.ts +0 -15
  560. package/dist/lib/resources/memory.js +0 -46
  561. package/dist/lib/resources/permissions.d.ts +0 -13
  562. package/dist/lib/resources/permissions.js +0 -202
  563. package/dist/lib/resources/rules.d.ts +0 -46
  564. package/dist/lib/resources/rules.js +0 -179
  565. package/dist/lib/resources/skills.d.ts +0 -37
  566. package/dist/lib/resources/skills.js +0 -247
  567. package/dist/lib/resources/subagents.d.ts +0 -46
  568. package/dist/lib/resources/subagents.js +0 -202
  569. /package/dist/lib/{feed.d.ts → feed/feed.d.ts} +0 -0
@@ -18,15 +18,15 @@ import * as fs from 'fs';
18
18
  import * as path from 'path';
19
19
  import * as os from 'os';
20
20
  import { getCliLaunch, getAgentsBinDir } from './cli-entry.js';
21
- import { resolveJobPrompt, parseTimeout, writeRunMeta, listRuns, getJobRunsDir, getRunDir, checkJobDeviceEligibility, finalizeRunMeta, resolveJobExecutionContext, slotRunId, claimRunSlot, readRunMeta, resolveHostStrategy, } from './routines.js';
22
- import { getRunsDir, getUserAgentsDir, readMeta } from './state.js';
21
+ import { resolveJobPrompt, parseTimeout, writeRunMeta, listRuns, getJobRunsDir, getRunDir, checkJobDeviceEligibility, finalizeRunMeta, resolveJobExecutionContext, slotRunId, claimRunSlot, readRunMeta, resolveHostStrategy, } from './scheduling/routines.js';
22
+ import { getRunsDir, getUserAgentsDir, readMeta, getDaemonDir } from './state.js';
23
23
  import { shortCodexHome } from './codex-home.js';
24
24
  import { prepareJobHome, buildSpawnEnv, getJobHomePath } from './sandbox.js';
25
25
  import { resolveModel, buildReasoningFlags } from './models.js';
26
- import { createTimer, redactPrompt, emitRoutineEnd } from './events.js';
26
+ import { createTimer, redactPrompt, emitRoutineEnd } from './feed/events.js';
27
27
  import { codexEditWritableRoots, codexPolicyArgs } from './codex-policy.js';
28
28
  import { applyAddDirs } from './add-dir.js';
29
- import { normalizeMode, resolveHeadlessMode, buildExecEnv, detectRateLimit, detectAuthFailure, isAuthFailureFromLog, authFailureReason, } from './exec.js';
29
+ import { normalizeMode, resolveHeadlessMode, buildExecEnv, detectRateLimit, detectAuthFailure, isAuthFailureFromLog, authFailureReason, AGENT_COMMANDS, } from './exec.js';
30
30
  import { resolveActor } from './actor.js';
31
31
  import { loadTask as loadHostTask } from './hosts/tasks.js';
32
32
  import { reconcileTask as reconcileHostTask } from './hosts/reconcile.js';
@@ -34,12 +34,12 @@ import { backgroundSpawnOptions, killTree } from './platform/process.js';
34
34
  import lockfile from 'proper-lockfile';
35
35
  import { ensureLockTarget } from './fs-atomic.js';
36
36
  import { walkForFiles } from './fs-walk.js';
37
- import { getBinaryPath, isVersionInstalled, resolveVersion, getVersionHomePath } from './versions.js';
37
+ import { getBinaryPath, isVersionInstalled, resolveVersion, getVersionHomePath } from './installations/versions.js';
38
38
  import { resolveClaudeSetupToken } from './claude-account-token.js';
39
- import { getConfiguredRunStrategy, resolveRunVersion, resolveAccountVersion, rotationFailoverChain, readinessFromCandidate, formatNoHealthyAccountError, } from './rotate.js';
39
+ import { getConfiguredRunStrategy, resolveRunVersion, resolveAccountVersion, rotationFailoverChain, readinessFromCandidate, formatNoHealthyAccountError, } from './accounting/rotate.js';
40
40
  import { readAuthHealth, isDeadVerdict } from './auth-health.js';
41
41
  import { machineId } from './machine-id.js';
42
- import { isSelfUpdatingAgent, ROUTINE_AGENT_COMMANDS as AGENT_COMMANDS, ROUTINE_AGENT_IDS, isAgentHardDeprecated, hardDeprecationError } from './agents.js';
42
+ import { isSelfUpdatingAgent, ROUTINE_AGENT_COMMANDS, isAgentHardDeprecated, hardDeprecationError } from './agents.js';
43
43
  export class RoutineAlreadyRunningError extends Error {
44
44
  constructor(jobName, runId) {
45
45
  super(`Routine '${jobName}' already has a running execution (${runId})`);
@@ -48,24 +48,97 @@ export class RoutineAlreadyRunningError extends Error {
48
48
  }
49
49
  const ROUTINE_LAUNCH_LOCK_STALE_MS = 30_000;
50
50
  const ROUTINE_LAUNCH_LOCK_WAIT_MS = 10_000;
51
+ /**
52
+ * The prior run of this routine that still holds the active-run slot, or null.
53
+ *
54
+ * ONLY a run still marked `running` can hold the slot. Every terminal status —
55
+ * completed / failed / timeout / missed / blocked / skipped — releases it the
56
+ * moment it is reached (RUSH-2640). A `failed`/`timeout` record used to keep the
57
+ * slot while its pid stayed alive, but that conflated two different operations:
58
+ * cleaning up a leftover process group (reapTerminalRoutineProcesses's job) with
59
+ * occupying the slot. A daemon-launched run that reached a terminal state while
60
+ * still carrying the daemon's own pid (a host run that threw `target_unreachable`
61
+ * before spawning a child) then held the slot forever, because the daemon never
62
+ * dies and `isPidOurs` never went false — every later scheduled slot was refused
63
+ * with `already has an active run` while the routine was silently dead.
64
+ *
65
+ * A `running` record is also aged out past its own timeout: a run cannot
66
+ * legitimately outlive its configured deadline, so past that window it is a
67
+ * wedged record (a daemon that died mid-run, a missed child-exit event, a reused
68
+ * pid an old record without `spawnedAt` reads as "ours"), not a live run — and it
69
+ * never holds the slot regardless of what its recorded pid now points at.
70
+ */
51
71
  function activeRoutineRun(config) {
52
72
  const timeoutMs = parseTimeout(config.timeout) || 10 * 60 * 1000;
53
73
  const now = Date.now();
54
74
  const runs = listRuns(config.name);
55
75
  for (let i = runs.length - 1; i >= 0; i--) {
56
76
  const run = runs[i];
57
- if (!['running', 'failed', 'timeout'].includes(run.status))
77
+ if (run.status !== 'running')
78
+ continue;
79
+ const startedAt = Date.parse(run.startedAt);
80
+ const limit = run.timeoutMs ?? timeoutMs;
81
+ if (Number.isFinite(startedAt) && now - startedAt >= limit)
58
82
  continue;
59
- if (run.pid && isPidOurs(run.pid, run.spawnedAt))
83
+ // A provisional launcher claim carries no child pid yet — trust it until the
84
+ // timeout window above elapses. A record with a child pid is active only
85
+ // while that pid is genuinely ours (alive with the same birth time).
86
+ if (!run.pid)
87
+ return run;
88
+ if (isPidOurs(run.pid, run.spawnedAt))
60
89
  return run;
61
- if (!run.pid) {
62
- const startedAt = Date.parse(run.startedAt);
63
- if (Number.isFinite(startedAt) && now - startedAt < (run.timeoutMs ?? timeoutMs))
64
- return run;
65
- }
66
90
  }
67
91
  return null;
68
92
  }
93
+ /**
94
+ * Consecutive trailing `skipped`/`active_run` records — a routine that keeps
95
+ * being refused because a prior run "still owns" the slot. After the slot is
96
+ * released correctly on terminal states (see {@link activeRoutineRun}) this can
97
+ * only accumulate for a genuine long-overlap or a new wedge; either way it means
98
+ * the routine has stopped firing on schedule and should be surfaced, not left to
99
+ * pile up silently. `runs` is oldest→newest (listRuns sorts by run id).
100
+ */
101
+ export function activeRunSkipStreak(runs) {
102
+ let streak = 0;
103
+ for (let i = runs.length - 1; i >= 0; i--) {
104
+ const run = runs[i];
105
+ if (run.status === 'skipped' && run.skipReason === 'active_run') {
106
+ streak++;
107
+ continue;
108
+ }
109
+ break;
110
+ }
111
+ return streak;
112
+ }
113
+ /** How many consecutive active-run skips before a routine's stall is surfaced. */
114
+ const SKIP_STREAK_ALERT_THRESHOLD = 3;
115
+ /**
116
+ * The pid to stamp on a launcher's provisional active claim, or null when the
117
+ * launcher is this box's routines daemon.
118
+ *
119
+ * The claim pid exists so a launcher that dies between claiming the slot and
120
+ * spawning the child releases the slot quickly (`isPidOurs` goes false) instead
121
+ * of wedging it for the full timeout. That fast recovery only helps a SHORT-LIVED
122
+ * foreground launcher (`agents routines run`): the daemon never dies between
123
+ * claim and spawn, and recording ITS pid is actively harmful — the daemon
124
+ * outlives every run, so `isPidOurs` never goes false and a claim finalized to a
125
+ * terminal state before its child spawned kept the slot and drew
126
+ * `reapTerminalRoutineProcesses` at the daemon's own process group on every tick
127
+ * (RUSH-2640, requirement: never record the daemon's own pid as a run's pid). So
128
+ * the daemon records no claim pid; the timeout window bounds a daemon that
129
+ * crashes mid-claim instead.
130
+ */
131
+ export function launcherClaimPid() {
132
+ try {
133
+ // Mirrors daemon.ts readDaemonPid() (PID_FILE = 'daemon.pid'); read directly
134
+ // rather than importing it to avoid a runner<->daemon import cycle.
135
+ const daemonPid = parseInt(fs.readFileSync(path.join(getDaemonDir(), 'daemon.pid'), 'utf-8').trim(), 10);
136
+ if (Number.isFinite(daemonPid) && daemonPid === process.pid)
137
+ return null;
138
+ }
139
+ catch { /* no daemon pid file — a foreground launcher; record its pid */ }
140
+ return process.pid;
141
+ }
69
142
  /** Serialize concurrent launches of one routine on this box (the on-disk claim
70
143
  * primitive `claimRunSlot` is what holds across processes; this lock only makes
71
144
  * the allocate→spawn window atomic within this process's launch paths). */
@@ -150,10 +223,13 @@ function writeActiveClaim(config, attempt) {
150
223
  ...attempt.stamp,
151
224
  ...(config.workflow ? { workflow: config.workflow } : config.command ? { command: config.command } : config.agent ? { agent: config.agent } : {}),
152
225
  // The launcher owns this provisional claim until the command/agent child
153
- // replaces it with its own pid. Recording the owner makes a crash between
154
- // lock release and child spawn recoverable instead of wedging the routine
155
- // for its full configured timeout.
156
- pid: process.pid,
226
+ // replaces it with its own pid. Recording a SHORT-LIVED foreground launcher's
227
+ // pid makes a crash between lock release and child spawn recoverable instead
228
+ // of wedging the routine for its full configured timeout. The long-lived
229
+ // daemon records no pid here (see launcherClaimPid): its pid never dies, so
230
+ // recording it wedged the slot forever and mis-aimed the process reaper at the
231
+ // daemon itself (RUSH-2640).
232
+ pid: launcherClaimPid(),
157
233
  // `isPidOurs` compares this value with the OS process birth time. The
158
234
  // daemon may have been alive for days before claiming a routine, so the
159
235
  // claim must carry the launcher's birth, not the claim timestamp.
@@ -228,7 +304,11 @@ function allocateRoutineAttempt(config, trigger) {
228
304
  }),
229
305
  };
230
306
  }
231
- if (!config.workflow && config.agent && ROUTINE_AGENT_IDS.includes(config.agent) && isAgentHardDeprecated(config.agent)) {
307
+ // Gate on deprecation alone, not ROUTINE_AGENT_IDS membership a retired
308
+ // harness leaves the command table (gemini did), and the legacy routine must
309
+ // still land a visible 'blocked' record, never a generic buildJobCommand
310
+ // failure (RUSH-2202).
311
+ if (!config.workflow && config.agent && isAgentHardDeprecated(config.agent)) {
232
312
  const reason = hardDeprecationError(config.agent);
233
313
  return {
234
314
  proceed: false,
@@ -278,6 +358,24 @@ function allocateRoutineAttempt(config, trigger) {
278
358
  }
279
359
  return { proceed: true, attempt: { runId, stamp } };
280
360
  }
361
+ /**
362
+ * Emit a loud, once-per-wedge warning when a routine has been refused its slot
363
+ * for {@link SKIP_STREAK_ALERT_THRESHOLD} consecutive scheduled runs. Fires only
364
+ * when the streak first reaches the threshold (not on every later skip), so a
365
+ * genuinely-stalled routine surfaces once instead of piling up silent `skipped`
366
+ * records the way RUSH-2640 did. Runs on the daemon's own stderr, so it lands in
367
+ * the daemon log the operator reads.
368
+ */
369
+ function surfaceWedgedRoutine(config, terminal) {
370
+ if (terminal.status !== 'skipped' || terminal.skipReason !== 'active_run')
371
+ return;
372
+ const streak = activeRunSkipStreak(listRuns(config.name));
373
+ if (streak !== SKIP_STREAK_ALERT_THRESHOLD)
374
+ return;
375
+ const stuck = terminal.activeRunId ?? 'unknown';
376
+ process.stderr.write(`[agents] routine '${config.name}' skipped ${streak} consecutive scheduled runs — ` +
377
+ `its active-run slot is still held by ${stuck}; the routine is not firing on schedule.\n`);
378
+ }
281
379
  /**
282
380
  * Claim one routine attempt under the short launch lock, then execute after
283
381
  * releasing it. The persisted `running` claim makes a concurrent entry point
@@ -293,8 +391,10 @@ async function runWithAttempt(config, trigger, run, wrapTerminal) {
293
391
  writeActiveClaim(config, alloc.attempt);
294
392
  return { attempt: alloc.attempt };
295
393
  });
296
- if ('terminal' in claimed)
394
+ if ('terminal' in claimed) {
395
+ surfaceWedgedRoutine(config, claimed.terminal);
297
396
  return wrapTerminal(claimed.terminal);
397
+ }
298
398
  try {
299
399
  return await run(claimed.attempt);
300
400
  }
@@ -316,13 +416,31 @@ async function runWithAttempt(config, trigger, run, wrapTerminal) {
316
416
  function terminateRoutineTree(pid) {
317
417
  if (!pid)
318
418
  return;
419
+ // Never take THIS process down. Both kills below are unconditional SIGKILLs,
420
+ // so a RunMeta naming the reaper's own pid -- a reused pid, a record written
421
+ // by the process now doing the reaping, or a hand-written fixture -- makes the
422
+ // reaper SIGKILL itself, and via `-pid` its whole process group with it. There
423
+ // is no recovery from that: the run is never finalized, and on the daemon it
424
+ // takes the scheduler down mid-sweep. daemon.ts:457 already refuses to evict an
425
+ // incumbent whose pid is `process.pid` for exactly this reason; the reap path
426
+ // needs the same guard. Skipping the kill still lets the caller finalize the
427
+ // run record, which is the part that matters.
428
+ if (pid === process.pid)
429
+ return;
319
430
  if (process.platform === 'win32') {
320
431
  killTree(pid);
321
432
  return;
322
433
  }
434
+ // Detached spawn makes the child a new process-group leader; kill the group.
435
+ // If setsid has not landed yet (or the pid is not a leader), -pid fails with
436
+ // ESRCH and the child stays up — also kill the pid itself.
323
437
  try {
324
438
  process.kill(-pid, 'SIGKILL');
325
439
  }
440
+ catch { /* not a group leader, or already exited */ }
441
+ try {
442
+ process.kill(pid, 'SIGKILL');
443
+ }
326
444
  catch { /* already exited */ }
327
445
  }
328
446
  /**
@@ -396,7 +514,7 @@ export function buildJobCommand(config, resolvedPrompt, forwardAccount = true) {
396
514
  cmd.push('--account', config.account);
397
515
  return cmd;
398
516
  }
399
- const template = AGENT_COMMANDS[agent];
517
+ const template = ROUTINE_AGENT_COMMANDS[agent];
400
518
  if (!template) {
401
519
  throw new Error(`Unsupported agent for daemon jobs: ${agent}`);
402
520
  }
@@ -433,15 +551,6 @@ export function buildJobCommand(config, resolvedPrompt, forwardAccount = true) {
433
551
  cmd.push(...codexPolicyArgs(policyMode, [...codexEditWritableRoots(), ...routineRoots]));
434
552
  appendModelAndReasoning(cmd, config);
435
553
  }
436
- if (config.agent === 'gemini') {
437
- if (mode === 'edit') {
438
- cmd.push('--approval-mode', 'auto_edit');
439
- }
440
- else if (mode === 'skip') {
441
- cmd.push('--yolo');
442
- }
443
- appendModelAndReasoning(cmd, config);
444
- }
445
554
  if (config.agent === 'cursor') {
446
555
  if (mode === 'plan') {
447
556
  cmd.push('--plan');
@@ -512,7 +621,7 @@ export function buildJobCommand(config, resolvedPrompt, forwardAccount = true) {
512
621
  return cmd;
513
622
  }
514
623
  /**
515
- * Append --model and reasoning flags to a command being assembled.
624
+ * Append the agent's canonical model flag and reasoning flags to a command.
516
625
  *
517
626
  * Pass-through model resolution: validates against the installed (agent, version)
518
627
  * catalog when possible and writes a warning to stderr on miss, but never blocks.
@@ -523,15 +632,19 @@ function appendModelAndReasoning(cmd, config) {
523
632
  const agent = config.agent;
524
633
  const model = config.config?.model;
525
634
  if (model) {
635
+ const modelFlag = AGENT_COMMANDS[agent].modelFlag;
636
+ if (!modelFlag) {
637
+ throw new Error(`Agent ${agent} does not support routine model selection`);
638
+ }
526
639
  if (config.version) {
527
640
  const resolved = resolveModel(agent, config.version, model);
528
641
  if (resolved.warning) {
529
642
  process.stderr.write(`[agents] ${resolved.warning}\n`);
530
643
  }
531
- cmd.push('--model', resolved.forwarded);
644
+ cmd.push(modelFlag, resolved.forwarded);
532
645
  }
533
646
  else {
534
- cmd.push('--model', model);
647
+ cmd.push(modelFlag, model);
535
648
  }
536
649
  }
537
650
  const reasoning = config.config?.reasoning;
@@ -772,18 +885,31 @@ export async function resolveRoutineLaunch(config, cwd = process.cwd(), deps = {
772
885
  // resolveRoutineLaunch is only called for agent jobs (workflow returns above;
773
886
  // command jobs branch out of execute*Job before reaching this).
774
887
  const agent = config.agent;
775
- const { findAccount, resolveAccountSelection, resolveCredentialAccount } = await import('./account-registry.js');
888
+ const { findAccount, findUnifiedAccount, resolveAccountSelection, resolveCredentialAccount } = await import('./account-registry.js');
889
+ const meta = (deps.readMeta ?? readMeta)();
776
890
  const explicitCredential = config.account
777
891
  ? (deps.findCredentialAccount?.(config.account) ?? (deps.resolveCredentialAccount !== undefined || findAccount(config.account) !== null))
778
892
  : false;
779
893
  const selectedCredential = config.account
780
894
  ? (explicitCredential ? config.account : undefined)
781
- : resolveAccountSelection(undefined, agent, (deps.readMeta ?? readMeta)());
895
+ : resolveAccountSelection(undefined, agent, meta);
782
896
  if (selectedCredential) {
783
- (deps.resolveCredentialAccount ?? resolveCredentialAccount)(selectedCredential, agent);
897
+ // A default/binding may resolve to a native account — never route that
898
+ // through the provider credential path (it has no bundle to resolve).
899
+ const unified = findUnifiedAccount(selectedCredential, meta);
900
+ if (unified?.kind !== 'native')
901
+ (deps.resolveCredentialAccount ?? resolveCredentialAccount)(selectedCredential, agent);
784
902
  }
785
903
  if (config.account && !explicitCredential) {
786
- const accountVersion = await (deps.resolveAccountVersion ?? resolveAccountVersion)(agent, config.account);
904
+ // A native routine account is named by its durable name; the version matcher
905
+ // keys on the identity (email/accountKey), so translate before resolving,
906
+ // and refuse a login that belongs to a different harness.
907
+ const unified = findUnifiedAccount(config.account, meta);
908
+ if (unified?.kind === 'native' && unified.agent !== agent) {
909
+ throw new Error(`Routine '${config.name}' account '${config.account}' is a ${unified.agent} login and cannot authenticate ${agent}.`);
910
+ }
911
+ const identity = unified?.kind === 'native' ? unified.identityKey : config.account;
912
+ const accountVersion = await (deps.resolveAccountVersion ?? resolveAccountVersion)(agent, identity);
787
913
  if (accountVersion) {
788
914
  if (config.version && config.version !== accountVersion) {
789
915
  throw new Error(`Routine '${config.name}' account '${config.account}' is signed in at ${agent}@${accountVersion}, not pinned ${agent}@${config.version}.`);
@@ -809,7 +935,10 @@ export async function resolveRoutineLaunch(config, cwd = process.cwd(), deps = {
809
935
  ...(config.account ? { forwardAccount: explicitCredential } : {}),
810
936
  };
811
937
  }
812
- const strategy = getConfiguredRunStrategy(agent, cwd);
938
+ // A per-routine strategy travels with the definition and beats the firing
939
+ // box's ambient run.<agent>.strategy — otherwise selection policy silently
940
+ // depends on whichever device fires the job (RUSH-2719).
941
+ const strategy = config.strategy ?? getConfiguredRunStrategy(agent, cwd);
813
942
  let version;
814
943
  let rotation = null;
815
944
  let exhausted;
@@ -892,6 +1021,70 @@ export function pinJobBinary(cmd, agent, version) {
892
1021
  * Such commands must NOT be binary-pinned (pinning rewrites cmd[0] to the agent binary,
893
1022
  * producing a broken `<binary> run …`) and must not receive a version-pinned spawn env.
894
1023
  */
1024
+ /**
1025
+ * Assert a routine's account can be dispatched to the resolved placement, BEFORE
1026
+ * any off-box dispatch (placement is resolved before {@link resolveRoutineLaunch}),
1027
+ * at the top of both the foreground and detached paths:
1028
+ *
1029
+ * - **native** account → rejected for host AND cloud: a native login is a
1030
+ * device-local harness credential that cannot be forwarded off-box.
1031
+ * - **provider** account + **cloud** → rejected (fail loud): the cloud dispatch
1032
+ * has no secure way to inject a device-local provider bundle yet.
1033
+ * - **provider** account + **host** → allowed: the host dispatch forwards the
1034
+ * account NAME (the remote resolves its own local bundle — no secret copied).
1035
+ *
1036
+ * `account` is injectable so the guard is unit-tested for both modes without a
1037
+ * registry or a real dispatch.
1038
+ */
1039
+ export async function assertRoutineAccountLocalForPlacement(config, mode, deps = {}) {
1040
+ if (!config.account)
1041
+ return;
1042
+ let account = deps.account;
1043
+ if (account === undefined) {
1044
+ const { findUnifiedAccount } = await import('./account-registry.js');
1045
+ account = findUnifiedAccount(config.account, (deps.readMeta ?? readMeta)());
1046
+ }
1047
+ if (!account) {
1048
+ throw new Error(`Routine '${config.name}' account '${config.account}' is unknown.`);
1049
+ }
1050
+ if (account?.kind === 'native') {
1051
+ throw new Error(`Routine '${config.name}' account '${config.account}' is a device-local ${account.agent} login and cannot run on a ${mode} placement. Use a provider account, or place this routine on the device that holds the login.`);
1052
+ }
1053
+ if (mode === 'cloud' && account?.kind === 'provider') {
1054
+ // RUSH-2689: cloud+provider injection not yet implemented.
1055
+ throw new Error(`Routine '${config.name}' account '${config.account}' is a provider credential; cloud placement cannot securely inject it (RUSH-2689). Run this routine locally or on a host that holds the bundle.`);
1056
+ }
1057
+ }
1058
+ export async function dispatchPlacedJob(config, target, attempt, deps = {}) {
1059
+ if (target.mode !== 'host' && target.mode !== 'cloud')
1060
+ return undefined;
1061
+ await assertRoutineAccountLocalForPlacement(config, target.mode, { account: deps.account });
1062
+ if (target.mode === 'host') {
1063
+ return (deps.host ?? executeJobOnHost)({ ...config, host: target.host }, { detached: false }, attempt);
1064
+ }
1065
+ return (deps.cloud ?? executeJobOnCloud)(config, { detached: false }, attempt);
1066
+ }
1067
+ /**
1068
+ * Build the options passed to `dispatchPromptToHost` for a host routine. Split
1069
+ * out so the execution boundary is unit-testable: it MUST forward the routine's
1070
+ * `account` by name (the remote resolves its own local bundle; no secret copied)
1071
+ * — dropping it silently ran the remote under the wrong identity.
1072
+ */
1073
+ export function buildHostDispatchOptions(config, ctx) {
1074
+ return {
1075
+ agent: config.agent,
1076
+ prompt: resolveJobPrompt(config),
1077
+ mode: normalizeMode(config.mode),
1078
+ effort: config.effort,
1079
+ model: config.config?.model,
1080
+ account: config.account,
1081
+ timeout: config.timeout, // enforced by the REMOTE agents run
1082
+ remoteCwd: ctx.remoteCwd,
1083
+ name: config.name,
1084
+ cwd: ctx.runDir,
1085
+ follow: !ctx.detached,
1086
+ };
1087
+ }
895
1088
  export function dispatchesViaAgentsRun(config) {
896
1089
  return Boolean(config.workflow || config.resume);
897
1090
  }
@@ -1069,13 +1262,10 @@ async function executeJobPlaced(config, deps, attempt) {
1069
1262
  // remote run to completion when possible.
1070
1263
  {
1071
1264
  const { resolvePlacementTarget } = await import('./routines-placement.js');
1072
- const target = resolvePlacementTarget(config);
1073
- if (target.mode === 'host') {
1074
- return executeJobOnHost({ ...config, host: target.host }, { detached: false }, attempt);
1075
- }
1076
- if (target.mode === 'cloud') {
1077
- return executeJobOnCloud(config, { detached: false }, attempt);
1078
- }
1265
+ const target = await resolvePlacementTarget(config);
1266
+ const placed = await dispatchPlacedJob(config, target, attempt);
1267
+ if (placed)
1268
+ return placed;
1079
1269
  }
1080
1270
  // Command-mode: run a plain shell command directly (no agent, no rotation,
1081
1271
  // no pinning, no sandbox overlay). Reuses the run-record machinery so
@@ -1111,12 +1301,16 @@ async function executeJobPlaced(config, deps, attempt) {
1111
1301
  // (command jobs branched out earlier, so config.agent is set on the non-workflow path.)
1112
1302
  const effectiveAgent = config.workflow ? 'claude' : config.agent;
1113
1303
  if (!dispatchesViaAgentsRun(config)) {
1114
- const { findAccount, resolveAccountSelection, resolveCredentialAccount } = await import('./account-registry.js');
1115
- const selectedAccount = config.account && !findAccount(config.account)
1116
- ? undefined
1117
- : resolveAccountSelection(config.account, effectiveAgent, readMeta());
1118
- if (selectedAccount)
1119
- Object.assign(baseEnv, resolveCredentialAccount(selectedAccount, effectiveAgent).env);
1304
+ const { findUnifiedAccount, resolveAccountSelection, resolveCredentialAccount } = await import('./account-registry.js');
1305
+ const meta = readMeta();
1306
+ const selectedAccount = resolveAccountSelection(config.account, effectiveAgent, meta);
1307
+ if (selectedAccount) {
1308
+ // Only a provider account injects env; a native account (explicit or via a
1309
+ // device-scoped binding) is read from the harness home and forwards nothing.
1310
+ const unified = findUnifiedAccount(selectedAccount, meta);
1311
+ if (unified?.kind === 'provider')
1312
+ Object.assign(baseEnv, resolveCredentialAccount(selectedAccount, effectiveAgent).env);
1313
+ }
1120
1314
  }
1121
1315
  const meta = {
1122
1316
  jobName: config.name,
@@ -1443,18 +1637,7 @@ async function executeJobOnHost(config, opts, attempt) {
1443
1637
  host: host.name,
1444
1638
  };
1445
1639
  writeRunMeta(meta);
1446
- const { task, exitCode } = await dispatchPromptToHost(host, {
1447
- agent: config.agent,
1448
- prompt: resolveJobPrompt(config),
1449
- mode: normalizeMode(config.mode),
1450
- effort: config.effort,
1451
- model: config.config?.model,
1452
- timeout: config.timeout, // enforced by the REMOTE agents run
1453
- remoteCwd,
1454
- name: config.name,
1455
- cwd: runDir,
1456
- follow: !opts.detached,
1457
- });
1640
+ const { task, exitCode } = await dispatchPromptToHost(host, buildHostDispatchOptions(config, { remoteCwd, runDir, detached: opts.detached }));
1458
1641
  meta.hostTaskId = task.id;
1459
1642
  // Sync path: a real exit code finalizes now. -1 (follow window closed) and
1460
1643
  // the detached path leave the meta `running` for the monitor to reconcile.
@@ -1572,7 +1755,10 @@ async function executeJobDetachedClaimed(config, attempt, hooks) {
1572
1755
  // sends the finish notification only for local detached runs below (RUSH-2030).
1573
1756
  {
1574
1757
  const { resolvePlacementTarget } = await import('./routines-placement.js');
1575
- const target = resolvePlacementTarget(config);
1758
+ const target = await resolvePlacementTarget(config);
1759
+ if (target.mode === 'host' || target.mode === 'cloud') {
1760
+ await assertRoutineAccountLocalForPlacement(config, target.mode);
1761
+ }
1576
1762
  if (target.mode === 'host') {
1577
1763
  const { meta } = await executeJobOnHost({ ...config, host: target.host }, { detached: true }, attempt);
1578
1764
  if (meta.status !== 'running')
@@ -2072,17 +2258,23 @@ export function monitorRunningJobs() {
2072
2258
  finalizeHostRun(meta);
2073
2259
  continue;
2074
2260
  }
2075
- if (!meta.pid)
2076
- continue;
2077
2261
  const runDirPath = path.join(jobRunsPath, runDirEntry.name);
2078
2262
  const stdoutPath = path.join(runDirPath, 'stdout.log');
2079
2263
  // Command-mode records carry no agent; there is no stream-json report to
2080
2264
  // parse or extract. Reap them on pid liveness alone.
2081
2265
  const isCommandRun = Boolean(meta.command) || !meta.agent;
2266
+ // Age-out runs FIRST, before the null-pid guard below, so a wedged record
2267
+ // still marked `running` past its deadline is always finalized — a
2268
+ // provisional launcher claim whose daemon crashed before spawning a child
2269
+ // (pid null), or an old record whose recorded pid was reused, would
2270
+ // otherwise linger as `running` forever (RUSH-2640). Only kill a process
2271
+ // group that is genuinely still ours; terminating a reused pid would kill
2272
+ // an unrelated process, and a null pid has nothing to kill.
2082
2273
  const wallClockMs = Date.now() - Date.parse(meta.startedAt);
2083
2274
  const timeoutMs = meta.timeoutMs ?? MAX_WALL_CLOCK_MS;
2084
2275
  if (Number.isFinite(wallClockMs) && wallClockMs > timeoutMs) {
2085
- terminateRoutineTree(meta.pid);
2276
+ if (meta.pid && isPidOurs(meta.pid, meta.spawnedAt))
2277
+ terminateRoutineTree(meta.pid);
2086
2278
  finalizeRunMeta(meta, 'timeout', null, { errorMessage: 'exceeded configured timeout' });
2087
2279
  writeRunMeta(meta);
2088
2280
  emitRoutineEnd(meta);
@@ -2092,6 +2284,8 @@ export function monitorRunningJobs() {
2092
2284
  }
2093
2285
  continue;
2094
2286
  }
2287
+ if (!meta.pid)
2288
+ continue;
2095
2289
  if (!isPidOurs(meta.pid, meta.spawnedAt)) {
2096
2290
  if (isCommandRun) {
2097
2291
  // Command routines normally record their own terminal status via
@@ -6,7 +6,7 @@
6
6
  * The spawned agent process sees only the overlay, limiting filesystem
7
7
  * access to explicitly allowed paths.
8
8
  */
9
- import type { JobConfig } from './routines.js';
9
+ import type { JobConfig } from './scheduling/routines.js';
10
10
  /** Build a restricted environment for a sandboxed process, setting HOME to the overlay. */
11
11
  export declare function buildSpawnEnv(overlayHome: string, extraEnv?: Record<string, string>): Record<string, string>;
12
12
  /**
@@ -5,7 +5,7 @@
5
5
  * process creates a single JobScheduler instance that loads enabled jobs
6
6
  * on startup and reloads them on SIGHUP.
7
7
  */
8
- import type { JobConfig } from './routines.js';
8
+ import type { JobConfig } from './scheduling/routines.js';
9
9
  /** How a fire was triggered, carrying the scheduler's intended UTC slot time. */
10
10
  export interface TriggerContext {
11
11
  /** The cron slot this callback fires for (croner `currentRun()`), for the
@@ -6,7 +6,7 @@
6
6
  * on startup and reloads them on SIGHUP.
7
7
  */
8
8
  import { Cron } from 'croner';
9
- import { listJobs, deleteJob, isPastEndAt, isPastOneShotRoutine, isOneShotRoutine, setJobEnabled, shouldPurgeCompletedOneShotRoutine, jobRunsOnThisDevice, hasAmbiguousDevicePin, routineOwnerDevice, } from './routines.js';
9
+ import { listJobs, deleteJob, isPastEndAt, isPastOneShotRoutine, isOneShotRoutine, setJobEnabled, shouldPurgeCompletedOneShotRoutine, jobRunsOnThisDevice, hasAmbiguousDevicePin, routineOwnerDevice, } from './scheduling/routines.js';
10
10
  /** In-memory cron scheduler that triggers a callback when jobs fire. */
11
11
  export class JobScheduler {
12
12
  jobs = new Map();