@phnx-labs/agents-cli 1.22.35 → 1.22.37

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 (487) hide show
  1. package/CHANGELOG.md +666 -2
  2. package/README.md +75 -35
  3. package/dist/bin/agents +0 -0
  4. package/dist/bootstrap.d.ts +15 -0
  5. package/dist/bootstrap.js +1211 -0
  6. package/dist/commands/accounts.d.ts +4 -11
  7. package/dist/commands/accounts.js +159 -27
  8. package/dist/commands/attach.js +17 -4
  9. package/dist/commands/audit.d.ts +8 -8
  10. package/dist/commands/audit.js +57 -47
  11. package/dist/commands/browser.js +15 -11
  12. package/dist/commands/cloud.js +1 -1
  13. package/dist/commands/commands.js +0 -11
  14. package/dist/commands/computer-actions.js +33 -0
  15. package/dist/commands/computer-sessions-picker.d.ts +21 -0
  16. package/dist/commands/computer-sessions-picker.js +141 -0
  17. package/dist/commands/computer.d.ts +16 -0
  18. package/dist/commands/computer.js +37 -0
  19. package/dist/commands/config.d.ts +17 -0
  20. package/dist/commands/config.js +401 -0
  21. package/dist/commands/cp.d.ts +84 -0
  22. package/dist/commands/cp.js +231 -0
  23. package/dist/commands/daemon.js +243 -14
  24. package/dist/commands/detach-core.d.ts +1 -1
  25. package/dist/commands/detach-core.js +12 -2
  26. package/dist/commands/detach.js +1 -1
  27. package/dist/commands/doctor.js +64 -5
  28. package/dist/commands/events.d.ts +24 -12
  29. package/dist/commands/events.js +144 -28
  30. package/dist/commands/exec.js +85 -41
  31. package/dist/commands/feed.d.ts +1 -1
  32. package/dist/commands/feed.js +16 -8
  33. package/dist/commands/focus.d.ts +33 -1
  34. package/dist/commands/focus.js +177 -17
  35. package/dist/commands/funnel.d.ts +1 -1
  36. package/dist/commands/go.js +9 -8
  37. package/dist/commands/harness-wizard.d.ts +1 -0
  38. package/dist/commands/harness-wizard.js +18 -20
  39. package/dist/commands/harness.d.ts +2 -0
  40. package/dist/commands/harness.js +59 -26
  41. package/dist/commands/hooks.js +0 -11
  42. package/dist/commands/inspect.d.ts +94 -1
  43. package/dist/commands/inspect.js +866 -40
  44. package/dist/commands/lease.d.ts +4 -4
  45. package/dist/commands/lease.js +6 -6
  46. package/dist/commands/login.js +0 -13
  47. package/dist/commands/logs.d.ts +2 -2
  48. package/dist/commands/logs.js +2 -2
  49. package/dist/commands/mcp.js +7 -2
  50. package/dist/commands/memory.js +7 -2
  51. package/dist/commands/message.d.ts +1 -1
  52. package/dist/commands/message.js +37 -6
  53. package/dist/commands/models.js +4 -0
  54. package/dist/commands/monitors.d.ts +0 -1
  55. package/dist/commands/monitors.js +199 -16
  56. package/dist/commands/open.d.ts +18 -0
  57. package/dist/commands/open.js +57 -0
  58. package/dist/commands/packages.js +2 -107
  59. package/dist/commands/plugins.js +6 -3
  60. package/dist/commands/profiles.d.ts +1 -0
  61. package/dist/commands/profiles.js +16 -160
  62. package/dist/commands/projects.d.ts +28 -0
  63. package/dist/commands/projects.js +125 -5
  64. package/dist/commands/reconnect.js +9 -3
  65. package/dist/commands/repo.js +42 -1
  66. package/dist/commands/resource-view.d.ts +17 -0
  67. package/dist/commands/resource-view.js +36 -14
  68. package/dist/commands/resume.js +9 -2
  69. package/dist/commands/routines.d.ts +0 -2
  70. package/dist/commands/routines.js +473 -289
  71. package/dist/commands/secrets.js +52 -9
  72. package/dist/commands/sessions-export.d.ts +47 -0
  73. package/dist/commands/sessions-export.js +116 -6
  74. package/dist/commands/sessions-import.d.ts +17 -0
  75. package/dist/commands/sessions-import.js +114 -6
  76. package/dist/commands/sessions-migrate.d.ts +27 -0
  77. package/dist/commands/sessions-migrate.js +50 -9
  78. package/dist/commands/sessions-picker.js +23 -4
  79. package/dist/commands/sessions-resume.d.ts +5 -3
  80. package/dist/commands/sessions-resume.js +30 -8
  81. package/dist/commands/sessions-watch.d.ts +2 -0
  82. package/dist/commands/sessions-watch.js +53 -0
  83. package/dist/commands/sessions.d.ts +66 -3
  84. package/dist/commands/sessions.js +298 -47
  85. package/dist/commands/set.d.ts +1 -1
  86. package/dist/commands/set.js +2 -2
  87. package/dist/commands/setup-browser.js +2 -2
  88. package/dist/commands/setup-mine.js +0 -1
  89. package/dist/commands/setup-preferences.js +1 -1
  90. package/dist/commands/setup-share.js +34 -4
  91. package/dist/commands/setup.d.ts +5 -0
  92. package/dist/commands/setup.js +26 -0
  93. package/dist/commands/share.d.ts +67 -0
  94. package/dist/commands/share.js +275 -12
  95. package/dist/commands/skills.js +0 -11
  96. package/dist/commands/snapshot.js +1 -1
  97. package/dist/commands/ssh.d.ts +18 -0
  98. package/dist/commands/ssh.js +549 -210
  99. package/dist/commands/sync.d.ts +5 -0
  100. package/dist/commands/sync.js +212 -32
  101. package/dist/commands/teams.d.ts +13 -0
  102. package/dist/commands/teams.js +187 -30
  103. package/dist/commands/tickets.d.ts +2 -0
  104. package/dist/commands/tickets.js +43 -0
  105. package/dist/commands/update.js +2 -4
  106. package/dist/commands/usage.js +5 -3
  107. package/dist/commands/versions.js +11 -5
  108. package/dist/commands/view.js +15 -7
  109. package/dist/commands/webhook.d.ts +2 -2
  110. package/dist/commands/webhook.js +7 -7
  111. package/dist/index.d.ts +18 -2
  112. package/dist/index.js +53 -1264
  113. package/dist/lib/account-catalog.d.ts +18 -0
  114. package/dist/lib/account-catalog.js +38 -0
  115. package/dist/lib/account-provider-registry.d.ts +18 -0
  116. package/dist/lib/account-provider-registry.js +59 -0
  117. package/dist/lib/account-registry.d.ts +40 -0
  118. package/dist/lib/account-registry.js +239 -0
  119. package/dist/lib/account-schema.d.ts +44 -0
  120. package/dist/lib/account-schema.js +91 -0
  121. package/dist/lib/account-state-service.d.ts +21 -0
  122. package/dist/lib/account-state-service.js +60 -0
  123. package/dist/lib/activity.d.ts +1 -1
  124. package/dist/lib/activity.js +8 -1
  125. package/dist/lib/add-dir.d.ts +80 -0
  126. package/dist/lib/add-dir.js +241 -0
  127. package/dist/lib/agent-cli-commands.d.ts +11 -0
  128. package/dist/lib/agent-cli-commands.js +30 -0
  129. package/dist/lib/agents.js +44 -36
  130. package/dist/lib/answer-router.js +1 -1
  131. package/dist/lib/audit/log.d.ts +10 -27
  132. package/dist/lib/audit/log.js +20 -33
  133. package/dist/lib/auth-health.d.ts +9 -2
  134. package/dist/lib/auth-health.js +42 -9
  135. package/dist/lib/auto-pull-worker.js +7 -3
  136. package/dist/lib/auto-pull.d.ts +44 -3
  137. package/dist/lib/auto-pull.js +88 -5
  138. package/dist/lib/binary-shadow.d.ts +28 -0
  139. package/dist/lib/binary-shadow.js +121 -0
  140. package/dist/lib/brand.js +9 -3
  141. package/dist/lib/browser/ipc.d.ts +30 -0
  142. package/dist/lib/browser/ipc.js +81 -4
  143. package/dist/lib/browser/profiles.d.ts +3 -2
  144. package/dist/lib/browser/profiles.js +65 -22
  145. package/dist/lib/browser/service.d.ts +4 -0
  146. package/dist/lib/browser/service.js +30 -3
  147. package/dist/lib/browser/sessions-list.d.ts +22 -2
  148. package/dist/lib/browser/sessions-list.js +54 -6
  149. package/dist/lib/browser/stream.d.ts +2 -0
  150. package/dist/lib/browser/stream.js +1 -0
  151. package/dist/lib/browser/types.d.ts +19 -0
  152. package/dist/lib/byok-usage.d.ts +9 -2
  153. package/dist/lib/byok-usage.js +133 -31
  154. package/dist/lib/cli-entry.d.ts +11 -0
  155. package/dist/lib/cli-entry.js +46 -0
  156. package/dist/lib/cloud/host.d.ts +1 -1
  157. package/dist/lib/cloud/host.js +2 -2
  158. package/dist/lib/cloud/registry.js +1 -1
  159. package/dist/lib/cloud/types.d.ts +1 -1
  160. package/dist/lib/commands.d.ts +2 -0
  161. package/dist/lib/commands.js +2 -0
  162. package/dist/lib/computer/sessions-list.d.ts +150 -0
  163. package/dist/lib/computer/sessions-list.js +363 -0
  164. package/dist/lib/config-keys.d.ts +86 -0
  165. package/dist/lib/config-keys.js +193 -0
  166. package/dist/lib/config-machine-keys.d.ts +12 -0
  167. package/dist/lib/config-machine-keys.js +17 -0
  168. package/dist/lib/config-transfer.js +3 -4
  169. package/dist/lib/crabbox/cli.d.ts +2 -2
  170. package/dist/lib/crabbox/cli.js +3 -3
  171. package/dist/lib/daemon-health.d.ts +22 -0
  172. package/dist/lib/daemon-health.js +33 -3
  173. package/dist/lib/daemon-services.d.ts +50 -0
  174. package/dist/lib/daemon-services.js +147 -0
  175. package/dist/lib/daemon-ticks.d.ts +35 -66
  176. package/dist/lib/daemon-ticks.js +77 -159
  177. package/dist/lib/daemon.d.ts +72 -4
  178. package/dist/lib/daemon.js +792 -202
  179. package/dist/lib/deeplink/register.d.ts +49 -0
  180. package/dist/lib/deeplink/register.js +253 -0
  181. package/dist/lib/deeplink/url.d.ts +34 -0
  182. package/dist/lib/deeplink/url.js +78 -0
  183. package/dist/lib/device-config.d.ts +124 -29
  184. package/dist/lib/device-config.js +346 -141
  185. package/dist/lib/devices/config-migration.d.ts +42 -0
  186. package/dist/lib/devices/config-migration.js +203 -0
  187. package/dist/lib/devices/connect.js +14 -7
  188. package/dist/lib/devices/doctor-findings.d.ts +4 -1
  189. package/dist/lib/devices/doctor-findings.js +20 -1
  190. package/dist/lib/devices/harness-inventory.d.ts +11 -2
  191. package/dist/lib/devices/harness-inventory.js +0 -0
  192. package/dist/lib/devices/health.d.ts +1 -1
  193. package/dist/lib/devices/health.js +1 -1
  194. package/dist/lib/devices/pending.d.ts +22 -1
  195. package/dist/lib/devices/pending.js +67 -2
  196. package/dist/lib/devices/registry.d.ts +0 -25
  197. package/dist/lib/devices/registry.js +2 -83
  198. package/dist/lib/devices/resolve-profile.d.ts +20 -0
  199. package/dist/lib/devices/resolve-profile.js +44 -0
  200. package/dist/lib/devices/rollout-verify.d.ts +101 -0
  201. package/dist/lib/devices/rollout-verify.js +193 -0
  202. package/dist/lib/devices/ssh-config.js +10 -6
  203. package/dist/lib/event-families.d.ts +28 -0
  204. package/dist/lib/event-families.js +159 -0
  205. package/dist/lib/event-stream.d.ts +9 -1
  206. package/dist/lib/event-stream.js +26 -9
  207. package/dist/lib/events.d.ts +9 -1
  208. package/dist/lib/events.js +21 -6
  209. package/dist/lib/exec.d.ts +30 -0
  210. package/dist/lib/exec.js +219 -121
  211. package/dist/lib/feed-broadcast.d.ts +25 -0
  212. package/dist/lib/feed-broadcast.js +33 -0
  213. package/dist/lib/feed.d.ts +1 -1
  214. package/dist/lib/feed.js +12 -2
  215. package/dist/lib/fleet/capture.js +15 -0
  216. package/dist/lib/fleet/manifest.js +9 -0
  217. package/dist/lib/fleet/types.d.ts +9 -0
  218. package/dist/lib/fleet-status.js +10 -8
  219. package/dist/lib/git.d.ts +20 -6
  220. package/dist/lib/git.js +121 -17
  221. package/dist/lib/hosts/dispatch.d.ts +8 -3
  222. package/dist/lib/hosts/dispatch.js +29 -3
  223. package/dist/lib/hosts/logs.d.ts +2 -2
  224. package/dist/lib/hosts/logs.js +2 -2
  225. package/dist/lib/hosts/option.js +1 -1
  226. package/dist/lib/hosts/passthrough.d.ts +2 -3
  227. package/dist/lib/hosts/passthrough.js +10 -24
  228. package/dist/lib/hosts/progress.js +2 -2
  229. package/dist/lib/hosts/providers/devices.d.ts +3 -3
  230. package/dist/lib/hosts/providers/devices.js +18 -12
  231. package/dist/lib/hosts/ready.d.ts +5 -1
  232. package/dist/lib/hosts/ready.js +9 -3
  233. package/dist/lib/hosts/reconcile.d.ts +2 -2
  234. package/dist/lib/hosts/reconcile.js +2 -2
  235. package/dist/lib/hosts/registry.js +14 -9
  236. package/dist/lib/hosts/remote-cmd.js +1 -1
  237. package/dist/lib/hosts/remote-os.d.ts +9 -6
  238. package/dist/lib/hosts/remote-os.js +13 -6
  239. package/dist/lib/hosts/routing-flag.d.ts +23 -0
  240. package/dist/lib/hosts/routing-flag.js +41 -0
  241. package/dist/lib/hosts/run-target.js +1 -1
  242. package/dist/lib/hosts/session-index.js +1 -1
  243. package/dist/lib/hosts/tasks.d.ts +6 -6
  244. package/dist/lib/hosts/tasks.js +4 -4
  245. package/dist/lib/hosts/types.js +1 -2
  246. package/dist/lib/installations/resolve.js +2 -8
  247. package/dist/lib/isolation-boundary-report.js +0 -1
  248. package/dist/lib/linear-cache.d.ts +7 -0
  249. package/dist/lib/linear-cache.js +31 -4
  250. package/dist/lib/linear-project-counts.d.ts +1 -1
  251. package/dist/lib/linear-project-counts.js +2 -3
  252. package/dist/lib/linear-projects.js +1 -1
  253. package/dist/lib/loop.d.ts +2 -2
  254. package/dist/lib/loop.js +1 -1
  255. package/dist/lib/mailbox-target.d.ts +1 -1
  256. package/dist/lib/mailbox-target.js +1 -1
  257. package/dist/lib/manifest.js +7 -4
  258. package/dist/lib/menubar/MenubarHelper.app/Contents/CodeResources +0 -0
  259. package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
  260. package/dist/lib/menubar/snapshot.d.ts +3 -2
  261. package/dist/lib/menubar/snapshot.js +6 -2
  262. package/dist/lib/migrate-fold.d.ts +33 -0
  263. package/dist/lib/migrate-fold.js +130 -0
  264. package/dist/lib/migrate.d.ts +34 -34
  265. package/dist/lib/migrate.js +106 -128
  266. package/dist/lib/model-tier-overrides.d.ts +1 -1
  267. package/dist/lib/model-tier-overrides.js +15 -2
  268. package/dist/lib/monitors/config.d.ts +17 -3
  269. package/dist/lib/monitors/config.js +52 -18
  270. package/dist/lib/monitors/engine.d.ts +32 -1
  271. package/dist/lib/monitors/engine.js +94 -11
  272. package/dist/lib/monitors/fingerprint.d.ts +46 -0
  273. package/dist/lib/monitors/fingerprint.js +100 -0
  274. package/dist/lib/monitors/remote.d.ts +47 -0
  275. package/dist/lib/monitors/remote.js +81 -0
  276. package/dist/lib/monitors/state.d.ts +39 -0
  277. package/dist/lib/monitors/state.js +56 -0
  278. package/dist/lib/onepassword.d.ts +17 -0
  279. package/dist/lib/onepassword.js +52 -22
  280. package/dist/lib/open-url.js +1 -1
  281. package/dist/lib/picker.d.ts +14 -2
  282. package/dist/lib/picker.js +35 -13
  283. package/dist/lib/placement.d.ts +1 -1
  284. package/dist/lib/placement.js +1 -1
  285. package/dist/lib/pr-land-detach.d.ts +32 -0
  286. package/dist/lib/pr-land-detach.js +79 -0
  287. package/dist/lib/profiles-presets.js +13 -0
  288. package/dist/lib/profiles.d.ts +2 -0
  289. package/dist/lib/profiles.js +44 -1
  290. package/dist/lib/project-focus.d.ts +1 -1
  291. package/dist/lib/project-focus.js +1 -1
  292. package/dist/lib/project-probe.d.ts +4 -1
  293. package/dist/lib/project-probe.js +5 -4
  294. package/dist/lib/project-resources.js +2 -18
  295. package/dist/lib/project-root.d.ts +16 -0
  296. package/dist/lib/project-root.js +20 -2
  297. package/dist/lib/projects.d.ts +20 -1
  298. package/dist/lib/projects.js +78 -1
  299. package/dist/lib/refresh-coordinator.d.ts +24 -0
  300. package/dist/lib/refresh-coordinator.js +52 -0
  301. package/dist/lib/registry.d.ts +2 -2
  302. package/dist/lib/registry.js +1 -1
  303. package/dist/lib/resource-aliases.d.ts +13 -0
  304. package/dist/lib/resource-aliases.js +26 -0
  305. package/dist/lib/resources/types.d.ts +1 -1
  306. package/dist/lib/resources.d.ts +16 -0
  307. package/dist/lib/resources.js +66 -10
  308. package/dist/lib/rotate.d.ts +3 -4
  309. package/dist/lib/rotate.js +4 -5
  310. package/dist/lib/routine-activation.d.ts +22 -2
  311. package/dist/lib/routine-activation.js +63 -16
  312. package/dist/lib/routine-context.d.ts +9 -2
  313. package/dist/lib/routine-context.js +21 -6
  314. package/dist/lib/routines-project.d.ts +58 -48
  315. package/dist/lib/routines-project.js +190 -159
  316. package/dist/lib/routines.d.ts +41 -6
  317. package/dist/lib/routines.js +92 -34
  318. package/dist/lib/run-defaults.d.ts +5 -0
  319. package/dist/lib/run-defaults.js +11 -1
  320. package/dist/lib/runner.d.ts +10 -8
  321. package/dist/lib/runner.js +122 -39
  322. package/dist/lib/secrets/Agents CLI.app/Contents/CodeResources +0 -0
  323. package/dist/lib/secrets/Agents CLI.app/Contents/MacOS/Agents CLI +0 -0
  324. package/dist/lib/secrets/agent.d.ts +10 -3
  325. package/dist/lib/secrets/agent.js +43 -8
  326. package/dist/lib/secrets/bundles.d.ts +1 -0
  327. package/dist/lib/secrets/bundles.js +92 -80
  328. package/dist/lib/secrets/index.js +32 -9
  329. package/dist/lib/secrets/install-helper.d.ts +4 -4
  330. package/dist/lib/secrets/install-helper.js +4 -4
  331. package/dist/lib/secrets/push.d.ts +40 -6
  332. package/dist/lib/secrets/push.js +58 -11
  333. package/dist/lib/secrets/read-backoff.d.ts +1 -1
  334. package/dist/lib/secrets/read-backoff.js +1 -1
  335. package/dist/lib/secrets/remote.d.ts +24 -0
  336. package/dist/lib/secrets/remote.js +54 -4
  337. package/dist/lib/self-update.d.ts +108 -0
  338. package/dist/lib/self-update.js +276 -1
  339. package/dist/lib/session/active.d.ts +89 -5
  340. package/dist/lib/session/active.js +165 -10
  341. package/dist/lib/session/actor-sidecar.d.ts +1 -1
  342. package/dist/lib/session/actor-sidecar.js +2 -1
  343. package/dist/lib/session/db.d.ts +176 -2
  344. package/dist/lib/session/db.js +484 -17
  345. package/dist/lib/session/discover.js +27 -4
  346. package/dist/lib/session/hook-sessions.js +2 -2
  347. package/dist/lib/session/host-link.d.ts +2 -2
  348. package/dist/lib/session/host-link.js +2 -2
  349. package/dist/lib/session/pid-registry.d.ts +21 -0
  350. package/dist/lib/session/pid-registry.js +57 -0
  351. package/dist/lib/session/remote-active.js +15 -1
  352. package/dist/lib/session/remote.js +2 -2
  353. package/dist/lib/session/session-cache.d.ts +14 -7
  354. package/dist/lib/session/session-cache.js +51 -9
  355. package/dist/lib/session/state.d.ts +2 -2
  356. package/dist/lib/session/state.js +1 -1
  357. package/dist/lib/session/sync/config.d.ts +10 -10
  358. package/dist/lib/session/sync/config.js +10 -10
  359. package/dist/lib/session/sync/r2.d.ts +34 -0
  360. package/dist/lib/session/sync/r2.js +123 -0
  361. package/dist/lib/session/throughput.d.ts +1 -1
  362. package/dist/lib/session/throughput.js +1 -1
  363. package/dist/lib/session/types.d.ts +23 -1
  364. package/dist/lib/session/types.js +15 -0
  365. package/dist/lib/session/viewing-in.d.ts +1 -1
  366. package/dist/lib/session/viewing-in.js +1 -1
  367. package/dist/lib/session/watch.d.ts +101 -0
  368. package/dist/lib/session/watch.js +242 -0
  369. package/dist/lib/share/config.d.ts +4 -0
  370. package/dist/lib/share/config.js +1 -0
  371. package/dist/lib/share/provision.d.ts +38 -0
  372. package/dist/lib/share/provision.js +50 -0
  373. package/dist/lib/share/publish.d.ts +40 -1
  374. package/dist/lib/share/publish.js +116 -3
  375. package/dist/lib/share/worker-template.js +71 -6
  376. package/dist/lib/shims.d.ts +17 -3
  377. package/dist/lib/shims.js +98 -26
  378. package/dist/lib/signin-badge.js +3 -2
  379. package/dist/lib/skills.js +2 -0
  380. package/dist/lib/smart-launch.d.ts +8 -8
  381. package/dist/lib/smart-launch.js +80 -59
  382. package/dist/lib/ssh-exec.d.ts +1 -1
  383. package/dist/lib/ssh-exec.js +1 -1
  384. package/dist/lib/staleness/prune.d.ts +88 -0
  385. package/dist/lib/staleness/prune.js +69 -0
  386. package/dist/lib/staleness/registry.d.ts +1 -1
  387. package/dist/lib/staleness/writers/commands.js +34 -2
  388. package/dist/lib/staleness/writers/hooks.js +16 -0
  389. package/dist/lib/staleness/writers/kinds.d.ts +6 -0
  390. package/dist/lib/staleness/writers/skills.js +19 -0
  391. package/dist/lib/staleness/writers/subagents.d.ts +2 -3
  392. package/dist/lib/staleness/writers/subagents.js +0 -4
  393. package/dist/lib/staleness/writers/types.d.ts +32 -0
  394. package/dist/lib/startup/command-registry.d.ts +6 -12
  395. package/dist/lib/startup/command-registry.js +11 -31
  396. package/dist/lib/startup/dev-build.d.ts +10 -0
  397. package/dist/lib/startup/dev-build.js +13 -1
  398. package/dist/lib/startup/spellcheck.d.ts +18 -0
  399. package/dist/lib/startup/spellcheck.js +45 -0
  400. package/dist/lib/state.d.ts +36 -9
  401. package/dist/lib/state.js +96 -46
  402. package/dist/lib/subagents-registry.d.ts +0 -7
  403. package/dist/lib/subagents-registry.js +38 -65
  404. package/dist/lib/subagents.d.ts +0 -33
  405. package/dist/lib/subagents.js +0 -75
  406. package/dist/lib/sync-umbrella.js +1 -1
  407. package/dist/lib/teams/agents.d.ts +41 -1
  408. package/dist/lib/teams/agents.js +187 -9
  409. package/dist/lib/teams/api.d.ts +11 -1
  410. package/dist/lib/teams/api.js +11 -2
  411. package/dist/lib/teams/delivery.d.ts +41 -0
  412. package/dist/lib/teams/delivery.js +60 -0
  413. package/dist/lib/teams/registry.d.ts +14 -0
  414. package/dist/lib/teams/registry.js +51 -1
  415. package/dist/lib/teams/remoteWorktree.d.ts +19 -0
  416. package/dist/lib/teams/remoteWorktree.js +29 -0
  417. package/dist/lib/teams/scheduler.d.ts +1 -1
  418. package/dist/lib/teams/scheduler.js +1 -1
  419. package/dist/lib/teams/worktree.d.ts +24 -0
  420. package/dist/lib/teams/worktree.js +42 -0
  421. package/dist/lib/terminal/backends/vscodium-agent.d.ts +10 -1
  422. package/dist/lib/terminal/backends/vscodium-agent.js +16 -5
  423. package/dist/lib/terminal/engine.d.ts +4 -0
  424. package/dist/lib/terminal/engine.js +8 -2
  425. package/dist/lib/terminal/types.d.ts +21 -2
  426. package/dist/lib/testdata/refresh-coordinator-worker.d.ts +1 -0
  427. package/dist/lib/testdata/refresh-coordinator-worker.js +23 -0
  428. package/dist/lib/tickets/list.d.ts +53 -0
  429. package/dist/lib/tickets/list.js +153 -0
  430. package/dist/lib/tmux/orphan-reap.d.ts +320 -0
  431. package/dist/lib/tmux/orphan-reap.js +644 -0
  432. package/dist/lib/tmux/session.d.ts +68 -3
  433. package/dist/lib/tmux/session.js +95 -5
  434. package/dist/lib/triggers/handlers.d.ts +20 -0
  435. package/dist/lib/triggers/handlers.js +6 -1
  436. package/dist/lib/types.d.ts +46 -34
  437. package/dist/lib/usage-fleet.d.ts +32 -0
  438. package/dist/lib/usage-fleet.js +125 -0
  439. package/dist/lib/usage-refresh.d.ts +3 -3
  440. package/dist/lib/usage-refresh.js +19 -16
  441. package/dist/lib/usage.d.ts +51 -47
  442. package/dist/lib/usage.js +145 -153
  443. package/dist/lib/version-duplicates.js +2 -2
  444. package/dist/lib/versions.d.ts +56 -13
  445. package/dist/lib/versions.js +195 -45
  446. package/dist/lib/watchdog/log.d.ts +1 -1
  447. package/dist/lib/watchdog/log.js +3 -3
  448. package/dist/lib/watchdog/rotate.d.ts +6 -6
  449. package/dist/lib/watchdog/rotate.js +6 -6
  450. package/dist/lib/workflows.d.ts +1 -1
  451. package/dist/lib/yaml-io.d.ts +47 -0
  452. package/dist/lib/yaml-io.js +55 -0
  453. package/package.json +2 -1
  454. package/scripts/install-helper.js +2 -2
  455. package/scripts/postinstall.js +23 -20
  456. package/dist/commands/defaults.d.ts +0 -7
  457. package/dist/commands/defaults.js +0 -107
  458. package/dist/commands/export.d.ts +0 -11
  459. package/dist/commands/export.js +0 -215
  460. package/dist/commands/helper.d.ts +0 -12
  461. package/dist/commands/helper.js +0 -87
  462. package/dist/commands/hosts.d.ts +0 -11
  463. package/dist/commands/hosts.js +0 -330
  464. package/dist/commands/lock.d.ts +0 -12
  465. package/dist/commands/lock.js +0 -70
  466. package/dist/commands/pull.d.ts +0 -17
  467. package/dist/commands/pull.js +0 -39
  468. package/dist/commands/push.d.ts +0 -14
  469. package/dist/commands/push.js +0 -30
  470. package/dist/commands/wallet.d.ts +0 -20
  471. package/dist/commands/wallet.js +0 -216
  472. package/dist/commands/worktree.d.ts +0 -19
  473. package/dist/commands/worktree.js +0 -272
  474. package/dist/lib/account-labels.d.ts +0 -24
  475. package/dist/lib/account-labels.js +0 -72
  476. package/dist/lib/auto-dispatch-linear.d.ts +0 -18
  477. package/dist/lib/auto-dispatch-linear.js +0 -107
  478. package/dist/lib/auto-dispatch-provider.d.ts +0 -10
  479. package/dist/lib/auto-dispatch-provider.js +0 -30
  480. package/dist/lib/auto-dispatch.d.ts +0 -93
  481. package/dist/lib/auto-dispatch.js +0 -128
  482. package/dist/lib/export.d.ts +0 -72
  483. package/dist/lib/export.js +0 -269
  484. package/dist/lib/lock.d.ts +0 -93
  485. package/dist/lib/lock.js +0 -207
  486. package/dist/lib/wallet/index.d.ts +0 -78
  487. package/dist/lib/wallet/index.js +0 -253
@@ -1,7 +1,7 @@
1
1
  /**
2
- * `agents lease` — manage the disposable cloud boxes used by `agents run --lease`.
2
+ * `agents devices lease` — manage the disposable cloud boxes used by `agents run --lease`.
3
3
  *
4
- * Today: `agents lease gc`, which stops expired + idle "orphan" boxes that are
4
+ * Today: `agents devices lease gc`, which stops expired + idle "orphan" boxes that are
5
5
  * holding a provider's server quota (the cause of the `server_limit` 403 a new
6
6
  * lease hits). Reaping is conservative: only boxes whose lease has expired AND
7
7
  * that have been untouched for a safety window are eligible (see `isReapSafe`),
@@ -25,7 +25,7 @@ export declare function boxStatus(box: CrabboxBox): string;
25
25
  * freshest box (an untouched `lastTouchedAt` sorts last).
26
26
  */
27
27
  export declare function reusableBoxes(boxes: CrabboxBox[], nowSecs: number): CrabboxBox[];
28
- /** One aligned row for the reuse picker / `agents lease list`. */
28
+ /** One aligned row for the reuse picker / `agents devices lease list`. */
29
29
  export declare function formatBoxRow(box: CrabboxBox, nowSecs: number): string;
30
30
  /** Validate a Hetzner token against the live API. Exported for unit tests (fetch injectable). */
31
31
  export declare function validateHetznerToken(token: string, fetchImpl?: typeof fetch): Promise<'valid' | 'invalid' | 'unreachable'>;
@@ -39,4 +39,4 @@ export declare function validateHetznerToken(token: string, fetchImpl?: typeof f
39
39
  export declare function runLeaseSetup(opts?: {
40
40
  provider?: string;
41
41
  }): Promise<boolean>;
42
- export declare function registerLeaseCommand(program: Command): void;
42
+ export declare function registerLeaseCommand(devicesCommand: Command): void;
@@ -1,7 +1,7 @@
1
1
  /**
2
- * `agents lease` — manage the disposable cloud boxes used by `agents run --lease`.
2
+ * `agents devices lease` — manage the disposable cloud boxes used by `agents run --lease`.
3
3
  *
4
- * Today: `agents lease gc`, which stops expired + idle "orphan" boxes that are
4
+ * Today: `agents devices lease gc`, which stops expired + idle "orphan" boxes that are
5
5
  * holding a provider's server quota (the cause of the `server_limit` 403 a new
6
6
  * lease hits). Reaping is conservative: only boxes whose lease has expired AND
7
7
  * that have been untouched for a safety window are eligible (see `isReapSafe`),
@@ -64,7 +64,7 @@ export function reusableBoxes(boxes, nowSecs) {
64
64
  .filter((b) => b.ready && (b.expiresAt === null || b.expiresAt > nowSecs))
65
65
  .sort((a, b) => (b.lastTouchedAt ?? 0) - (a.lastTouchedAt ?? 0));
66
66
  }
67
- /** One aligned row for the reuse picker / `agents lease list`. */
67
+ /** One aligned row for the reuse picker / `agents devices lease list`. */
68
68
  export function formatBoxRow(box, nowSecs) {
69
69
  const slug = box.slug.padEnd(16);
70
70
  const cls = (box.class ?? '?').padEnd(10);
@@ -201,8 +201,8 @@ export async function runLeaseSetup(opts = {}) {
201
201
  throw e;
202
202
  }
203
203
  }
204
- export function registerLeaseCommand(program) {
205
- const lease = program
204
+ export function registerLeaseCommand(devicesCommand) {
205
+ const lease = devicesCommand
206
206
  .command('lease')
207
207
  .description('Manage the disposable cloud boxes used by `agents run --lease`.');
208
208
  lease
@@ -241,7 +241,7 @@ export function registerLeaseCommand(program) {
241
241
  console.log(chalk.bold(`Warm boxes (${boxes.length})`));
242
242
  for (const b of boxes)
243
243
  console.log(' ' + formatBoxRow(b, nowSecs));
244
- console.log(chalk.gray(' Reuse: agents run <agent> "…" --box <slug> · Stop: agents lease stop <slug>'));
244
+ console.log(chalk.gray(' Reuse: agents run <agent> "…" --box <slug> · Stop: agents devices lease stop <slug>'));
245
245
  });
246
246
  lease
247
247
  .command('stop <slug>')
@@ -107,17 +107,4 @@ export function registerLoginCommands(program) {
107
107
  clearVaultKey();
108
108
  console.log(chalk.green('Logged out. Synced secrets are locked.'));
109
109
  });
110
- program
111
- .command('whoami')
112
- .description('Show synced-secrets login status')
113
- .action(() => {
114
- const session = getVaultSession();
115
- if (!session.loggedIn) {
116
- console.log(chalk.yellow('Not logged in.'));
117
- console.log(chalk.gray(`File: ${vaultPath()}${vaultExists() ? '' : ' (not created)'}`));
118
- return;
119
- }
120
- console.log(chalk.green(`Logged in (${formatRemaining(session.expiresAt)} remaining).`));
121
- console.log(chalk.gray(`File: ${vaultPath()}`));
122
- });
123
110
  }
@@ -17,8 +17,8 @@
17
17
  * id, `--host`/`--agent`/`--version` filter a merged candidate list; one match is
18
18
  * shown, several open the fuzzy picker (or, non-TTY, print the list).
19
19
  *
20
- * Additive: `agents hosts logs` and `agents sessions tail` are unchanged and share
21
- * the same underlying helpers (showHostTaskLog / streamSessionTail).
20
+ * Additive: `agents devices ps`/`stop` and `agents sessions tail` are unchanged and
21
+ * share the same underlying helpers (showHostTaskLog / streamSessionTail).
22
22
  */
23
23
  import type { Command } from 'commander';
24
24
  /** Register the top-level `agents logs` command. */
@@ -17,8 +17,8 @@
17
17
  * id, `--host`/`--agent`/`--version` filter a merged candidate list; one match is
18
18
  * shown, several open the fuzzy picker (or, non-TTY, print the list).
19
19
  *
20
- * Additive: `agents hosts logs` and `agents sessions tail` are unchanged and share
21
- * the same underlying helpers (showHostTaskLog / streamSessionTail).
20
+ * Additive: `agents devices ps`/`stop` and `agents sessions tail` are unchanged and
21
+ * share the same underlying helpers (showHostTaskLog / streamSessionTail).
22
22
  */
23
23
  import chalk from 'chalk';
24
24
  import { discoverSessions, resolveSessionById } from '../lib/session/discover.js';
@@ -564,9 +564,11 @@ Examples:
564
564
  }
565
565
  console.log();
566
566
  });
567
+ // Deprecated: superseded by `agents sync --mcp`. Kept as a warned, functional
568
+ // alias so old muscle-memory and scripts don't break.
567
569
  mcpCmd
568
- .command('register [name]')
569
- .description('Apply MCP servers from manifest to agent config files')
570
+ .command('register [name]', { hidden: true })
571
+ .description('Deprecated use `agents sync --mcp` instead.')
570
572
  .option('-a, --agents <list>', 'Override manifest targets: claude, codex@0.116.0')
571
573
  .option('-y, --yes', 'Auto-install any missing agent versions without prompting')
572
574
  .addHelpText('after', `
@@ -581,6 +583,9 @@ Examples:
581
583
  agents mcp register --agents codex@0.116.0
582
584
  `)
583
585
  .action(async (name, options) => {
586
+ console.warn(chalk.yellow('`agents mcp register` is deprecated — use `agents sync --mcp` instead:'));
587
+ console.warn(chalk.gray(' all servers: agents sync --mcp'));
588
+ console.warn(chalk.gray(' specific server: agents sync --mcp <name>'));
584
589
  const localPath = getUserAgentsDir();
585
590
  const manifest = readManifest(localPath);
586
591
  if (!manifest?.mcp) {
@@ -111,11 +111,16 @@ export function registerMemoryCommands(program) {
111
111
  console.log(chalk.dim(`# ${fact.name} [${fact.layer}] ${fact.path}`));
112
112
  console.log(fs.readFileSync(fact.path, 'utf-8'));
113
113
  });
114
+ // Deprecated: superseded by `agents sync --memory`. Kept as a warned, functional
115
+ // alias so old muscle-memory and scripts don't break.
114
116
  memoryCmd
115
- .command('sync [agent]')
116
- .description('Copy canonical memory into capable agent version homes')
117
+ .command('sync [agent]', { hidden: true })
118
+ .description('Deprecated use `agents sync --memory` instead.')
117
119
  .option('-a, --agent <agent>', 'Limit to one agent (or agent@version)')
118
120
  .action(async (agentArg, options) => {
121
+ console.warn(chalk.yellow('`agents memory sync` is deprecated — use `agents sync --memory` instead:'));
122
+ console.warn(chalk.gray(' all agents: agents sync --memory'));
123
+ console.warn(chalk.gray(' one agent: agents sync --memory <agent>'));
119
124
  ensureUserMemoryDir();
120
125
  const input = agentArg || options.agent;
121
126
  if (input) {
@@ -12,7 +12,7 @@
12
12
  * written on the host that actually owns the agent. A caller who doesn't already
13
13
  * know the host (a detached `agents run --device <h> --no-follow` dispatch) is
14
14
  * still resolved automatically: a `target` matching no local/cloud session falls
15
- * through to the `~/.agents/.cache/hosts/` records `agents hosts ps` reads
15
+ * through to the `~/.agents/.cache/hosts/` records `agents devices ps` reads
16
16
  * (RUSH-2366 follow-up — see decideHostTaskRoute in lib/mailbox-target.ts), and
17
17
  * the message is rerouted there.
18
18
  *
@@ -2,7 +2,7 @@ import chalk from 'chalk';
2
2
  import { spawn } from 'child_process';
3
3
  import { die } from '../lib/format.js';
4
4
  import { parseDuration } from '../lib/hooks/cache.js';
5
- import { getActiveSessions } from '../lib/session/active.js';
5
+ import { getActiveSessions, isSessionIdLiveOnProcessTable } from '../lib/session/active.js';
6
6
  import { getTaskById, updateTaskStatus } from '../lib/cloud/store.js';
7
7
  import { resolveProvider } from '../lib/cloud/registry.js';
8
8
  import { mailboxDir, enqueue } from '../lib/mailbox.js';
@@ -119,7 +119,7 @@ async function deliverViaResume(route, mailboxId) {
119
119
  * dispatch (RUSH-2366 follow-up). `getActiveSessions()` never sees these: the
120
120
  * live process is on the dispatch's host, not this machine, so the local
121
121
  * session resolver in `resolveMessageTarget` reports "no running agent" even
122
- * while `agents hosts ps` shows the same dispatch running with a live remote
122
+ * while `agents devices ps` shows the same dispatch running with a live remote
123
123
  * pid — the only recovery was kill-and-redispatch, losing all context.
124
124
  *
125
125
  * Re-spawns `agents message <remoteRef> <text> --host <host>` through
@@ -251,11 +251,42 @@ export function registerMessageCommand(program) {
251
251
  return;
252
252
  }
253
253
  case 'none': {
254
+ // RUSH-2384: a live local process can still advertise `--session-id
255
+ // <target>` in its argv when getActiveSessions lost the row (empty
256
+ // by-pid registry, teams status flap, fold into a parent). Mailbox
257
+ // delivery only needs the id — prove liveness from the process table
258
+ // before giving up, so a mid-run agent is never unreachable while
259
+ // its pid is alive.
260
+ if (await isSessionIdLiveOnProcessTable(target)) {
261
+ try {
262
+ const block = findOpenBlockForMailbox(target);
263
+ const route = resolveAnswerRoute({
264
+ mailboxId: target,
265
+ answer: text,
266
+ block,
267
+ session: null,
268
+ });
269
+ if (route.kind === 'refuse')
270
+ die(route.reason);
271
+ claimBlockAnswer(block, opts);
272
+ if (route.kind === 'mailbox') {
273
+ await deliverViaMailbox(target, text, block, { from: opts.from, ttlSeconds });
274
+ return;
275
+ }
276
+ die(`Live process carries --session-id ${target} but needs a ${route.kind} rail ` +
277
+ `that is unavailable without an active-session row. Retry after the session ` +
278
+ `reappears in \`agents sessions --active\`, or inject into its terminal directly.`);
279
+ }
280
+ catch (err) {
281
+ die(err.message);
282
+ }
283
+ return;
284
+ }
254
285
  // Not a local/cloud session — check whether it's a detached
255
286
  // `--device ... --no-follow` dispatch, which `getActiveSessions()`
256
287
  // never sees (its live process is on another host). Same records
257
- // `agents hosts ps` reads, so the two commands never disagree.
258
- // Heal first, exactly as `hosts stop`/`hosts ps` do: a detached
288
+ // `agents devices ps` reads, so the two commands never disagree.
289
+ // Heal first, exactly as `agents devices stop`/`agents devices ps` do: a detached
259
290
  // dispatch record never self-updates, so a finished run is still
260
291
  // stamped `status:'running'` on disk. Without this we'd route a dead
261
292
  // task through an SSH reroute that can only fail, instead of
@@ -269,9 +300,9 @@ export function registerMessageCommand(program) {
269
300
  if (hostRoute.kind === 'finished') {
270
301
  die(`Task '${target}' on host '${hostRoute.host}' already ${hostRoute.status}` +
271
302
  (hostRoute.exitCode !== undefined ? ` (exit ${hostRoute.exitCode})` : '') +
272
- `. Nothing to message. View its output: \`agents hosts logs ${target}\`.`);
303
+ `. Nothing to message. View its output: \`agents logs ${target}\`.`);
273
304
  }
274
- die(`No running agent or cloud task matches "${target}". List targets with \`agents sessions --active\` or \`agents hosts ps\`.`);
305
+ die(`No running agent or cloud task matches "${target}". List targets with \`agents sessions --active\` or \`agents devices ps\`.`);
275
306
  }
276
307
  }
277
308
  });
@@ -77,6 +77,7 @@ export function registerModelsCommand(program) {
77
77
  });
78
78
  // Override subcommands. These WRITE agents.yaml so the user never hand-edits it;
79
79
  // resolution is exact `<agent>@<version>` over `<agent>` over the auto guess.
80
+ const tierDeprecation = chalk.yellow('Deprecation: `agents models tier` is replaced by `agents config set run.<agent@version>.tier.<tier>`.');
80
81
  const tier = models
81
82
  .command('tier')
82
83
  .description('Override which model a cost tier resolves to (per harness, or per agent@version).');
@@ -85,6 +86,7 @@ export function registerModelsCommand(program) {
85
86
  .description('Pin a tier to a model. selector: <agent> or <agent>@<version> (e.g. kimi, kimi@0.19.2).')
86
87
  .action((selector, tierName, model) => {
87
88
  try {
89
+ console.warn(tierDeprecation);
88
90
  const entry = setTierOverride(selector, tierName, model);
89
91
  console.log(chalk.green(`✓ ${entry.selector} ${chalk.cyan(tierName.toLowerCase())} → ${chalk.bold(model)}`));
90
92
  }
@@ -98,6 +100,7 @@ export function registerModelsCommand(program) {
98
100
  .description('Clear one tier (or all tiers) back to the auto guess.')
99
101
  .action((selector, tierName) => {
100
102
  try {
103
+ console.warn(tierDeprecation);
101
104
  const changed = clearTierOverride(selector, tierName);
102
105
  console.log(changed ? chalk.green(`✓ cleared ${selector}${tierName ? ` ${tierName}` : ''}`) : chalk.gray('nothing to clear'));
103
106
  }
@@ -110,6 +113,7 @@ export function registerModelsCommand(program) {
110
113
  .command('list')
111
114
  .description('List all configured tier overrides.')
112
115
  .action(() => {
116
+ console.warn(tierDeprecation);
113
117
  const entries = listTierOverrides();
114
118
  if (entries.length === 0) {
115
119
  console.log(chalk.gray('No tier overrides — every tier uses the auto guess. Set one with `agents models tier set`.'));
@@ -8,5 +8,4 @@
8
8
  * source instead of a clock.
9
9
  */
10
10
  import type { Command } from 'commander';
11
- /** Register the `agents monitors` command tree. */
12
11
  export declare function registerMonitorsCommands(program: Command): void;
@@ -12,9 +12,12 @@ import * as fs from 'fs';
12
12
  import * as path from 'path';
13
13
  import * as yaml from 'yaml';
14
14
  import { isDaemonRunning, signalDaemonReload, startDaemon, } from '../lib/daemon.js';
15
- import { listMonitors, readMonitor, writeMonitor, deleteMonitor, setMonitorEnabled, getMonitorPath, validateMonitor, monitorRunsOnThisDevice, } from '../lib/monitors/config.js';
16
- import { evaluateMonitorOnce } from '../lib/monitors/engine.js';
17
- import { listFires, readState } from '../lib/monitors/state.js';
15
+ import { findDuplicateMonitor, monitorFingerprint } from '../lib/monitors/fingerprint.js';
16
+ import { gatherFleetMonitors, NO_MONITOR_FANOUT_ENV } from '../lib/monitors/remote.js';
17
+ import { listMonitors, readMonitor, writeMonitor, deleteMonitor, setMonitorEnabled, getMonitorPath, validateMonitor, monitorRunsOnThisDevice, parseInterval, } from '../lib/monitors/config.js';
18
+ import { formatRelativeTime } from '../lib/session/relative-time.js';
19
+ import { evaluateMonitorOnce, POLL_SOURCE_TYPES } from '../lib/monitors/engine.js';
20
+ import { listFires, readState, readLiveness } from '../lib/monitors/state.js';
18
21
  import { listRuns, getLatestRun, getRunDir } from '../lib/routines.js';
19
22
  import { getMonitorsDir } from '../lib/state.js';
20
23
  import { IS_WINDOWS } from '../lib/platform/index.js';
@@ -72,6 +75,54 @@ function ownerLabel(monitor) {
72
75
  return monitor.devices.join(',');
73
76
  return 'all';
74
77
  }
78
+ /** A monitor's evaluation cadence in ms (falls back to the engine default). */
79
+ function monitorIntervalMs(monitor) {
80
+ if (monitor.source.interval)
81
+ return parseInterval(monitor.source.interval) ?? 60_000;
82
+ return 60_000;
83
+ }
84
+ /**
85
+ * True when an enabled, locally-owned monitor's last poll is far enough past its
86
+ * interval that the engine has plainly stopped checking it (dead engine, swallowed
87
+ * start failure, never picked up). Tolerates a few missed ticks before flagging.
88
+ */
89
+ function isStalled(monitor, liveness) {
90
+ if (!monitor.enabled || !monitorRunsOnThisDevice(monitor))
91
+ return false;
92
+ if (!liveness)
93
+ return false; // "never polled" is its own state, handled separately
94
+ const staleAfter = Math.max(monitorIntervalMs(monitor) * 3, 90_000);
95
+ return Date.now() - new Date(liveness.lastCheckedAt).getTime() > staleAfter;
96
+ }
97
+ /**
98
+ * The human liveness line for a monitor. This is the RUSH-2485 fix: it makes
99
+ * "the engine has never touched this" (`never polled`) visibly distinct from
100
+ * "polling steadily, condition just isn't matching" (`checked Nx`), from a real
101
+ * fire, and from a stalled engine.
102
+ */
103
+ function livenessLabel(monitor, state, liveness) {
104
+ const here = monitorRunsOnThisDevice(monitor);
105
+ if (!monitor.enabled)
106
+ return chalk.gray('paused');
107
+ if (!here) {
108
+ // Not owned by this box — this daemon never checks it, so there's no local
109
+ // liveness to report; fall back to fire history if the owner synced it.
110
+ return state?.lastFiredAt ? chalk.gray(`fired ${formatRelativeTime(state.lastFiredAt)}`) : chalk.gray('owned elsewhere');
111
+ }
112
+ if (!liveness)
113
+ return chalk.yellow('never polled');
114
+ if (isStalled(monitor, liveness)) {
115
+ return chalk.red(`STALLED — last poll ${formatRelativeTime(liveness.lastCheckedAt)}`);
116
+ }
117
+ const checkedAgo = formatRelativeTime(liveness.lastCheckedAt);
118
+ if (liveness.lastError) {
119
+ return chalk.red(`checked ${liveness.checkCount}x · error: ${liveness.lastError.replace(/\s+/g, ' ').slice(0, 60)}`);
120
+ }
121
+ if (state?.lastFiredAt) {
122
+ return chalk.green(`fired ${formatRelativeTime(state.lastFiredAt)}`) + chalk.gray(` · checked ${liveness.checkCount}x`);
123
+ }
124
+ return chalk.gray(`checked ${liveness.checkCount}x · last ${checkedAgo} · no match yet`);
125
+ }
75
126
  /** Start or reload the background daemon so a newly-added monitor is watched. */
76
127
  function ensureDaemonRunning() {
77
128
  if (isDaemonRunning()) {
@@ -88,6 +139,37 @@ function ensureDaemonRunning() {
88
139
  stderrLine(chalk.yellow('Could not start the daemon. Start it manually with: agents routines start'));
89
140
  }
90
141
  }
142
+ /**
143
+ * Assert the postcondition of `add`: the engine actually picked the monitor up.
144
+ * Config acceptance is not enough — RUSH-2485 was a monitor that added cleanly,
145
+ * listed as `on`, and never polled. A poll-model monitor owned by and enabled on
146
+ * this box should show a liveness heartbeat within a couple of engine ticks; wait
147
+ * for it and report the real outcome instead of reporting success on write. A
148
+ * miss is a warning, not a hard failure — a freshly-started daemon may still be
149
+ * booting — but it is surfaced so a dead engine can never masquerade as healthy.
150
+ */
151
+ async function assertEnginePickup(monitor) {
152
+ const pollSource = POLL_SOURCE_TYPES.has(monitor.source.type);
153
+ if (!monitor.enabled || !monitorRunsOnThisDevice(monitor) || !pollSource)
154
+ return; // nothing to assert here
155
+ const before = readLiveness(monitor.name);
156
+ const baseline = before?.checkCount ?? 0;
157
+ const deadline = Date.now() + 12_000; // a couple of 5s ticks, plus daemon-boot slack
158
+ stderrLine(chalk.gray(' waiting for the engine to poll it…'));
159
+ while (Date.now() < deadline) {
160
+ await new Promise((r) => setTimeout(r, 500));
161
+ const now = readLiveness(monitor.name);
162
+ if (now && now.checkCount > baseline) {
163
+ console.log(chalk.green(` engine picked it up — first poll ${formatRelativeTime(now.lastCheckedAt)}`));
164
+ if (now.lastError) {
165
+ stderrLine(chalk.yellow(` note: that poll errored — ${now.lastError.replace(/\s+/g, ' ').slice(0, 80)}`));
166
+ }
167
+ return;
168
+ }
169
+ }
170
+ stderrLine(chalk.yellow(` the engine has not polled '${monitor.name}' yet.`));
171
+ stderrLine(chalk.yellow(` confirm the daemon is running (agents routines status) and re-check with: agents monitors view ${monitor.name}`));
172
+ }
91
173
  /** Validate a single device name against the registered fleet; exit on miss. */
92
174
  async function validateDevice(name) {
93
175
  const normalized = normalizeHost(name.trim());
@@ -242,6 +324,58 @@ async function pickMonitor(message, alternatives = []) {
242
324
  }
243
325
  }
244
326
  /** Register the `agents monitors` command tree. */
327
+ /**
328
+ * Refuse a monitor that duplicates one already in play — same NAME (which
329
+ * `writeMonitor` would silently overwrite) or same BEHAVIOR under any name, on
330
+ * this box or any other. Exits the process on a refusal.
331
+ *
332
+ * Shared by BOTH `add` paths. The file path (`add ./watcher.yml`) returns early
333
+ * and used to skip the guard entirely, so a duplicate could be walked straight
334
+ * in through a YAML file — the one input an agent is most likely to generate.
335
+ */
336
+ async function guardAgainstDuplicateMonitor(config, force) {
337
+ if (force)
338
+ return;
339
+ const existing = listMonitors();
340
+ const sameName = existing.find((m) => m.name === config.name);
341
+ if (sameName) {
342
+ stderrLine(chalk.red(`Monitor '${config.name}' already exists — adding would overwrite it.`));
343
+ stderrLine(chalk.gray(` Inspect it: agents monitors view ${config.name}`));
344
+ stderrLine(chalk.gray(` Replace it: agents monitors add ${config.name} ... --force`));
345
+ process.exit(1);
346
+ }
347
+ const duplicate = findDuplicateMonitor(config, existing);
348
+ if (duplicate) {
349
+ stderrLine(chalk.red(`Monitor '${duplicate}' already watches this exact source and fires the same action.`));
350
+ stderrLine(chalk.gray(' Adding it again would fire the same trigger twice.'));
351
+ stderrLine(chalk.gray(` Inspect it: agents monitors view ${duplicate}`));
352
+ stderrLine(chalk.gray(` Add anyway: agents monitors add ${config.name} ... --force`));
353
+ process.exit(1);
354
+ }
355
+ // The case a local check cannot see: another agent, on another box, already
356
+ // watching this same work item with these same arguments. One work item, two
357
+ // triggers. Identity is the arguments, so the claim has to be fleet-wide —
358
+ // different arguments (another PR) are not a clash and still pass.
359
+ if (process.env[NO_MONITOR_FANOUT_ENV])
360
+ return;
361
+ const fleet = await gatherFleetMonitors();
362
+ const mine = monitorFingerprint(config);
363
+ const clash = fleet.monitors.find((r) => monitorFingerprint(r.monitor) === mine);
364
+ if (clash) {
365
+ stderrLine(chalk.red(`Monitor '${clash.monitor.name}' on ${chalk.bold(clash.machine)} already watches this exact source and fires the same action.`));
366
+ stderrLine(chalk.gray(' Two boxes watching one work item is a double trigger.'));
367
+ stderrLine(chalk.gray(` Inspect it: agents ssh ${clash.machine} 'agents monitors view ${clash.monitor.name}'`));
368
+ stderrLine(chalk.gray(` Add anyway: agents monitors add ${config.name} ... --force`));
369
+ process.exit(1);
370
+ }
371
+ // Never treat "could not ask" as "no duplicate".
372
+ if (fleet.discoveryFailed) {
373
+ stderrLine(chalk.yellow(' Note: could not reach the device registry — the fleet was not checked for duplicates.'));
374
+ }
375
+ else if (fleet.skipped.length > 0) {
376
+ stderrLine(chalk.yellow(` Note: could not check ${fleet.skipped.join(', ')} — a duplicate there would not have been caught.`));
377
+ }
378
+ }
245
379
  export function registerMonitorsCommands(program) {
246
380
  const monitorsCmd = program
247
381
  .command('monitors')
@@ -315,11 +449,12 @@ export function registerMonitorsCommands(program) {
315
449
  .option('--notify [channel]', 'Notify the owner (notify.owner); [channel] overrides the owner channel')
316
450
  .option('--webhook-out <url>', 'POST the event to this URL')
317
451
  // PLACEMENT / hygiene
318
- .option('--device <name>', 'OWNER (not body placement) — the single machine that evaluates + fires (exactly-once). See docs/00-concepts.md#placement.')
452
+ .option('--device <name>', 'OWNER (not body placement) — the single machine that evaluates + fires (exactly-once). See docs/concepts.md#placement.')
319
453
  .option('--devices <list>', 'Allowlist (comma-separated): each device fires independently')
320
454
  .option('--run-on <host>', 'BODY placement — execute the ACTION on this machine over SSH (same idea as run --where device:<host>)')
321
455
  .option('--rate-limit <spec>', 'Auto-pause if it fires more than N/<interval> (e.g. 5/1m)')
322
456
  .option('--disabled', 'Create the monitor paused (enable later with resume)')
457
+ .option('--force', 'Overwrite a same-named monitor, or add one that duplicates an existing watcher')
323
458
  .action(async (nameOrPath, options) => {
324
459
  // File mode: a single arg pointing at an existing .yml with no source flags.
325
460
  const hasSourceFlag = Boolean(options.watch || options.poll || options.pollHttp || options.on || options.ws || options.watchFile || options.watchDevice);
@@ -342,9 +477,11 @@ export function registerMonitorsCommands(program) {
342
477
  stderrLine(chalk.red(` - ${err}`));
343
478
  process.exit(1);
344
479
  }
480
+ await guardAgainstDuplicateMonitor(config, options.force === true);
345
481
  writeMonitor(config);
346
482
  console.log(chalk.green(`Monitor '${name}' added`));
347
483
  ensureDaemonRunning();
484
+ await assertEnginePickup(config);
348
485
  return;
349
486
  }
350
487
  if (!nameOrPath) {
@@ -413,10 +550,12 @@ export function registerMonitorsCommands(program) {
413
550
  if (condition.mode === 'match' && condition.match && /^(issued|success|ok|pass(ed)?|done|ready)$/i.test(condition.match)) {
414
551
  stderrLine(chalk.yellow(` Note: --match '${condition.match}' only fires on success — it stays silent if the source breaks or never matches.`));
415
552
  }
553
+ await guardAgainstDuplicateMonitor(config, options.force === true);
416
554
  writeMonitor(config);
417
555
  console.log(chalk.green(`Monitor '${nameOrPath}' added`));
418
556
  console.log(chalk.gray(` ${sourceLabel(source)} → [${condition.mode}] → ${actionLabel(action)} · owner: ${ownerLabel(config)}`));
419
557
  ensureDaemonRunning();
558
+ await assertEnginePickup(config);
420
559
  });
421
560
  // ─── list ────────────────────────────────────────────────────────────────────
422
561
  monitorsCmd
@@ -428,16 +567,28 @@ export function registerMonitorsCommands(program) {
428
567
  if (options.json) {
429
568
  const payload = monitors.map((m) => {
430
569
  const state = readState(m.name);
570
+ const liveness = readLiveness(m.name);
431
571
  return {
432
572
  name: m.name,
433
573
  enabled: m.enabled,
434
574
  source: m.source,
435
575
  condition: m.condition,
436
- action: { type: m.action.type },
576
+ // Full action, not just `type`: the cross-machine duplicate guard
577
+ // fingerprints source+condition+action, so a type-only action made
578
+ // every `--run` monitor unmatchable and the fleet check inert for
579
+ // exactly the case it exists for. `source` already ships whole.
580
+ action: m.action,
437
581
  owner: ownerLabel(m),
438
582
  runsHere: monitorRunsOnThisDevice(m),
439
583
  lastSeenAt: state?.lastSeenAt ?? null,
440
584
  lastFiredAt: state?.lastFiredAt ?? null,
585
+ // Liveness heartbeat (RUSH-2485): distinguishes never-polled from
586
+ // polling-not-matching from a stalled engine.
587
+ lastCheckedAt: liveness?.lastCheckedAt ?? null,
588
+ checkCount: liveness?.checkCount ?? 0,
589
+ lastError: liveness?.lastError ?? null,
590
+ consecutiveErrors: liveness?.consecutiveErrors ?? 0,
591
+ stalled: isStalled(m, liveness),
441
592
  };
442
593
  });
443
594
  stdoutJson(payload);
@@ -451,12 +602,12 @@ export function registerMonitorsCommands(program) {
451
602
  console.log(chalk.bold('Monitors\n'));
452
603
  for (const m of monitors) {
453
604
  const state = readState(m.name);
605
+ const liveness = readLiveness(m.name);
454
606
  const enabled = m.enabled ? chalk.green('on') : chalk.gray('off');
455
607
  const here = monitorRunsOnThisDevice(m);
456
608
  const owner = here ? ownerLabel(m) : chalk.gray(ownerLabel(m));
457
- const lastFired = state?.lastFiredAt ? `fired ${state.lastFiredAt}` : chalk.gray('never fired');
458
609
  console.log(` ${chalk.cyan(m.name.padEnd(22))} ${enabled.padEnd(3)} ${sourceLabel(m.source)}`);
459
- console.log(` ${' '.repeat(22)} ${chalk.gray(`[${m.condition.mode}]`)} → ${actionLabel(m.action)} ${chalk.gray(`owner: ${owner}`)} ${chalk.gray(lastFired)}`);
610
+ console.log(` ${' '.repeat(22)} ${chalk.gray(`[${m.condition.mode}]`)} → ${actionLabel(m.action)} ${chalk.gray(`owner: ${owner}`)} ${livenessLabel(m, state, liveness)}`);
460
611
  }
461
612
  console.log();
462
613
  });
@@ -477,6 +628,7 @@ export function registerMonitorsCommands(program) {
477
628
  process.exit(1);
478
629
  }
479
630
  const state = readState(name);
631
+ const liveness = readLiveness(name);
480
632
  const recentFires = listFires(name).slice(-5);
481
633
  if (options.json) {
482
634
  stdoutJson({
@@ -485,14 +637,30 @@ export function registerMonitorsCommands(program) {
485
637
  owner: ownerLabel(monitor),
486
638
  runsHere: monitorRunsOnThisDevice(monitor),
487
639
  state,
640
+ liveness,
641
+ stalled: isStalled(monitor, liveness),
488
642
  recentFires,
489
643
  });
490
644
  return;
491
645
  }
492
646
  console.log(chalk.bold(`Monitor: ${name}\n`));
493
647
  console.log(yaml.stringify(monitor));
648
+ // Liveness first (RUSH-2485): the heartbeat is the answer to "is this thing
649
+ // actually running?" — it renders even when the monitor has never fired.
650
+ console.log(chalk.bold('Liveness'));
651
+ console.log(` ${livenessLabel(monitor, state, liveness)}`);
652
+ if (liveness) {
653
+ console.log(chalk.gray(` last checked: ${liveness.lastCheckedAt} (${formatRelativeTime(liveness.lastCheckedAt)})`));
654
+ console.log(chalk.gray(` checks: ${liveness.checkCount}`));
655
+ if (liveness.lastError) {
656
+ console.log(chalk.red(` last error: ${liveness.lastError.replace(/\s+/g, ' ').slice(0, 200)} (${liveness.consecutiveErrors} in a row)`));
657
+ }
658
+ }
659
+ else if (monitor.enabled && monitorRunsOnThisDevice(monitor)) {
660
+ console.log(chalk.yellow(' The engine has not polled this monitor yet. If this persists, the daemon may not have picked it up — check: agents routines status'));
661
+ }
494
662
  if (state) {
495
- console.log(chalk.bold('Watched state'));
663
+ console.log(chalk.bold('\nWatched state'));
496
664
  console.log(chalk.gray(` last seen: ${state.lastSeenAt}`));
497
665
  if (state.lastFiredAt)
498
666
  console.log(chalk.gray(` last fired: ${state.lastFiredAt}`));
@@ -566,19 +734,29 @@ export function registerMonitorsCommands(program) {
566
734
  if (!name)
567
735
  return;
568
736
  }
737
+ // getMonitorPath is user-layer only: edits always land in the user dir,
738
+ // never the pull-only system mirror. Editing a system built-in (no user
739
+ // copy yet) materializes one, prefilled with the built-in's own config.
569
740
  let monitorPath = getMonitorPath(name);
570
741
  if (!monitorPath) {
571
742
  const dir = getMonitorsDir();
572
743
  fs.mkdirSync(dir, { recursive: true });
573
744
  monitorPath = safeJoin(dir, `${name}.yml`);
574
- const template = yaml.stringify({
575
- name,
576
- source: { type: 'poll', command: 'echo hello', interval: '1m' },
577
- condition: { mode: 'on-change' },
578
- action: { type: 'notify' },
579
- });
580
- fs.writeFileSync(monitorPath, template, 'utf-8');
581
- console.log(chalk.gray(`Created new monitor file: ${monitorPath}`));
745
+ const builtIn = readMonitor(name);
746
+ if (builtIn) {
747
+ fs.writeFileSync(monitorPath, yaml.stringify(builtIn), 'utf-8');
748
+ console.log(chalk.gray(`Editing a copy of built-in monitor '${name}' in your user dir: ${monitorPath}`));
749
+ }
750
+ else {
751
+ const template = yaml.stringify({
752
+ name,
753
+ source: { type: 'poll', command: 'echo hello', interval: '1m' },
754
+ condition: { mode: 'on-change' },
755
+ action: { type: 'notify' },
756
+ });
757
+ fs.writeFileSync(monitorPath, template, 'utf-8');
758
+ console.log(chalk.gray(`Created new monitor file: ${monitorPath}`));
759
+ }
582
760
  }
583
761
  const editor = process.env.EDITOR || process.env.VISUAL || (IS_WINDOWS ? 'notepad' : 'vi');
584
762
  const parts = editor.split(/\s+/).filter(Boolean);
@@ -772,6 +950,11 @@ export function registerMonitorsCommands(program) {
772
950
  stderrLine(chalk.gray('Daemon reloaded'));
773
951
  }
774
952
  }
953
+ else if (readMonitor(name)) {
954
+ // Resolvable but not in the user dir: a pull-only system built-in.
955
+ stderrLine(chalk.red(`Monitor '${name}' is a built-in and can't be removed; pause it with: agents monitors pause ${name}`));
956
+ process.exit(1);
957
+ }
775
958
  else {
776
959
  stderrLine(chalk.red(`Monitor '${name}' not found`));
777
960
  process.exit(1);
@@ -0,0 +1,18 @@
1
+ /**
2
+ * `agents open` — resolve an `agents://` deep link, and manage the OS handler
3
+ * that routes such links here.
4
+ *
5
+ * agents open agents://session/<id> resume that session in a terminal
6
+ * agents open register register the agents:// scheme with the OS
7
+ * agents open unregister remove the handler
8
+ * agents open status report whether the handler is registered
9
+ *
10
+ * A rendered artifact (plan/report) embeds `agents://session/<id>` in its
11
+ * provenance line; clicking it hands the URL to the OS, which invokes
12
+ * `agents open <url>`. This command parses it (lib/deeplink/url.ts) and hands the
13
+ * session id to the existing resume dispatcher, which resolves the owning host
14
+ * and opens the terminal with the cursor in the input bar. The id is passed as
15
+ * argv, never interpolated into a shell.
16
+ */
17
+ import type { Command } from 'commander';
18
+ export declare function registerOpenCommand(program: Command): void;