@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
@@ -14,14 +14,14 @@ import { spawn } from 'child_process';
14
14
  import { Option } from 'commander';
15
15
  import chalk from 'chalk';
16
16
  import { truncate, padRight, humanDuration } from '../lib/format.js';
17
- import { sanitizeForTerminal } from '../lib/redact.js';
17
+ import { sanitizeForTerminal, redactSecrets } from '../lib/redact.js';
18
18
  import { resolveProjectKey } from '../lib/project-key.js';
19
19
  import { listProjectDefs, resolveProjectNameForCwd } from '../lib/projects.js';
20
20
  import ora from 'ora';
21
21
  import { SESSION_AGENTS } from '../lib/session/types.js';
22
22
  import { discoverArtifacts, readArtifact, resolveArtifact } from '../lib/session/artifacts.js';
23
23
  import { looksLikePath, toComparablePath, homeDir, needsWindowsShell, composeWin32CommandLine } from '../lib/platform/index.js';
24
- import { getActiveSessions } from '../lib/session/active.js';
24
+ import { getActiveSessions, sessionProcessIsLocal } from '../lib/session/active.js';
25
25
  import { enumerateGhosttyTabs, assignGhosttyTabs } from '../lib/session/ghostty-tabs.js';
26
26
  import { mapPanesToTargets, listClients } from '../lib/tmux/session.js';
27
27
  import { resolveViewingIn, viewingInLabel } from '../lib/session/viewing-in.js';
@@ -29,10 +29,11 @@ import { machineId, normalizeHost } from '../lib/session/sync/config.js';
29
29
  import { gatherRemoteActive, NO_FANOUT_ENV } from '../lib/session/remote-active.js';
30
30
  import { loadFleetActiveSessions, loadLocalActiveSessions, } from '../lib/session/session-cache.js';
31
31
  import { gatherRemoteList, gatherRemoteToolProgramCounts, gatherRemoteToolSearch, runOnPeer } from '../lib/session/remote-list.js';
32
+ import { gatherRemoteAgentsJson } from '../lib/remote-agents-json.js';
32
33
  import { stringWidth, truncateToWidth, padToWidth, terminalWidth } from '../lib/session/width.js';
33
34
  import { inferSessionState } from '../lib/session/state.js';
34
35
  import { discoverSessions, queryIndexedSessions, countSessionsInScope, resolveSessionById, isCompleteSessionId, looksLikeSessionId, searchContentIndex, getSessionRoots, scopeToManaged } from '../lib/session/discover.js';
35
- import { findSessionsById, querySessions, getSessionById } from '../lib/session/db.js';
36
+ import { findSessionsById, querySessions, getSessionById, readSessionContent, readArchivedSessionPreview } from '../lib/session/db.js';
36
37
  import { filterTeamSessions, shouldShowTeamSessions, safeTeamText, groupSessionsByTeam, NO_TEAM_GROUP_KEY, } from '../lib/session/team-filter.js';
37
38
  import { parseSession } from '../lib/session/parse.js';
38
39
  import { runRemoteSessions, buildForwardedArgs, ensureWholeIndex } from '../lib/session/remote.js';
@@ -73,7 +74,10 @@ import { registerSessionsBackfillCommand } from './sessions-backfill.js';
73
74
  import { registerSessionsStatsCommand } from './sessions-stats.js';
74
75
  import { registerSessionsInsightsCommand } from './insights.js';
75
76
  import { registerSessionsOptimizeCommand } from './sessions-optimize.js';
77
+ import { registerSessionsWatchCommand } from './sessions-watch.js';
76
78
  import { runBrowserSessionsCommand } from './browser-sessions-picker.js';
79
+ import { runComputerSessionsCommand } from './computer-sessions-picker.js';
80
+ import { buildComputerSessionRows } from '../lib/computer/sessions-list.js';
77
81
  import { countToolProgramOccurrences, parseToolProgramCountClause, readToolIndexCoverage, searchToolCalls, TOOL_QUERY_MAX_CLAUSE_BYTES, TOOL_QUERY_MAX_CLAUSES, TOOL_QUERY_MAX_RESULT_SESSIONS, serializeToolSearchEnvelope, toolSearchRemoteReceiveBudget, } from '../lib/session/tool-index.js';
78
82
  const SESSION_AGENT_FILTER_HELP = `Filter by agent, e.g. claude, codex, claude@2.0.65`;
79
83
  function collectQueryClause(value, previous) {
@@ -669,6 +673,29 @@ export function serializeActiveSessionsForJson(sessions) {
669
673
  viewingIn: viewingInLabel(s) ?? null,
670
674
  }));
671
675
  }
676
+ /** Canonical JSON row consumed by resume pickers and other session UIs. */
677
+ export function serializeSessionPickerRows(sessions, liveSessions, self = machineId()) {
678
+ const liveById = new Map(liveSessions.filter((row) => row.sessionId).map((row) => [row.sessionId, row]));
679
+ return sessions.map((session) => {
680
+ const live = liveById.get(session.id);
681
+ const sourceDevice = live?.machine ?? session.machine ?? self;
682
+ const viewingIn = live ? viewingInLabel(live) ?? null : null;
683
+ const resumable = buildResumeCommand(session) !== null;
684
+ return {
685
+ ...session,
686
+ state: live?.status ?? 'inactive',
687
+ resumable,
688
+ unwatched: !viewingIn,
689
+ viewingIn,
690
+ sourceDevice,
691
+ lastActivityMs: live?.lastActivityMs ?? Date.parse(session.lastActivity ?? session.timestamp),
692
+ pid: live?.pid ?? null,
693
+ recovery: resumable
694
+ ? { command: 'agents', args: ['sessions', 'resume', session.id, '--device', sourceDevice], ...(session.cwd ? { cwd: session.cwd } : {}) }
695
+ : null,
696
+ };
697
+ });
698
+ }
672
699
  /**
673
700
  * Compact, colour-coded badges for the durable/awaiting signals. Text-only (no
674
701
  * emoji, per repo convention): `plan` / `ask` / `perm` for why it's waiting,
@@ -984,7 +1011,7 @@ export function groupSessionsByMachine(sessions, localMachine) {
984
1011
  * correlated, so they're all kept.
985
1012
  */
986
1013
  export function dedupeByMachineSession(sessions) {
987
- const seen = new Set();
1014
+ const seen = new Map();
988
1015
  const out = [];
989
1016
  for (const s of sessions) {
990
1017
  if (!s.sessionId) {
@@ -992,13 +1019,38 @@ export function dedupeByMachineSession(sessions) {
992
1019
  continue;
993
1020
  }
994
1021
  const key = `${s.machine ?? ''}:${s.sessionId}`;
995
- if (seen.has(key))
1022
+ const at = seen.get(key);
1023
+ if (at === undefined) {
1024
+ seen.set(key, out.length);
1025
+ out.push(s);
996
1026
  continue;
997
- seen.add(key);
998
- out.push(s);
1027
+ }
1028
+ // Both rows now describe the same session on the same machine, so the tie is
1029
+ // between the EXECUTING box's own row and the dispatcher's shim row for a
1030
+ // host-dispatched run (they only started colliding once foldExecutionMachine
1031
+ // attributed both to the executing host — RUSH-2479). The shim carries no
1032
+ // transcript and a `[host/<peer>]` placeholder label, so keeping it first
1033
+ // would strip a real preview off the merged fleet view. Prefer the row that
1034
+ // is not an offload shim; otherwise the first one still wins.
1035
+ if (out[at].offloadedFrom && !s.offloadedFrom)
1036
+ out[at] = s;
999
1037
  }
1000
1038
  return out;
1001
1039
  }
1040
+ /**
1041
+ * Narrow a gathered live set to the machines an explicit `--host`/`--device`
1042
+ * scope named. The gather picks which boxes to ASK; this asserts what the answer
1043
+ * may contain, and the two are not the same question: a host-dispatched run is
1044
+ * reported by the box that dispatched it while executing somewhere else, so
1045
+ * `--device <dispatcher>` used to list sessions that were not running there at
1046
+ * all (RUSH-2479). No scope → unchanged. Pure; exported for unit testing.
1047
+ */
1048
+ export function filterActiveSessionsByHostScope(sessions, hosts, self) {
1049
+ if (!hosts || hosts.length === 0)
1050
+ return sessions;
1051
+ const wanted = new Set(hosts.map(hostToken));
1052
+ return sessions.filter((s) => wanted.has(s.machine ?? self));
1053
+ }
1002
1054
  /**
1003
1055
  * Order a merged listing so the local machine's sessions come first, then each
1004
1056
  * remote machine as a contiguous block (more sessions first, then name), with
@@ -1090,6 +1142,41 @@ async function runRemoteSessionsJson(hosts) {
1090
1142
  const { sessions } = await gatherRemoteList(forwarded, hosts);
1091
1143
  process.stdout.write(serializeSessionsJson(sessions));
1092
1144
  }
1145
+ /** Parse one peer's computer-run array without accepting banners or partial
1146
+ * JSON. The fan-out boundary supplies the machine name when an older peer row
1147
+ * omitted it. */
1148
+ export function parseRemoteComputerSessionRows(stdout, machine) {
1149
+ try {
1150
+ const value = JSON.parse(stdout);
1151
+ if (!Array.isArray(value))
1152
+ return { items: [], valid: false };
1153
+ const items = value
1154
+ .filter((row) => Boolean(row && typeof row === 'object' && !Array.isArray(row)))
1155
+ .map((row) => ({ ...row, machine: row.machine || machine }));
1156
+ return { items, valid: true };
1157
+ }
1158
+ catch {
1159
+ return { items: [], valid: false };
1160
+ }
1161
+ }
1162
+ /** Collect computer history from named peers, or every automatic peer when
1163
+ * hosts is omitted. Every peer is forced to JSON and receives the recursion
1164
+ * guard through the shared fleet transport. */
1165
+ export async function gatherRemoteComputerSessionRows(hosts) {
1166
+ const hostSet = new Set(hosts ?? []);
1167
+ const forwarded = buildForwardedArgs(process.argv, hostSet);
1168
+ if (!forwarded.includes('--json'))
1169
+ forwarded.push('--json');
1170
+ if (!forwarded.includes('--no-interactive'))
1171
+ forwarded.push('--no-interactive');
1172
+ const result = await gatherRemoteAgentsJson({
1173
+ args: forwarded,
1174
+ noFanoutEnv: NO_FANOUT_ENV,
1175
+ hosts,
1176
+ parse: parseRemoteComputerSessionRows,
1177
+ });
1178
+ return result.items;
1179
+ }
1093
1180
  /**
1094
1181
  * `running N · idle N · waiting N · queued N · closed N · abandoned N · unknown N`
1095
1182
  * for a bucket of sessions (zero buckets omitted). Same bucketing as the summary so
@@ -1351,7 +1438,15 @@ async function gatherActiveSessionsLive(opts = {}) {
1351
1438
  merged = dedupeByMachineSession([...local, ...remote.sessions]);
1352
1439
  }
1353
1440
  }
1354
- return { sessions: merged, remoteDeviceCount };
1441
+ // Asking a box is not the same as a session running there: a host-dispatched
1442
+ // run is reported by its dispatcher while executing on the peer. Scope on the
1443
+ // machine the session runs on so `--device X` never lists someone else's work
1444
+ // (RUSH-2479). Applied here, in the single gather, so the interactive browser
1445
+ // gets the same answer as `--active --json`.
1446
+ return {
1447
+ sessions: filterActiveSessionsByHostScope(merged, opts.hosts, self),
1448
+ remoteDeviceCount,
1449
+ };
1355
1450
  }
1356
1451
  /**
1357
1452
  * Render the unified active-session view, grouped by machine. Scoping and the
@@ -1387,7 +1482,7 @@ async function renderActiveSessions(asJson, waitingOnly = false, opts = {}) {
1387
1482
  // is how a consumer distinguishes a session someone is looking at from one
1388
1483
  // running orphaned after its terminal died. tmux-only (no osascript) so the
1389
1484
  // scriptable path stays cheap — see enrichTmuxLocators.
1390
- await enrichTmuxLocators(sessions.filter(s => !s.machine || s.machine === self));
1485
+ await enrichTmuxLocators(sessions.filter(s => sessionProcessIsLocal(s, self)));
1391
1486
  process.stdout.write(JSON.stringify(serializeActiveSessionsForJson(sessions), null, 2) + '\n');
1392
1487
  if (waitingOnly && sessions.some(isAwaitingUser))
1393
1488
  process.exitCode = 1;
@@ -1402,7 +1497,7 @@ async function renderActiveSessions(asJson, waitingOnly = false, opts = {}) {
1402
1497
  // Enrich LOCAL sessions with jump locators (display-only, after the --json /
1403
1498
  // --waiting gates so scriptable output stays osascript-free). Remote sessions
1404
1499
  // keep their raw pane id — their tmux/Ghostty live on the other machine.
1405
- await enrichLocalLocators(sessions.filter(s => !s.machine || s.machine === self));
1500
+ await enrichLocalLocators(sessions.filter(s => sessionProcessIsLocal(s, self)));
1406
1501
  const grouped = groupSessionsByMachine(sessions, self);
1407
1502
  let firstMachine = true;
1408
1503
  for (const mg of grouped.machines) {
@@ -1944,9 +2039,15 @@ export async function renderSessionPreview(query, scope) {
1944
2039
  }
1945
2040
  }
1946
2041
  if (outcome.kind === 'partial') {
1947
- console.error(chalk.red(`Partial session resolution: ${outcome.failedPeers.join(', ')} did not answer.`));
1948
- console.error(chalk.gray('No preview was rendered because the short ID may be ambiguous on an unreachable peer.'));
1949
- process.exitCode = 2;
2042
+ // RUSH-2492: an unreachable peer is a warning, not a hard failure. The
2043
+ // resolver already resolves an id found on the reachable fleet (SES-9a),
2044
+ // so reaching here means the session was not found on any device we COULD
2045
+ // reach — it may live on an unreachable peer, which we could not check.
2046
+ const offline = outcome.failedPeers;
2047
+ console.error(chalk.yellow(`Warning: ${offline.length} device(s) unreachable, not checked: ${offline.join(', ')}`));
2048
+ console.error(chalk.red(`No session matching "${query}" on any reachable device (${offline.length} unreachable, not checked).`));
2049
+ console.error(chalk.gray(' If it lives on an offline box, wake it (agents devices) or run there: agents ssh <device>'));
2050
+ process.exitCode = 1;
1950
2051
  return;
1951
2052
  }
1952
2053
  if (outcome.kind === 'not-found') {
@@ -2722,7 +2823,14 @@ limitSource) {
2722
2823
  const filtered = searchQuery
2723
2824
  ? resolveSessionQuery(sessions, searchQuery).matches
2724
2825
  : sessions;
2725
- process.stdout.write(serializeSessionsJson(filtered));
2826
+ // JSON is the canonical picker contract: enrich the durable rows once
2827
+ // from the shared live cache so every consumer gets lifecycle/recovery
2828
+ // metadata without performing its own join or transcript scan.
2829
+ const live = await gatherActiveSessions({
2830
+ local: options.local === true || process.env[NO_FANOUT_ENV] === '1',
2831
+ hosts: options.host,
2832
+ });
2833
+ process.stdout.write(serializeSessionsJson(serializeSessionPickerRows(filtered, live.sessions)));
2726
2834
  return;
2727
2835
  }
2728
2836
  // Cross-machine fan-out: unless --local (or we ARE a peer answering a
@@ -3351,10 +3459,79 @@ export async function renderSessionLog(session, mode = 'summary') {
3351
3459
  export async function renderSessionLogJson(session) {
3352
3460
  await renderSession(session, 'json', {});
3353
3461
  }
3462
+ /**
3463
+ * Render a file-gone (archived) session from the local DB (RUSH-2436). The
3464
+ * transcript file is deleted, but the user turns survive in session_text and the
3465
+ * last-computed digest in session_preview_cache — serve those so `agents sessions
3466
+ * <id>` still shows the prompts instead of an empty metadata dump. User-turn text
3467
+ * is the durable content every harness stores; assistant text survives only as
3468
+ * the cached digest's `lastAssistant` snippet, shown when present.
3469
+ */
3470
+ function renderArchivedSession(session, mode, options = {}) {
3471
+ // Redact by default, mirroring the live render path (render.ts renderConversationMarkdown):
3472
+ // session_text stores raw user text, so masking is render-time. `--no-redact`
3473
+ // opts out, same as the live path.
3474
+ const redact = (text) => options.redact !== false ? redactSecrets(text) : text;
3475
+ const content = redact((readSessionContent(session.id) ?? '').trim());
3476
+ const digestRaw = readArchivedSessionPreview(session.id);
3477
+ const digest = digestRaw
3478
+ ? { ...digestRaw, lastAssistant: redact(digestRaw.lastAssistant ?? '') }
3479
+ : undefined;
3480
+ if (mode === 'json') {
3481
+ // Minimal machine shape for a file-gone session: the durable user content
3482
+ // plus the cached preview digest, tagged archived. Deliberately NOT the full
3483
+ // { session, events } contract — there are no events to parse. Redact the
3484
+ // first-message-excerpt meta fields (topic/label/plan) too, matching the live
3485
+ // single-session --json (render.ts redactJson), so `--json` masks them unless
3486
+ // --no-redact is passed.
3487
+ console.log(JSON.stringify({
3488
+ session: {
3489
+ ...session,
3490
+ topic: session.topic != null ? redact(session.topic) : session.topic,
3491
+ label: session.label != null ? redact(session.label) : session.label,
3492
+ plan: session.plan != null ? redact(session.plan) : session.plan,
3493
+ archived: true,
3494
+ },
3495
+ archived: true,
3496
+ userContent: content,
3497
+ preview: digest ?? null,
3498
+ }, null, 2));
3499
+ return;
3500
+ }
3501
+ const agentColor = colorAgent(session.agent);
3502
+ const absTime = formatAbsoluteTime(session.timestamp);
3503
+ const title = session.label || session.topic;
3504
+ console.log('');
3505
+ if (title)
3506
+ console.log(chalk.bold.white(title));
3507
+ console.log(agentColor(session.agent) +
3508
+ (session.version ? chalk.yellow(` ${session.version}`) : '') +
3509
+ (session.project ? chalk.cyan(` ${session.project}`) : '') +
3510
+ chalk.gray(` ${absTime} (${formatRelativeTime(session.timestamp)})`) +
3511
+ (session.account ? chalk.gray(` · ${session.account}`) : ''));
3512
+ console.log(chalk.yellow('archived — transcript file removed; user turns served from the local DB'));
3513
+ console.log(chalk.gray('─'.repeat(60)));
3514
+ console.log(chalk.cyan('User:'));
3515
+ console.log(content);
3516
+ if (digest?.lastAssistant?.trim()) {
3517
+ console.log('');
3518
+ console.log(chalk.magenta('Last assistant:'));
3519
+ console.log(digest.lastAssistant.trim());
3520
+ }
3521
+ }
3354
3522
  async function renderSession(session, mode, filters, options = {}) {
3355
3523
  // OpenCode stores sessions in SQLite; filePath is "db_path#session_id"
3356
3524
  const realPath = session.filePath.split('#')[0];
3357
3525
  if (!fs.existsSync(realPath)) {
3526
+ // The transcript file is gone, but the session's user turns are stored
3527
+ // durably in the local DB (session_text), so serve those instead of a bare
3528
+ // metadata dump (RUSH-2436). This is what makes an archived session still
3529
+ // render its prompts after `agents remove` / rm / a box reimage.
3530
+ const archivedContent = readSessionContent(session.id);
3531
+ if (archivedContent && archivedContent.trim() !== '') {
3532
+ renderArchivedSession(session, mode, options);
3533
+ return;
3534
+ }
3358
3535
  console.log(chalk.yellow('Session transcript not available (file no longer exists).'));
3359
3536
  console.log(chalk.gray(`Path: ${session.filePath}`));
3360
3537
  if (session.version)
@@ -4265,8 +4442,15 @@ async function renderOneSession(query, mode, scope) {
4265
4442
  if (looksLikeSessionId(query)) {
4266
4443
  const outcome = await resolveSessionMetadataValue(query, scope);
4267
4444
  if (outcome.kind === 'partial') {
4268
- console.error(chalk.red(`Partial session resolution: ${outcome.failedPeers.join(', ')} did not answer.`));
4269
- process.exit(2);
4445
+ // RUSH-2492: an unreachable peer is a warning, not a hard failure. The
4446
+ // resolver already resolves an id found on the reachable fleet (SES-9a),
4447
+ // so reaching here means the session was not found on any device we
4448
+ // COULD reach — it may live on an unreachable peer we could not check.
4449
+ const offline = outcome.failedPeers;
4450
+ console.error(chalk.yellow(`Warning: ${offline.length} device(s) unreachable, not checked: ${offline.join(', ')}`));
4451
+ console.error(chalk.red(`No session matching "${query}" on any reachable device (${offline.length} unreachable, not checked).`));
4452
+ console.error(chalk.gray(' If it lives on an offline box, wake it (agents devices) or run there: agents ssh <device>'));
4453
+ process.exit(1);
4270
4454
  }
4271
4455
  // An index miss can be a transcript created since the last incremental
4272
4456
  // scan, or a Claude history alias. Fall through to the established
@@ -4459,6 +4643,11 @@ const FULL_SESSION_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-
4459
4643
  * the wrong session (whichever peer replied first). Labels therefore stay
4460
4644
  * all-settle so a cross-machine label conflict surfaces as an ambiguity, and a
4461
4645
  * short-id PREFIX stays all-settle for the same reason (RUSH-2203).
4646
+ *
4647
+ * This is about cancelling a sweep that is still IN FLIGHT, where a peer that
4648
+ * has not answered yet is still expected to. It is deliberately stricter than
4649
+ * `isUniqueEnoughSelector`, which decides what to do once the sweep is OVER and
4650
+ * a peer has definitively not answered — see SES-9a.
4462
4651
  */
4463
4652
  export function isDefinitiveMatch(session, selector) {
4464
4653
  return FULL_SESSION_ID_RE.test(selector) && session.id.toLowerCase() === selector.trim().toLowerCase();
@@ -4545,23 +4734,54 @@ export function toolSearchForwardedArgs(argv, hosts) {
4545
4734
  args.push('--local');
4546
4735
  return args;
4547
4736
  }
4548
- /** Resolution fails closed for prefixes/keywords when a peer did not answer.
4549
- * A full UUID is globally unique, so one exact hit is sufficient even when an
4550
- * unrelated registered device is offline. */
4737
+ /** Width of the short id the CLI prints everywhere (`SessionMeta.shortId`):
4738
+ * 8 hex chars / 32 bits. A selector shorter than this is treated as a keyword,
4739
+ * not an identifier. */
4740
+ const SHORT_SESSION_ID_WIDTH = 8;
4741
+ /**
4742
+ * Whether a selector names ONE session precisely enough to resolve from the
4743
+ * reachable fleet alone when some peer did not answer (SES-9a).
4744
+ *
4745
+ * Deliberately stricter than `looksLikeSessionId`, which accepts any 6+ char
4746
+ * `[0-9a-f-]` run and so matches ordinary words (`facade`, `decade`, `beaded`).
4747
+ * Those are keywords a user typed as a search, not identifiers, and they must
4748
+ * keep waiting for every peer.
4749
+ */
4750
+ export function isUniqueEnoughSelector(selector) {
4751
+ const trimmed = selector.trim();
4752
+ if (isCompleteSessionId(trimmed))
4753
+ return true;
4754
+ return /^[0-9a-f-]+$/i.test(trimmed)
4755
+ && trimmed.replace(/-/g, '').length >= SHORT_SESSION_ID_WIDTH;
4756
+ }
4757
+ /** Resolution fails closed for keywords and labels when a peer did not answer.
4758
+ * An id-shaped selector at least `SHORT_SESSION_ID_WIDTH` hex chars wide (or a
4759
+ * complete id) resolves from a single reachable hit even when an unrelated
4760
+ * registered device is offline — see SES-9a for the accepted collision risk. */
4551
4761
  export function metadataResolveOutcome(localMatches, remote, selector) {
4552
4762
  // Every peer answered through --resolve-safe-v1, so its native-id row is
4553
4763
  // already the result of resolving the original selector. Re-filtering by the
4554
4764
  // selector would discard alias suffixes such as c1f3d813 because the native
4555
4765
  // UUID intentionally has a different prefix.
4556
4766
  const candidates = fleetCandidatesByQuery([...localMatches, ...remote.sessions], selector, true);
4557
- // A full UUID is globally unique, so one exact hit resolves even when an
4558
- // unrelated registered device is offline. A label is NOT globally unique a
4559
- // distinct session may carry the same label on an unreachable peer so it
4560
- // stays fail-closed: a unique label auto-resumes only once every peer has
4561
- // answered (candidates.length === 1 below), and an unreachable peer forces
4562
- // `partial` rather than guessing. (RUSH-2203: early-exit is UUID-only for the
4563
- // same reason see isDefinitiveMatch.)
4564
- if (FULL_SESSION_ID_RE.test(selector) && candidates.length === 1 && candidates[0].id.toLowerCase() === selector.toLowerCase()) {
4767
+ // One hit on the REACHABLE fleet resolves a precise-enough id selector even
4768
+ // when a peer is offline (SES-9a). This is a deliberate, bounded trade, not a
4769
+ // claim that prefixes cannot collide they can, which is why the `ambiguous`
4770
+ // branch below still exists for peers that DID answer:
4771
+ // - refusing costs 100% of lookups on any fleet with a permanently offline
4772
+ // device (9 of them here), to avoid a prefix collision that ALSO has to
4773
+ // land on the one box that did not answer. Rate depends on the id type:
4774
+ // a UUIDv4 short id is unique in practice, while a time-ordered
4775
+ // UUIDv7/ULID prefix is largely a timestamp and collides much more
4776
+ // readily (see deriveShortId in session/db.ts);
4777
+ // - `isUniqueEnoughSelector` keeps this off keyword-shaped queries, so a
4778
+ // 6-char word like `facade` or `decade` is not treated as an identifier.
4779
+ // A label stays fail-closed at any length: labels are free-form and collide by
4780
+ // design, so one hit there really is a guess.
4781
+ // (RUSH-2203's early-exit stays UUID-only — see isDefinitiveMatch — because
4782
+ // that cancels the sweep mid-flight, where a peer that has not answered YET is
4783
+ // still expected to answer. Here the sweep is already over.)
4784
+ if (isUniqueEnoughSelector(selector) && candidates.length === 1) {
4565
4785
  return { kind: 'resolved', session: candidates[0].hits[0].session };
4566
4786
  }
4567
4787
  if (remote.unreachable.length > 0)
@@ -4610,8 +4830,11 @@ export async function resolveSessionMetadataValue(selector, scope = {}, deps = {
4610
4830
  }
4611
4831
  /** Resolve one selector to indexed metadata across the fleet without reading or
4612
4832
  * rendering transcript events. A peer answering the parent sweep returns every
4613
- * local candidate; the parent performs the one logical-session uniqueness gate. */
4614
- async function resolveSessionMetadata(selector, scope, deps = { gatherRemoteList }) {
4833
+ * local candidate; the parent performs the one logical-session uniqueness gate.
4834
+ * Backs `agents sessions --resolve <selector> --json`. Exported (deps already
4835
+ * injectable) so tests can drive this real call site against a fake fan-out
4836
+ * instead of only the pure resolver it wraps. */
4837
+ export async function resolveSessionMetadata(selector, scope, deps = { gatherRemoteList }) {
4615
4838
  const localMachine = machineId();
4616
4839
  const includeLocal = !scope.hosts?.length || shouldIncludeLocal(scope.hosts, localMachine);
4617
4840
  const indexed = includeLocal ? indexedRowsForSelector(selector, scope) : [];
@@ -4625,9 +4848,15 @@ async function resolveSessionMetadata(selector, scope, deps = { gatherRemoteList
4625
4848
  }
4626
4849
  const outcome = await resolveSessionMetadataValue(selector, scope, deps);
4627
4850
  if (outcome.kind === 'partial') {
4628
- console.error(chalk.red(`Partial session resolution: ${outcome.failedPeers.join(', ')} did not answer.`));
4629
- console.error(chalk.gray('No unique/no-match decision was made. Upgrade or reconnect every peer, then retry.'));
4630
- process.exit(2);
4851
+ // RUSH-2492: an unreachable peer is a warning, not a hard failure. The
4852
+ // resolver already resolves an id found on the reachable fleet (SES-9a),
4853
+ // so reaching here means the session was not found on any device we
4854
+ // COULD reach — it may live on an unreachable peer we could not check.
4855
+ const offline = outcome.failedPeers;
4856
+ console.error(chalk.yellow(`Warning: ${offline.length} device(s) unreachable, not checked: ${offline.join(', ')}`));
4857
+ console.error(chalk.red(`No session matching "${selector}" on any reachable device (${offline.length} unreachable, not checked).`));
4858
+ console.error(chalk.gray(' If it lives on an offline box, wake it (agents devices) or run there: agents ssh <device>'));
4859
+ process.exit(1);
4631
4860
  }
4632
4861
  if (outcome.kind === 'not-found') {
4633
4862
  console.error(chalk.red(`No session found matching: ${selector}`));
@@ -4766,6 +4995,7 @@ export function registerSessionsCommands(program) {
4766
4995
  .option('--fleet', 'With --include tools: query every registered online compute device and merge compact matches')
4767
4996
  .option('--count', 'With one program:<name> tool query: count static occurrences, containing calls, and sessions')
4768
4997
  .option('--browser', 'List browser-profile captures (screenshots, PDFs, recordings, downloads) instead of agent transcripts — alias of `agents browser sessions`')
4998
+ .option('--computer', 'List computer-driving history, grouped by run, instead of agent transcripts — alias of `agents computer sessions`')
4769
4999
  .option('--no-interactive', 'Print the listing instead of opening the interactive browser (default on a TTY for the bare listing and --active)')
4770
5000
  .option('--print-cmd', 'Print the canonical `ag sessions …` command for the given flags and exit (the twin of the browser’s `y` hotkey)')
4771
5001
  .option('--preview', 'With a session id/query: print a compact preview and exit (no pager)');
@@ -4789,17 +5019,17 @@ export function registerSessionsCommands(program) {
4789
5019
  agents sessions --orphan
4790
5020
  agents sessions --crashed
4791
5021
 
4792
- # --- Session lifecycle (one verb per intent) ---
4793
- # Focus a session (attach its living terminal, or recover an ended one)
4794
- agents sessions focus a1b2c3d4
4795
- # Attach only never fork a copy (old: sessions go)
4796
- agents sessions focus a1b2c3d4 --attach-only
4797
- # Interactive headless (keep working unattended)
4798
- agents sessions detach a1b2c3d4
4799
- # Headless → interactive in this terminal
4800
- agents sessions attach a1b2c3d4
5022
+ # --- Session lifecycle ---
5023
+ # Get back into a session attaches a live pane, or recovers an ended one
5024
+ agents sessions resume a1b2c3d4
5025
+ # Same, by the tmux name shown in: agents tmux ls
5026
+ agents sessions resume ag-claude-a1b2c3d4
5027
+ # Attach only never fork a copy
5028
+ agents sessions resume a1b2c3d4 --attach-only
4801
5029
  # Multi-select history and open each in a tab
4802
5030
  agents sessions resume
5031
+ # The other direction: interactive → headless (keep working unattended)
5032
+ agents sessions detach a1b2c3d4
4803
5033
 
4804
5034
  # The interactive list folds in other online machines automatically,
4805
5035
  # labelled by host with this machine first. Stay local with --local:
@@ -4851,12 +5081,12 @@ export function registerSessionsCommands(program) {
4851
5081
  agents sessions --all "deploy script" --host box-a --host box-b
4852
5082
  `,
4853
5083
  notes: `
4854
- Session lifecycle (pick one verb they are not synonyms):
4855
- focus [selector] attach a living pane, or recover on the origin device
4856
- focus [id] --attach-only attach only; never fork (replaces sessions go)
4857
- detach <id> interactive headless continuation
4858
- attach <id> headless interactive in this terminal
4859
- resume [query] multi-select history open tabs (or run --resume <id>)
5084
+ Session lifecycle ONE verb gets you back in, it detects the state:
5085
+ resume <id|alias> live pane -> attach; headless -> foreground; ended -> recover
5086
+ resume <id> --attach-only attach only; never fork a copy
5087
+ resume multi-select history -> open tabs
5088
+ detach <id> the other direction: interactive -> headless
5089
+ (retired, still working for one release: sessions attach, sessions go, reconnect)
4860
5090
  - The interactive listing and every live-status flag fold in your other online machines automatically (live over SSH, no sync) — each row is labelled by host, this machine first. Use --local to skip the fan-out; single-id lookups stay local.
4861
5091
  - --all is not a device flag: it widens historical directory and time filters. Fleet collection is already the default. A status flag (--working/--idle/--waiting/--orphan/--crashed/--closed/--abandoned/--queued/--unknown) implies --active; combine status flags for a union.
4862
5092
  - --version <version> requires --agent and is equivalent to --agent <agent@version>.
@@ -4883,6 +5113,26 @@ export function registerSessionsCommands(program) {
4883
5113
  await runBrowserSessionsCommand({ profile: query, json: options.json, interactive: options.interactive });
4884
5114
  return;
4885
5115
  }
5116
+ if (options.computer) {
5117
+ // Alias for `agents computer sessions`: a machine positional narrows to
5118
+ // one machine. `--no-interactive` carries through the same way.
5119
+ const limit = options.limit === undefined ? undefined : Number.parseInt(options.limit, 10);
5120
+ const deviceArgs = [...(options.device ?? []), ...(options.devices ?? [])];
5121
+ const allFleet = deviceArgs.some((host) => ['all', 'fleet'].includes(host.toLowerCase()));
5122
+ const hosts = [...(options.host ?? []), ...deviceArgs]
5123
+ .filter((host) => !['all', 'fleet'].includes(host.toLowerCase()));
5124
+ if (hosts.length > 0 || allFleet) {
5125
+ const remoteRows = await gatherRemoteComputerSessionRows(allFleet ? undefined : hosts);
5126
+ const rows = allFleet
5127
+ ? [...buildComputerSessionRows({ machine: query }), ...remoteRows]
5128
+ : remoteRows;
5129
+ rows.sort((a, b) => b.endMs - a.endMs);
5130
+ await runComputerSessionsCommand({ rows, machine: query, limit, json: options.json, interactive: options.interactive });
5131
+ return;
5132
+ }
5133
+ await runComputerSessionsCommand({ machine: query, limit, json: options.json, interactive: options.interactive });
5134
+ return;
5135
+ }
4886
5136
  await sessionsAction(query, options, command.getOptionValueSource('limit'));
4887
5137
  });
4888
5138
  const previewCmd = sessionsCmd
@@ -4943,6 +5193,7 @@ export function registerSessionsCommands(program) {
4943
5193
  registerSessionsStatsCommand(sessionsCmd);
4944
5194
  registerSessionsInsightsCommand(sessionsCmd);
4945
5195
  registerSessionsOptimizeCommand(sessionsCmd);
5196
+ registerSessionsWatchCommand(sessionsCmd);
4946
5197
  // Observe-umbrella alias (Phase 3): roster → sessions --active.
4947
5198
  registerSessionsObserveAliases(program);
4948
5199
  }
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * `agents set claude@2.1.220 --model opus-5` pins the default model (and/or
5
5
  * mode) that `agents run` uses for that agent version. It reads and writes the
6
- * same store as `agents defaults run set` (agents.yaml -> run.defaults), so the
6
+ * same store as `agents config set run.<agent@version>.*` (agents.yaml -> run.defaults), so the
7
7
  * two stay consistent — `set` is just the short front door.
8
8
  *
9
9
  * agents set # list every configured default
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * `agents set claude@2.1.220 --model opus-5` pins the default model (and/or
5
5
  * mode) that `agents run` uses for that agent version. It reads and writes the
6
- * same store as `agents defaults run set` (agents.yaml -> run.defaults), so the
6
+ * same store as `agents config set run.<agent@version>.*` (agents.yaml -> run.defaults), so the
7
7
  * two stay consistent — `set` is just the short front door.
8
8
  *
9
9
  * agents set # list every configured default
@@ -72,7 +72,7 @@ export function registerSetCommand(program) {
72
72
  notes: `
73
73
  Selectors use <agent>@<version> or <agent>:<version>; * matches all versions.
74
74
  Exact selectors override wildcard selectors field by field.
75
- Writes the same store as 'agents defaults run set'. Explicit flags on
75
+ Writes the same store as 'agents config set run.<agent@version>.*'. Explicit flags on
76
76
  'agents run' always win over configured defaults.
77
77
  `,
78
78
  });
@@ -8,7 +8,7 @@
8
8
  * the pinned browser or re-point the device default.
9
9
  */
10
10
  import chalk from 'chalk';
11
- import { updateMeta } from '../lib/state.js';
11
+ import { setConfigValue } from '../lib/device-config.js';
12
12
  import { findFirstInstalledBrowser, listInstalledBrowsers } from '../lib/browser/chrome.js';
13
13
  import { DEFAULT_BROWSER_PROFILE_NAME, createProfile, findFreeProfilePort, getConfiguredDefaultProfileName, getProfile, } from '../lib/browser/profiles.js';
14
14
  import { DEFAULT_VIEWPORT } from '../lib/browser/devices.js';
@@ -113,7 +113,7 @@ async function maybeSetDeviceDefault(name, confirm) {
113
113
  default: true,
114
114
  });
115
115
  if (set) {
116
- updateMeta((m) => ({ ...m, defaultBrowserProfile: name }));
116
+ setConfigValue('browser.profile', name);
117
117
  console.log(chalk.dim(`Bare \`agents browser start\` will now use "${name}" on this machine.`));
118
118
  }
119
119
  }
@@ -25,7 +25,6 @@ const DISABLEABLE_FEATURES = [
25
25
  { name: 'secrets', hint: 'keychain-backed env bundles' },
26
26
  { name: 'routines', hint: 'run agents on a cron schedule' },
27
27
  { name: 'monitors', hint: 'event-triggered watchers' },
28
- { name: 'wallet', hint: 'payment cards' },
29
28
  ];
30
29
  /**
31
30
  * Interactive white-label setup. Returns true when a brand exists afterward,
@@ -67,7 +67,7 @@ export async function maybePickInteractiveHost() {
67
67
  default: defaultInteractiveHostChoice(macs, self) ?? SKIP,
68
68
  choices: [
69
69
  ...macs.map((n) => ({ name: n === self ? `${n} ${chalk.dim('(this machine)')}` : n, value: n })),
70
- { name: `Skip ${chalk.dim('— decide later: agents devices set-interactive <name>')}`, value: SKIP },
70
+ { name: `Skip ${chalk.dim('— decide later: agents devices config <name> interactive.host <name>')}`, value: SKIP },
71
71
  ],
72
72
  });
73
73
  if (picked === SKIP)