@phnx-labs/agents-cli 1.22.34 → 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 (493) hide show
  1. package/CHANGELOG.md +672 -2
  2. package/README.md +82 -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 +85 -0
  94. package/dist/commands/share.js +379 -8
  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/codex-policy.d.ts +9 -1
  161. package/dist/lib/codex-policy.js +17 -2
  162. package/dist/lib/commands.d.ts +2 -0
  163. package/dist/lib/commands.js +2 -0
  164. package/dist/lib/computer/sessions-list.d.ts +150 -0
  165. package/dist/lib/computer/sessions-list.js +363 -0
  166. package/dist/lib/config-keys.d.ts +86 -0
  167. package/dist/lib/config-keys.js +193 -0
  168. package/dist/lib/config-machine-keys.d.ts +12 -0
  169. package/dist/lib/config-machine-keys.js +17 -0
  170. package/dist/lib/config-transfer.js +3 -4
  171. package/dist/lib/crabbox/cli.d.ts +2 -2
  172. package/dist/lib/crabbox/cli.js +3 -3
  173. package/dist/lib/daemon-health.d.ts +22 -0
  174. package/dist/lib/daemon-health.js +33 -3
  175. package/dist/lib/daemon-services.d.ts +50 -0
  176. package/dist/lib/daemon-services.js +147 -0
  177. package/dist/lib/daemon-ticks.d.ts +35 -66
  178. package/dist/lib/daemon-ticks.js +77 -159
  179. package/dist/lib/daemon.d.ts +72 -4
  180. package/dist/lib/daemon.js +792 -202
  181. package/dist/lib/deeplink/register.d.ts +49 -0
  182. package/dist/lib/deeplink/register.js +253 -0
  183. package/dist/lib/deeplink/url.d.ts +34 -0
  184. package/dist/lib/deeplink/url.js +78 -0
  185. package/dist/lib/device-config.d.ts +124 -29
  186. package/dist/lib/device-config.js +346 -141
  187. package/dist/lib/devices/config-migration.d.ts +42 -0
  188. package/dist/lib/devices/config-migration.js +203 -0
  189. package/dist/lib/devices/connect.js +14 -7
  190. package/dist/lib/devices/doctor-findings.d.ts +4 -1
  191. package/dist/lib/devices/doctor-findings.js +20 -1
  192. package/dist/lib/devices/harness-inventory.d.ts +11 -2
  193. package/dist/lib/devices/harness-inventory.js +0 -0
  194. package/dist/lib/devices/health.d.ts +1 -1
  195. package/dist/lib/devices/health.js +1 -1
  196. package/dist/lib/devices/pending.d.ts +22 -1
  197. package/dist/lib/devices/pending.js +67 -2
  198. package/dist/lib/devices/registry.d.ts +0 -25
  199. package/dist/lib/devices/registry.js +2 -83
  200. package/dist/lib/devices/resolve-profile.d.ts +20 -0
  201. package/dist/lib/devices/resolve-profile.js +44 -0
  202. package/dist/lib/devices/rollout-verify.d.ts +101 -0
  203. package/dist/lib/devices/rollout-verify.js +193 -0
  204. package/dist/lib/devices/ssh-config.js +10 -6
  205. package/dist/lib/event-families.d.ts +28 -0
  206. package/dist/lib/event-families.js +159 -0
  207. package/dist/lib/event-stream.d.ts +9 -1
  208. package/dist/lib/event-stream.js +26 -9
  209. package/dist/lib/events.d.ts +9 -1
  210. package/dist/lib/events.js +21 -6
  211. package/dist/lib/exec.d.ts +30 -0
  212. package/dist/lib/exec.js +220 -122
  213. package/dist/lib/feed-broadcast.d.ts +25 -0
  214. package/dist/lib/feed-broadcast.js +33 -0
  215. package/dist/lib/feed.d.ts +1 -1
  216. package/dist/lib/feed.js +12 -2
  217. package/dist/lib/fleet/capture.js +15 -0
  218. package/dist/lib/fleet/manifest.js +9 -0
  219. package/dist/lib/fleet/types.d.ts +9 -0
  220. package/dist/lib/fleet-status.js +10 -8
  221. package/dist/lib/git.d.ts +20 -6
  222. package/dist/lib/git.js +121 -17
  223. package/dist/lib/hosts/dispatch.d.ts +8 -3
  224. package/dist/lib/hosts/dispatch.js +29 -3
  225. package/dist/lib/hosts/logs.d.ts +2 -2
  226. package/dist/lib/hosts/logs.js +2 -2
  227. package/dist/lib/hosts/option.js +1 -1
  228. package/dist/lib/hosts/passthrough.d.ts +2 -3
  229. package/dist/lib/hosts/passthrough.js +10 -24
  230. package/dist/lib/hosts/progress.js +2 -2
  231. package/dist/lib/hosts/providers/devices.d.ts +3 -3
  232. package/dist/lib/hosts/providers/devices.js +18 -12
  233. package/dist/lib/hosts/ready.d.ts +5 -1
  234. package/dist/lib/hosts/ready.js +9 -3
  235. package/dist/lib/hosts/reconcile.d.ts +2 -2
  236. package/dist/lib/hosts/reconcile.js +2 -2
  237. package/dist/lib/hosts/registry.js +14 -9
  238. package/dist/lib/hosts/remote-cmd.js +1 -1
  239. package/dist/lib/hosts/remote-os.d.ts +9 -6
  240. package/dist/lib/hosts/remote-os.js +13 -6
  241. package/dist/lib/hosts/routing-flag.d.ts +23 -0
  242. package/dist/lib/hosts/routing-flag.js +41 -0
  243. package/dist/lib/hosts/run-target.js +1 -1
  244. package/dist/lib/hosts/session-index.js +1 -1
  245. package/dist/lib/hosts/tasks.d.ts +6 -6
  246. package/dist/lib/hosts/tasks.js +4 -4
  247. package/dist/lib/hosts/types.js +1 -2
  248. package/dist/lib/installations/resolve.js +2 -8
  249. package/dist/lib/isolation-boundary-report.js +0 -1
  250. package/dist/lib/linear-cache.d.ts +7 -0
  251. package/dist/lib/linear-cache.js +31 -4
  252. package/dist/lib/linear-project-counts.d.ts +1 -1
  253. package/dist/lib/linear-project-counts.js +2 -3
  254. package/dist/lib/linear-projects.js +1 -1
  255. package/dist/lib/loop.d.ts +2 -2
  256. package/dist/lib/loop.js +1 -1
  257. package/dist/lib/mailbox-target.d.ts +1 -1
  258. package/dist/lib/mailbox-target.js +1 -1
  259. package/dist/lib/manifest.js +7 -4
  260. package/dist/lib/menubar/MenubarHelper.app/Contents/CodeResources +0 -0
  261. package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
  262. package/dist/lib/menubar/snapshot.d.ts +3 -2
  263. package/dist/lib/menubar/snapshot.js +6 -2
  264. package/dist/lib/migrate-fold.d.ts +33 -0
  265. package/dist/lib/migrate-fold.js +130 -0
  266. package/dist/lib/migrate.d.ts +34 -34
  267. package/dist/lib/migrate.js +106 -128
  268. package/dist/lib/model-tier-overrides.d.ts +1 -1
  269. package/dist/lib/model-tier-overrides.js +15 -2
  270. package/dist/lib/monitors/config.d.ts +17 -3
  271. package/dist/lib/monitors/config.js +52 -18
  272. package/dist/lib/monitors/engine.d.ts +32 -1
  273. package/dist/lib/monitors/engine.js +94 -11
  274. package/dist/lib/monitors/fingerprint.d.ts +46 -0
  275. package/dist/lib/monitors/fingerprint.js +100 -0
  276. package/dist/lib/monitors/remote.d.ts +47 -0
  277. package/dist/lib/monitors/remote.js +81 -0
  278. package/dist/lib/monitors/state.d.ts +39 -0
  279. package/dist/lib/monitors/state.js +56 -0
  280. package/dist/lib/onepassword.d.ts +17 -0
  281. package/dist/lib/onepassword.js +52 -22
  282. package/dist/lib/open-url.js +1 -1
  283. package/dist/lib/picker.d.ts +14 -2
  284. package/dist/lib/picker.js +35 -13
  285. package/dist/lib/placement.d.ts +1 -1
  286. package/dist/lib/placement.js +1 -1
  287. package/dist/lib/pr-land-detach.d.ts +32 -0
  288. package/dist/lib/pr-land-detach.js +79 -0
  289. package/dist/lib/profiles-presets.js +13 -0
  290. package/dist/lib/profiles.d.ts +2 -0
  291. package/dist/lib/profiles.js +44 -1
  292. package/dist/lib/project-focus.d.ts +1 -1
  293. package/dist/lib/project-focus.js +1 -1
  294. package/dist/lib/project-key.d.ts +17 -0
  295. package/dist/lib/project-key.js +26 -0
  296. package/dist/lib/project-probe.d.ts +4 -1
  297. package/dist/lib/project-probe.js +5 -4
  298. package/dist/lib/project-resources.js +2 -18
  299. package/dist/lib/project-root.d.ts +16 -0
  300. package/dist/lib/project-root.js +20 -2
  301. package/dist/lib/projects.d.ts +20 -1
  302. package/dist/lib/projects.js +78 -1
  303. package/dist/lib/refresh-coordinator.d.ts +24 -0
  304. package/dist/lib/refresh-coordinator.js +52 -0
  305. package/dist/lib/registry.d.ts +2 -2
  306. package/dist/lib/registry.js +1 -1
  307. package/dist/lib/resource-aliases.d.ts +13 -0
  308. package/dist/lib/resource-aliases.js +26 -0
  309. package/dist/lib/resources/types.d.ts +1 -1
  310. package/dist/lib/resources.d.ts +16 -0
  311. package/dist/lib/resources.js +66 -10
  312. package/dist/lib/rotate.d.ts +3 -4
  313. package/dist/lib/rotate.js +4 -5
  314. package/dist/lib/routine-activation.d.ts +22 -2
  315. package/dist/lib/routine-activation.js +63 -16
  316. package/dist/lib/routine-context.d.ts +9 -2
  317. package/dist/lib/routine-context.js +21 -6
  318. package/dist/lib/routines-project.d.ts +58 -48
  319. package/dist/lib/routines-project.js +190 -159
  320. package/dist/lib/routines.d.ts +41 -6
  321. package/dist/lib/routines.js +92 -34
  322. package/dist/lib/run-defaults.d.ts +5 -0
  323. package/dist/lib/run-defaults.js +11 -1
  324. package/dist/lib/runner.d.ts +10 -8
  325. package/dist/lib/runner.js +122 -39
  326. package/dist/lib/secrets/Agents CLI.app/Contents/CodeResources +0 -0
  327. package/dist/lib/secrets/Agents CLI.app/Contents/MacOS/Agents CLI +0 -0
  328. package/dist/lib/secrets/agent.d.ts +10 -3
  329. package/dist/lib/secrets/agent.js +43 -8
  330. package/dist/lib/secrets/bundles.d.ts +1 -0
  331. package/dist/lib/secrets/bundles.js +92 -80
  332. package/dist/lib/secrets/index.js +32 -9
  333. package/dist/lib/secrets/install-helper.d.ts +4 -4
  334. package/dist/lib/secrets/install-helper.js +4 -4
  335. package/dist/lib/secrets/push.d.ts +40 -6
  336. package/dist/lib/secrets/push.js +58 -11
  337. package/dist/lib/secrets/read-backoff.d.ts +1 -1
  338. package/dist/lib/secrets/read-backoff.js +1 -1
  339. package/dist/lib/secrets/remote.d.ts +24 -0
  340. package/dist/lib/secrets/remote.js +54 -4
  341. package/dist/lib/self-update.d.ts +108 -0
  342. package/dist/lib/self-update.js +276 -1
  343. package/dist/lib/session/active.d.ts +89 -5
  344. package/dist/lib/session/active.js +165 -10
  345. package/dist/lib/session/actor-sidecar.d.ts +1 -1
  346. package/dist/lib/session/actor-sidecar.js +2 -1
  347. package/dist/lib/session/db.d.ts +176 -2
  348. package/dist/lib/session/db.js +484 -17
  349. package/dist/lib/session/discover.js +27 -4
  350. package/dist/lib/session/hook-sessions.js +2 -2
  351. package/dist/lib/session/host-link.d.ts +2 -2
  352. package/dist/lib/session/host-link.js +2 -2
  353. package/dist/lib/session/pid-registry.d.ts +21 -0
  354. package/dist/lib/session/pid-registry.js +57 -0
  355. package/dist/lib/session/remote-active.js +15 -1
  356. package/dist/lib/session/remote.js +2 -2
  357. package/dist/lib/session/session-cache.d.ts +14 -7
  358. package/dist/lib/session/session-cache.js +51 -9
  359. package/dist/lib/session/state.d.ts +2 -2
  360. package/dist/lib/session/state.js +1 -1
  361. package/dist/lib/session/sync/config.d.ts +10 -10
  362. package/dist/lib/session/sync/config.js +10 -10
  363. package/dist/lib/session/sync/r2.d.ts +34 -0
  364. package/dist/lib/session/sync/r2.js +123 -0
  365. package/dist/lib/session/throughput.d.ts +1 -1
  366. package/dist/lib/session/throughput.js +1 -1
  367. package/dist/lib/session/types.d.ts +23 -1
  368. package/dist/lib/session/types.js +15 -0
  369. package/dist/lib/session/viewing-in.d.ts +1 -1
  370. package/dist/lib/session/viewing-in.js +1 -1
  371. package/dist/lib/session/watch.d.ts +101 -0
  372. package/dist/lib/session/watch.js +242 -0
  373. package/dist/lib/share/config.d.ts +4 -0
  374. package/dist/lib/share/config.js +1 -0
  375. package/dist/lib/share/delete.d.ts +93 -0
  376. package/dist/lib/share/delete.js +127 -0
  377. package/dist/lib/share/provision.d.ts +38 -0
  378. package/dist/lib/share/provision.js +50 -0
  379. package/dist/lib/share/publish.d.ts +40 -1
  380. package/dist/lib/share/publish.js +116 -3
  381. package/dist/lib/share/worker-template.js +71 -6
  382. package/dist/lib/shims.d.ts +17 -3
  383. package/dist/lib/shims.js +136 -27
  384. package/dist/lib/signin-badge.js +3 -2
  385. package/dist/lib/skills.js +2 -0
  386. package/dist/lib/smart-launch.d.ts +8 -8
  387. package/dist/lib/smart-launch.js +80 -59
  388. package/dist/lib/ssh-exec.d.ts +1 -1
  389. package/dist/lib/ssh-exec.js +1 -1
  390. package/dist/lib/staleness/prune.d.ts +88 -0
  391. package/dist/lib/staleness/prune.js +69 -0
  392. package/dist/lib/staleness/registry.d.ts +1 -1
  393. package/dist/lib/staleness/writers/commands.js +34 -2
  394. package/dist/lib/staleness/writers/hooks.js +16 -0
  395. package/dist/lib/staleness/writers/kinds.d.ts +6 -0
  396. package/dist/lib/staleness/writers/skills.js +19 -0
  397. package/dist/lib/staleness/writers/subagents.d.ts +2 -3
  398. package/dist/lib/staleness/writers/subagents.js +0 -4
  399. package/dist/lib/staleness/writers/types.d.ts +32 -0
  400. package/dist/lib/startup/command-registry.d.ts +6 -12
  401. package/dist/lib/startup/command-registry.js +14 -31
  402. package/dist/lib/startup/dev-build.d.ts +10 -0
  403. package/dist/lib/startup/dev-build.js +13 -1
  404. package/dist/lib/startup/spellcheck.d.ts +18 -0
  405. package/dist/lib/startup/spellcheck.js +45 -0
  406. package/dist/lib/state.d.ts +36 -9
  407. package/dist/lib/state.js +96 -46
  408. package/dist/lib/subagents-registry.d.ts +0 -7
  409. package/dist/lib/subagents-registry.js +38 -65
  410. package/dist/lib/subagents.d.ts +0 -33
  411. package/dist/lib/subagents.js +0 -75
  412. package/dist/lib/sync-umbrella.js +1 -1
  413. package/dist/lib/teams/agents.d.ts +41 -1
  414. package/dist/lib/teams/agents.js +187 -9
  415. package/dist/lib/teams/api.d.ts +11 -1
  416. package/dist/lib/teams/api.js +11 -2
  417. package/dist/lib/teams/delivery.d.ts +41 -0
  418. package/dist/lib/teams/delivery.js +60 -0
  419. package/dist/lib/teams/registry.d.ts +14 -0
  420. package/dist/lib/teams/registry.js +51 -1
  421. package/dist/lib/teams/remoteWorktree.d.ts +19 -0
  422. package/dist/lib/teams/remoteWorktree.js +29 -0
  423. package/dist/lib/teams/scheduler.d.ts +1 -1
  424. package/dist/lib/teams/scheduler.js +1 -1
  425. package/dist/lib/teams/worktree.d.ts +24 -0
  426. package/dist/lib/teams/worktree.js +42 -0
  427. package/dist/lib/terminal/backends/vscodium-agent.d.ts +10 -1
  428. package/dist/lib/terminal/backends/vscodium-agent.js +16 -5
  429. package/dist/lib/terminal/engine.d.ts +4 -0
  430. package/dist/lib/terminal/engine.js +8 -2
  431. package/dist/lib/terminal/types.d.ts +21 -2
  432. package/dist/lib/testdata/refresh-coordinator-worker.d.ts +1 -0
  433. package/dist/lib/testdata/refresh-coordinator-worker.js +23 -0
  434. package/dist/lib/tickets/list.d.ts +53 -0
  435. package/dist/lib/tickets/list.js +153 -0
  436. package/dist/lib/tmux/orphan-reap.d.ts +320 -0
  437. package/dist/lib/tmux/orphan-reap.js +644 -0
  438. package/dist/lib/tmux/session.d.ts +68 -3
  439. package/dist/lib/tmux/session.js +95 -5
  440. package/dist/lib/triggers/handlers.d.ts +20 -0
  441. package/dist/lib/triggers/handlers.js +6 -1
  442. package/dist/lib/types.d.ts +46 -34
  443. package/dist/lib/usage-fleet.d.ts +32 -0
  444. package/dist/lib/usage-fleet.js +125 -0
  445. package/dist/lib/usage-refresh.d.ts +3 -3
  446. package/dist/lib/usage-refresh.js +19 -16
  447. package/dist/lib/usage.d.ts +51 -47
  448. package/dist/lib/usage.js +145 -153
  449. package/dist/lib/version-duplicates.js +2 -2
  450. package/dist/lib/versions.d.ts +56 -13
  451. package/dist/lib/versions.js +195 -45
  452. package/dist/lib/watchdog/log.d.ts +1 -1
  453. package/dist/lib/watchdog/log.js +3 -3
  454. package/dist/lib/watchdog/rotate.d.ts +6 -6
  455. package/dist/lib/watchdog/rotate.js +6 -6
  456. package/dist/lib/workflows.d.ts +1 -1
  457. package/dist/lib/yaml-io.d.ts +47 -0
  458. package/dist/lib/yaml-io.js +55 -0
  459. package/package.json +2 -1
  460. package/scripts/install-helper.js +2 -2
  461. package/scripts/postinstall.js +23 -20
  462. package/dist/commands/defaults.d.ts +0 -7
  463. package/dist/commands/defaults.js +0 -107
  464. package/dist/commands/export.d.ts +0 -11
  465. package/dist/commands/export.js +0 -215
  466. package/dist/commands/helper.d.ts +0 -12
  467. package/dist/commands/helper.js +0 -87
  468. package/dist/commands/hosts.d.ts +0 -11
  469. package/dist/commands/hosts.js +0 -330
  470. package/dist/commands/lock.d.ts +0 -12
  471. package/dist/commands/lock.js +0 -70
  472. package/dist/commands/pull.d.ts +0 -17
  473. package/dist/commands/pull.js +0 -39
  474. package/dist/commands/push.d.ts +0 -14
  475. package/dist/commands/push.js +0 -30
  476. package/dist/commands/wallet.d.ts +0 -20
  477. package/dist/commands/wallet.js +0 -216
  478. package/dist/commands/worktree.d.ts +0 -19
  479. package/dist/commands/worktree.js +0 -272
  480. package/dist/lib/account-labels.d.ts +0 -24
  481. package/dist/lib/account-labels.js +0 -72
  482. package/dist/lib/auto-dispatch-linear.d.ts +0 -18
  483. package/dist/lib/auto-dispatch-linear.js +0 -107
  484. package/dist/lib/auto-dispatch-provider.d.ts +0 -10
  485. package/dist/lib/auto-dispatch-provider.js +0 -30
  486. package/dist/lib/auto-dispatch.d.ts +0 -93
  487. package/dist/lib/auto-dispatch.js +0 -128
  488. package/dist/lib/export.d.ts +0 -72
  489. package/dist/lib/export.js +0 -269
  490. package/dist/lib/lock.d.ts +0 -93
  491. package/dist/lib/lock.js +0 -207
  492. package/dist/lib/wallet/index.d.ts +0 -78
  493. package/dist/lib/wallet/index.js +0 -253
@@ -6,6 +6,23 @@ import { getHelpersDir } from '../state.js';
6
6
  import { startDaemon, stopDaemon } from '../daemon.js';
7
7
  import { getCliVersion } from '../version.js';
8
8
  const SOCKET_NAME = 'browser.sock';
9
+ /**
10
+ * Backstop for {@link BrowserIPCServer.stop} — how long to wait for the socket
11
+ * to be released before unlinking it anyway (RUSH-2421).
12
+ *
13
+ * This MUST stay well under the daemon's SIGTERM grace window
14
+ * (`STOP_GRACE_MS`, daemon.ts). `handleShutdown` awaits `stop()`, so a close
15
+ * that takes as long as the grace window means `stopDaemon` gives up waiting
16
+ * and escalates to `killTree` — turning every graceful stop into a kill. The
17
+ * first version of this constant was set to exactly 5000, the same value as
18
+ * `STOP_GRACE_MS`, and did precisely that whenever a browser client held its
19
+ * (deliberately) long-lived connection open.
20
+ *
21
+ * With connections now ended explicitly in `closeServer`, reaching this
22
+ * timeout at all means a socket refused to die; 1.5s bounds that without
23
+ * coming near the grace window.
24
+ */
25
+ const IPC_CLOSE_TIMEOUT_MS = 1_500;
9
26
  export class BrowserDaemonNotRunningError extends Error {
10
27
  constructor() {
11
28
  super(formatBrowserDaemonNotRunningError());
@@ -153,6 +170,10 @@ export class BrowserIPCConnection {
153
170
  export class BrowserIPCServer {
154
171
  server = null;
155
172
  service;
173
+ /** Live client connections, so {@link stop} can end them rather than wait. */
174
+ connections = new Set();
175
+ /** In-flight stop, so a second SIGTERM awaits the same close, never skips it. */
176
+ stopping = null;
156
177
  constructor(service) {
157
178
  this.service = service;
158
179
  }
@@ -170,6 +191,12 @@ export class BrowserIPCServer {
170
191
  }
171
192
  }
172
193
  this.server = net.createServer((socket) => {
194
+ // `net.Server.close()` stops accepting but does not complete until every
195
+ // EXISTING connection ends, and clients here hold one open on purpose
196
+ // ("the process and socket stay warm between actions"). Tracking them is
197
+ // what lets stop() end them deliberately instead of waiting out a timeout.
198
+ this.connections.add(socket);
199
+ socket.on('close', () => this.connections.delete(socket));
173
200
  let buffer = '';
174
201
  socket.on('data', async (data) => {
175
202
  buffer += data.toString();
@@ -229,11 +256,38 @@ export class BrowserIPCServer {
229
256
  });
230
257
  });
231
258
  }
259
+ /**
260
+ * Stop accepting, release the binding, and only then resolve.
261
+ *
262
+ * RUSH-2421: this used to call `server.close()` and move on. `close()` is
263
+ * asynchronous — it stops accepting immediately but the binding is not
264
+ * actually released until the `'close'` event fires — so `stop()` resolved
265
+ * while the socket (or named pipe) was still held. The daemon's
266
+ * `handleShutdown` awaits this before it exits, and a successor's
267
+ * `claimDaemonInstance` waits for that exit as its proof the predecessor's
268
+ * resources are free (SING-11). Resolving early made that proof false: the
269
+ * newcomer could bind before the incumbent's binding was gone, which is the
270
+ * two-servers-on-one-socket orphan the eviction protocol exists to prevent.
271
+ *
272
+ * The first version of this waited out a timeout instead, and that made every
273
+ * graceful daemon stop escalate to `killTree`: `close()` does not complete
274
+ * while a connection is open, browser clients hold one open on purpose, and
275
+ * the timeout was set equal to the daemon's own SIGTERM grace window
276
+ * (`STOP_GRACE_MS`) — so `handleShutdown` was still inside `stop()` when
277
+ * `stopDaemon` gave up waiting and killed it. So we END the connections
278
+ * rather than wait for them: `close()` stops accepting, destroying the
279
+ * tracked sockets lets it complete, and the timeout is only a backstop for a
280
+ * socket that will not die, deliberately far below `STOP_GRACE_MS`.
281
+ */
232
282
  async stop() {
233
- if (this.server) {
234
- this.server.close();
235
- this.server = null;
236
- }
283
+ // A second SIGTERM must await the SAME stop, not skip past it because
284
+ // `this.server` was already nulled by the first.
285
+ if (!this.stopping)
286
+ this.stopping = this.doStop();
287
+ return this.stopping;
288
+ }
289
+ async doStop() {
290
+ await this.closeServer();
237
291
  if (!IS_WINDOWS) {
238
292
  const socketPath = getSocketPath();
239
293
  if (fs.existsSync(socketPath)) {
@@ -242,6 +296,28 @@ export class BrowserIPCServer {
242
296
  }
243
297
  await this.service.shutdown();
244
298
  }
299
+ /** Release the listening binding, resolving only once it is genuinely gone. */
300
+ closeServer() {
301
+ const server = this.server;
302
+ this.server = null;
303
+ if (!server)
304
+ return Promise.resolve();
305
+ return new Promise((resolve) => {
306
+ const done = () => { clearTimeout(timer); resolve(); };
307
+ // Backstop only, for a socket that refuses to die. Far below the daemon's
308
+ // SIGTERM grace window so a slow close can never be what gets the daemon
309
+ // killed — the whole point is that the graceful path stays graceful.
310
+ const timer = setTimeout(done, IPC_CLOSE_TIMEOUT_MS);
311
+ // `close()` reports an error when the server was never listening —
312
+ // nothing to release, so that is a completed close, not a failure.
313
+ server.close(() => done());
314
+ // `close()` waits for existing connections; ending them is what lets it
315
+ // finish now instead of at the timeout.
316
+ for (const socket of this.connections)
317
+ socket.destroy();
318
+ this.connections.clear();
319
+ });
320
+ }
245
321
  async handleRequest(request) {
246
322
  if (request.action === 'upload-stage') {
247
323
  const source = request.source;
@@ -266,6 +342,7 @@ export class BrowserIPCServer {
266
342
  skipDomainSkill: request.skipDomainSkill,
267
343
  actor: request.actor,
268
344
  launchId: request.launchId,
345
+ sessionId: request.sessionId,
269
346
  });
270
347
  return {
271
348
  ok: true,
@@ -5,8 +5,9 @@ export declare const DEFAULT_BROWSER_PROFILE_NAME = "default";
5
5
  * The device-local configured default profile name (set via
6
6
  * `agents browser profiles set-default`), or undefined when unset. When set, it
7
7
  * is the profile `agents browser start` resolves to for BOTH the no-`--profile`
8
- * path and an explicit `--profile default`. Stored per-machine see
9
- * `Meta.defaultBrowserProfile`.
8
+ * path and an explicit `--profile default`. Stored as this machine's
9
+ * `browser.profile` device-config key (central `fleet.devices.<name>.config`
10
+ * block — see lib/device-config.ts).
10
11
  */
11
12
  export declare function getConfiguredDefaultProfileName(): string | undefined;
12
13
  export declare function getBrowserRuntimeDir(): string;
@@ -1,17 +1,33 @@
1
1
  import * as path from 'path';
2
- import { getBrowserRuntimeDir as getBrowserRuntimeDirRoot, readMeta, writeMeta, } from '../state.js';
2
+ import { getBrowserRuntimeDir as getBrowserRuntimeDirRoot, readMeta, updateMeta, } from '../state.js';
3
+ import { getConfigValue } from '../device-config.js';
3
4
  import { findBrowserPath, findFirstInstalledBrowser, isPortInUse } from './chrome.js';
4
5
  import { DEFAULT_VIEWPORT } from './devices.js';
5
6
  export const DEFAULT_BROWSER_PROFILE_NAME = 'default';
7
+ /**
8
+ * True for a profile whose contents only make sense on THIS machine, so it must
9
+ * live in the per-machine doc rather than the fleet-synced agents.yaml.
10
+ *
11
+ * Only the auto-detected `default` qualifies: it is generated by probing local
12
+ * browser installs and a free local port, so its `binary:` is an absolute path
13
+ * for one OS. Shared fleet-wide it caused a permanent rewrite loop — a macOS box
14
+ * wrote `/Applications/...`, a Linux box rewrote `/usr/bin/chromium-browser`,
15
+ * each on every `agents browser start`. Named profiles a user created are real
16
+ * fleet config and keep syncing.
17
+ */
18
+ function isMachineLocalProfile(name) {
19
+ return name === DEFAULT_BROWSER_PROFILE_NAME;
20
+ }
6
21
  /**
7
22
  * The device-local configured default profile name (set via
8
23
  * `agents browser profiles set-default`), or undefined when unset. When set, it
9
24
  * is the profile `agents browser start` resolves to for BOTH the no-`--profile`
10
- * path and an explicit `--profile default`. Stored per-machine see
11
- * `Meta.defaultBrowserProfile`.
25
+ * path and an explicit `--profile default`. Stored as this machine's
26
+ * `browser.profile` device-config key (central `fleet.devices.<name>.config`
27
+ * block — see lib/device-config.ts).
12
28
  */
13
29
  export function getConfiguredDefaultProfileName() {
14
- return readMeta().defaultBrowserProfile || undefined;
30
+ return getConfigValue('browser.profile').value || undefined;
15
31
  }
16
32
  export function getBrowserRuntimeDir() {
17
33
  return getBrowserRuntimeDirRoot();
@@ -82,15 +98,22 @@ function profileToConfig(profile) {
82
98
  config.logHost = profile.logHost;
83
99
  return config;
84
100
  }
85
- export async function listProfiles() {
101
+ /**
102
+ * Every profile visible on this machine: the fleet-shared ones plus this
103
+ * machine's own. A machine-local entry WINS on a name collision — it was written
104
+ * by this box for this box, whereas the shared copy may carry another OS's
105
+ * binary path (that mismatch is exactly why `default` moved local).
106
+ */
107
+ function allProfileConfigs() {
86
108
  const meta = readMeta();
87
- if (!meta.browser)
88
- return [];
89
- return Object.entries(meta.browser).map(([name, config]) => configToProfile(name, config));
109
+ return { ...meta.browser, ...meta.deviceBrowser };
110
+ }
111
+ export async function listProfiles() {
112
+ const configs = allProfileConfigs();
113
+ return Object.entries(configs).map(([name, config]) => configToProfile(name, config));
90
114
  }
91
115
  export async function getProfile(name) {
92
- const meta = readMeta();
93
- const config = meta.browser?.[name];
116
+ const config = allProfileConfigs()[name];
94
117
  if (!config)
95
118
  return null;
96
119
  return configToProfile(name, config);
@@ -271,7 +294,8 @@ function hasSshEndpoint(endpoints) {
271
294
  }
272
295
  export async function createProfile(profile) {
273
296
  const meta = readMeta();
274
- if (meta.browser?.[profile.name]) {
297
+ const existingConfigs = allProfileConfigs();
298
+ if (existingConfigs[profile.name]) {
275
299
  throw new Error(`Profile "${profile.name}" already exists`);
276
300
  }
277
301
  // Collision check. Every CDP/SSH profile ends up listening on (or
@@ -280,8 +304,8 @@ export async function createProfile(profile) {
280
304
  // longer need to scope by host. Two profiles that would need the same
281
305
  // local port can't both run at the same time.
282
306
  const newLocal = effectiveLocalPort(profile);
283
- if (newLocal !== undefined && meta.browser) {
284
- for (const [existingName, existingConfig] of Object.entries(meta.browser)) {
307
+ if (newLocal !== undefined) {
308
+ for (const [existingName, existingConfig] of Object.entries(existingConfigs)) {
285
309
  const existingProfile = configToProfile(existingName, existingConfig);
286
310
  const existingLocal = effectiveLocalPort(existingProfile);
287
311
  if (existingLocal === newLocal) {
@@ -302,25 +326,44 @@ export async function createProfile(profile) {
302
326
  if (!hasSshEndpoint(profile.endpoints)) {
303
327
  findBrowserPath(profile.browser, profile.binary);
304
328
  }
305
- meta.browser = meta.browser ?? {};
306
- meta.browser[profile.name] = profileToConfig(profile);
307
- writeMeta(meta);
329
+ const config = profileToConfig(profile);
330
+ if (isMachineLocalProfile(profile.name)) {
331
+ updateMeta((m) => ({ ...m, deviceBrowser: { ...m.deviceBrowser, [profile.name]: config } }));
332
+ return;
333
+ }
334
+ updateMeta((m) => ({ ...m, browser: { ...m.browser, [profile.name]: config } }));
308
335
  }
309
336
  export async function updateProfile(profile) {
310
337
  const meta = readMeta();
311
- if (!meta.browser?.[profile.name]) {
338
+ const local = meta.deviceBrowser?.[profile.name];
339
+ if (!local && !meta.browser?.[profile.name]) {
312
340
  throw new Error(`Profile "${profile.name}" does not exist`);
313
341
  }
314
- meta.browser[profile.name] = profileToConfig(profile);
315
- writeMeta(meta);
342
+ const config = profileToConfig(profile);
343
+ // A profile that already lives machine-locally stays there; so does the auto
344
+ // `default`, whose binary path and port are specific to this machine.
345
+ if (local || isMachineLocalProfile(profile.name)) {
346
+ updateMeta((m) => ({ ...m, deviceBrowser: { ...m.deviceBrowser, [profile.name]: config } }));
347
+ return;
348
+ }
349
+ updateMeta((m) => ({ ...m, browser: { ...m.browser, [profile.name]: config } }));
316
350
  }
317
351
  export async function deleteProfile(name) {
318
352
  const meta = readMeta();
319
- if (!meta.browser?.[name]) {
353
+ const isLocal = !!meta.deviceBrowser?.[name];
354
+ if (!isLocal && !meta.browser?.[name]) {
320
355
  throw new Error(`Profile "${name}" does not exist`);
321
356
  }
322
- delete meta.browser[name];
323
- writeMeta(meta);
357
+ updateMeta((m) => {
358
+ if (isLocal) {
359
+ const next = { ...m.deviceBrowser };
360
+ delete next[name];
361
+ return { ...m, deviceBrowser: Object.keys(next).length > 0 ? next : undefined };
362
+ }
363
+ const next = { ...m.browser };
364
+ delete next[name];
365
+ return { ...m, browser: Object.keys(next).length > 0 ? next : undefined };
366
+ });
324
367
  }
325
368
  /**
326
369
  * Resolve a profile's endpoint presets into a normalized map regardless of
@@ -62,9 +62,11 @@ export interface HealInfo {
62
62
  export declare function resolveTaskIdentity(forwarded: {
63
63
  actor?: string;
64
64
  launchId?: string;
65
+ sessionId?: string;
65
66
  }, resolveLocalActor: () => string): {
66
67
  owner: string;
67
68
  launchId?: string;
69
+ sessionId?: string;
68
70
  };
69
71
  export declare class BrowserService {
70
72
  private static readonly SOURCE_PREFIX;
@@ -83,6 +85,8 @@ export declare class BrowserService {
83
85
  /** Caller identity, forwarded from the CLI (see IPCRequest.actor/launchId). */
84
86
  actor?: string;
85
87
  launchId?: string;
88
+ /** Calling agent session, forwarded from the CLI (see IPCRequest.sessionId). */
89
+ sessionId?: string;
86
90
  }): Promise<{
87
91
  task: string;
88
92
  name: string;
@@ -15,6 +15,7 @@ import { typeEditorText } from './editor.js';
15
15
  import { detectUploadPattern, stageUploadFile, uploadToDropTarget, uploadToFileInput, uploadViaFileChooser, } from './upload.js';
16
16
  import { emit } from '../events.js';
17
17
  import { resolveActor } from '../actor.js';
18
+ import { recordBrowserSession } from '../session/db.js';
18
19
  import { sshExecAsync } from '../ssh-exec.js';
19
20
  function isPathInside(candidate, dir) {
20
21
  const rel = path.relative(dir, candidate);
@@ -235,6 +236,7 @@ export function resolveTaskIdentity(forwarded, resolveLocalActor) {
235
236
  return {
236
237
  owner: forwarded.actor ?? resolveLocalActor(),
237
238
  launchId: forwarded.launchId,
239
+ sessionId: forwarded.sessionId,
238
240
  };
239
241
  }
240
242
  export class BrowserService {
@@ -348,9 +350,10 @@ export class BrowserService {
348
350
  createdAt: Date.now(),
349
351
  pid: conn.pid,
350
352
  // Identity is forwarded from the caller (see resolveTaskIdentity): WHO
351
- // (owner) and WHICH run (launchId). Resolving daemon-side would attribute
352
- // every task to the shared daemon's actor (the RUSH-2020 bug).
353
- ...resolveTaskIdentity({ actor: opts.actor, launchId: opts.launchId }, () => resolveActor().id),
353
+ // (owner), WHICH run (launchId), and WHICH agent session (sessionId).
354
+ // Resolving daemon-side would attribute every task to the shared daemon's
355
+ // actor (the RUSH-2020 bug).
356
+ ...resolveTaskIdentity({ actor: opts.actor, launchId: opts.launchId, sessionId: opts.sessionId }, () => resolveActor().id),
354
357
  };
355
358
  // For Electron, get the existing window as the tab
356
359
  if (conn.electron) {
@@ -363,6 +366,30 @@ export class BrowserService {
363
366
  }
364
367
  conn.tasks.set(taskName, task);
365
368
  await this.saveTaskState(effectiveProfileName, conn.tasks);
369
+ // Durable identity, written ONCE at start and never deleted (RUSH-2549).
370
+ // tasks.json above stays live state: `stop` drops the task from that map, so
371
+ // anything recorded only there is gone the moment the task ends -- which is
372
+ // why every finished task used to list as "unlinked". This row outlives the
373
+ // task, the daemon, and a reboot. Metadata only: the capture bytes stay on
374
+ // disk under capture_dir.
375
+ // Guarded like `emit` below ("logging should never break the CLI",
376
+ // events.ts): the browser task is already started and registered. An
377
+ // unwritable session DB must not turn a working `agents browser start` into
378
+ // a failure -- the cost of a miss is one unlinked row, not a dead browser.
379
+ try {
380
+ recordBrowserSession({
381
+ task: taskName,
382
+ profile: effectiveProfileName,
383
+ sessionId: task.sessionId,
384
+ launchId: task.launchId,
385
+ actor: task.owner,
386
+ startedAt: task.createdAt,
387
+ captureDir: getProfileSessionsDir(effectiveProfileName, taskName),
388
+ });
389
+ }
390
+ catch {
391
+ // Recording is best-effort; the task itself is live either way.
392
+ }
366
393
  emit('browser.launch', { profile: effectiveProfileName, task: taskName, pid: conn.pid });
367
394
  void import('../analytics/usage-db.js').then(({ recordUsage }) => {
368
395
  recordUsage({
@@ -33,10 +33,17 @@ export declare function renderBrowserSessions(groups: ProfileArtifacts[]): strin
33
33
  export declare function resolveArtifact(groups: ProfileArtifacts[], selector: string): string | null;
34
34
  /** Open a file in the OS default app. Returns true on success. */
35
35
  export declare function openArtifact(filePath: string): boolean;
36
- /** The identity fields this module cares about from a profile's `tasks.json`. */
36
+ /** The identity fields this module cares about for one task. */
37
37
  export interface TaskIdentity {
38
38
  owner?: string;
39
39
  launchId?: string;
40
+ /**
41
+ * The agent session that drove the task. Primary identity: it is carried by
42
+ * every agent process, whereas a launch id is present on a minority of them.
43
+ * Sourced from the durable `browser_sessions` row, which survives task stop —
44
+ * `tasks.json` never records it beyond the task's own lifetime (RUSH-2549).
45
+ */
46
+ sessionId?: string;
40
47
  }
41
48
  /**
42
49
  * Read a profile's `tasks.json` for the identity of its CURRENTLY LIVE tasks,
@@ -48,6 +55,17 @@ export interface TaskIdentity {
48
55
  * browser daemon is running.
49
56
  */
50
57
  export declare function loadTaskIdentities(profile: string): Map<string, TaskIdentity>;
58
+ /**
59
+ * Identity for one profile's tasks, durable copy first.
60
+ *
61
+ * `browser_sessions` is the source of truth: it is written at task start and
62
+ * never deleted, so it answers for tasks that have already stopped — the case
63
+ * `tasks.json` structurally cannot, since `saveTaskState` rewrites that file
64
+ * from the LIVE task map. The live file is still merged on top for a task that
65
+ * is running right now, so a task started by an older CLI (no DB row yet) keeps
66
+ * whatever identity it does have rather than regressing to nothing.
67
+ */
68
+ export declare function loadDurableTaskIdentities(profile: string): Map<string, TaskIdentity>;
51
69
  /** launchId -> indexed session id, built once from every source that records
52
70
  * this join, so a task-heavy profile resolves without re-scanning per task. */
53
71
  export interface LaunchSessionIndex {
@@ -85,6 +103,8 @@ export interface BrowserSessionRow {
85
103
  task?: string;
86
104
  owner?: string;
87
105
  launchId?: string;
106
+ /** The agent session that drove the task, when one was recorded. */
107
+ sessionId?: string;
88
108
  linkStatus: BrowserSessionLinkStatus;
89
109
  linkedSession?: SessionMeta;
90
110
  /** Newest first. */
@@ -99,7 +119,7 @@ export interface BrowserSessionRow {
99
119
  * or session-index dependency and is unit-testable with synthetic data (see
100
120
  * {@link buildBrowserSessionRows} for the impure disk/index-reading caller).
101
121
  */
102
- export declare function groupIntoRows(groups: ProfileArtifacts[], taskIdentities: Map<string, Map<string, TaskIdentity>>, resolveLaunch?: (launchId: string) => SessionMeta | null): BrowserSessionRow[];
122
+ export declare function groupIntoRows(groups: ProfileArtifacts[], taskIdentities: Map<string, Map<string, TaskIdentity>>, resolveLaunch?: (launchId: string) => SessionMeta | null, resolveSession?: (sessionId: string) => SessionMeta | null): BrowserSessionRow[];
103
123
  /** Build task-first rows for one profile (or every profile with captures),
104
124
  * reading `tasks.json` and resolving launchIds against the live indexes.
105
125
  * The interactive picker's data source. */
@@ -19,7 +19,7 @@ import * as path from 'path';
19
19
  import { spawnSync } from 'child_process';
20
20
  import { getBrowserRuntimeDir, getProfileRuntimeDir } from './profiles.js';
21
21
  import { formatRelativeTime } from '../session/relative-time.js';
22
- import { getSessionById } from '../session/db.js';
22
+ import { getSessionById, listBrowserSessionRecords, pruneToolSessions } from '../session/db.js';
23
23
  import { listPidSessionEntries } from '../session/pid-registry.js';
24
24
  import { loadHookSessionIndex } from '../session/hook-sessions.js';
25
25
  import { readRecentActivity } from '../activity.js';
@@ -214,10 +214,40 @@ export function loadTaskIdentities(profile) {
214
214
  out.set(name, {
215
215
  owner: typeof t.owner === 'string' ? t.owner : undefined,
216
216
  launchId: typeof t.launchId === 'string' ? t.launchId : undefined,
217
+ sessionId: typeof t.sessionId === 'string' ? t.sessionId : undefined,
217
218
  });
218
219
  }
219
220
  return out;
220
221
  }
222
+ /**
223
+ * Identity for one profile's tasks, durable copy first.
224
+ *
225
+ * `browser_sessions` is the source of truth: it is written at task start and
226
+ * never deleted, so it answers for tasks that have already stopped — the case
227
+ * `tasks.json` structurally cannot, since `saveTaskState` rewrites that file
228
+ * from the LIVE task map. The live file is still merged on top for a task that
229
+ * is running right now, so a task started by an older CLI (no DB row yet) keeps
230
+ * whatever identity it does have rather than regressing to nothing.
231
+ */
232
+ export function loadDurableTaskIdentities(profile) {
233
+ const merged = new Map();
234
+ for (const record of listBrowserSessionRecords(profile)) {
235
+ merged.set(record.task, {
236
+ owner: record.actor,
237
+ launchId: record.launchId,
238
+ sessionId: record.sessionId,
239
+ });
240
+ }
241
+ for (const [task, live] of loadTaskIdentities(profile)) {
242
+ const durable = merged.get(task);
243
+ merged.set(task, {
244
+ owner: live.owner ?? durable?.owner,
245
+ launchId: live.launchId ?? durable?.launchId,
246
+ sessionId: live.sessionId ?? durable?.sessionId,
247
+ });
248
+ }
249
+ return merged;
250
+ }
221
251
  /**
222
252
  * Build the launchId -> sessionId index from the same three sources
223
253
  * `feed-post.ts` `resolvePostIdentity` already uses for this exact problem —
@@ -260,7 +290,7 @@ export function resolveLaunchSession(index, launchId) {
260
290
  * or session-index dependency and is unit-testable with synthetic data (see
261
291
  * {@link buildBrowserSessionRows} for the impure disk/index-reading caller).
262
292
  */
263
- export function groupIntoRows(groups, taskIdentities, resolveLaunch) {
293
+ export function groupIntoRows(groups, taskIdentities, resolveLaunch, resolveSession) {
264
294
  const rows = [];
265
295
  for (const g of groups) {
266
296
  const identities = taskIdentities.get(g.profile) ?? new Map();
@@ -278,14 +308,24 @@ export function groupIntoRows(groups, taskIdentities, resolveLaunch) {
278
308
  for (const [task, artifacts] of byTask) {
279
309
  artifacts.sort((a, b) => b.mtimeMs - a.mtimeMs);
280
310
  const identity = identities.get(task);
281
- const linkedSession = identity?.launchId ? resolveLaunch?.(identity.launchId) ?? null : null;
311
+ // Session id first: it is the direct answer and the one agents actually
312
+ // carry. The launchId join stays as the fallback for a task that recorded
313
+ // only that (an older CLI, or a run whose session id was unset).
314
+ let linkedSession = null;
315
+ if (identity?.sessionId && resolveSession)
316
+ linkedSession = resolveSession(identity.sessionId);
317
+ if (!linkedSession && identity?.launchId && resolveLaunch) {
318
+ linkedSession = resolveLaunch(identity.launchId);
319
+ }
320
+ const hasIdentityKey = !!(identity?.sessionId || identity?.launchId);
282
321
  rows.push({
283
322
  kind: 'task',
284
323
  profile: g.profile,
285
324
  task,
286
325
  owner: identity?.owner,
287
326
  launchId: identity?.launchId,
288
- linkStatus: linkedSession ? 'linked' : identity?.launchId ? 'unresolved' : 'unlinked',
327
+ sessionId: identity?.sessionId,
328
+ linkStatus: linkedSession ? 'linked' : hasIdentityKey ? 'unresolved' : 'unlinked',
289
329
  linkedSession: linkedSession ?? undefined,
290
330
  artifacts,
291
331
  counts: countByKind(artifacts),
@@ -311,10 +351,18 @@ export function groupIntoRows(groups, taskIdentities, resolveLaunch) {
311
351
  * reading `tasks.json` and resolving launchIds against the live indexes.
312
352
  * The interactive picker's data source. */
313
353
  export function buildBrowserSessionRows(profile) {
354
+ // Retention runs from BOTH listing paths, not just the computer one: a box
355
+ // that uses `agents browser` and never runs `agents sessions --computer`
356
+ // would otherwise never sweep either table. Best-effort — a read-only DB
357
+ // must not break a listing.
358
+ try {
359
+ pruneToolSessions();
360
+ }
361
+ catch { /* listing must not fail on retention */ }
314
362
  const groups = listBrowserSessions(profile);
315
- const taskIdentities = new Map(groups.map((g) => [g.profile, loadTaskIdentities(g.profile)]));
363
+ const taskIdentities = new Map(groups.map((g) => [g.profile, loadDurableTaskIdentities(g.profile)]));
316
364
  const index = buildLaunchSessionIndex();
317
- return groupIntoRows(groups, taskIdentities, (launchId) => resolveLaunchSession(index, launchId));
365
+ return groupIntoRows(groups, taskIdentities, (launchId) => resolveLaunchSession(index, launchId), (sessionId) => getSessionById(sessionId));
318
366
  }
319
367
  /**
320
368
  * Search predicate for the interactive picker: task name, profile, the linked
@@ -5,6 +5,8 @@ export interface BrowserIPCStreamOptions {
5
5
  task?: string;
6
6
  actor: string;
7
7
  launchId?: string;
8
+ /** Calling agent session, forwarded onto `start` requests (RUSH-2549). */
9
+ sessionId?: string;
8
10
  autoStartDaemon?: boolean;
9
11
  }
10
12
  /**
@@ -53,6 +53,7 @@ export async function runBrowserIPCStream(options) {
53
53
  taskName: request.taskName ?? defaultTask,
54
54
  actor: request.actor ?? options.actor,
55
55
  launchId: request.launchId ?? options.launchId,
56
+ sessionId: request.sessionId ?? options.sessionId,
56
57
  };
57
58
  }
58
59
  else if (!request.task && defaultTask) {
@@ -93,6 +93,13 @@ export interface Task {
93
93
  * from the caller over IPC. Optional: tasks from before this shipped carry none.
94
94
  */
95
95
  launchId?: string;
96
+ /**
97
+ * The agent session that started this task (`$AGENT_SESSION_ID`), forwarded
98
+ * from the caller at `start`. The durable copy lives in the `browser_sessions`
99
+ * table, which survives `stop`; this in-memory/tasks.json copy is the live one
100
+ * (RUSH-2549).
101
+ */
102
+ sessionId?: string;
96
103
  /**
97
104
  * Per-tab snapshot of the last ref listing captured for that tab
98
105
  * (shortId -> {descriptors, opts}). Persisted to tasks.json so a later
@@ -196,6 +203,18 @@ export interface IPCRequest {
196
203
  skipDomainSkill?: boolean;
197
204
  actor?: string;
198
205
  launchId?: string;
206
+ /**
207
+ * The calling agent session (`$AGENT_SESSION_ID` / `$AGENTS_SESSION_ID`) —
208
+ * the id that answers "which agent drove this task" and the one persisted to
209
+ * `browser_sessions` (RUSH-2549).
210
+ *
211
+ * This is the primary identity, not a spare: `launchId` alone was the join
212
+ * key, and a fleet measurement found it present on only 2 of 5 live agent
213
+ * processes while a session id was on 5 of 5 — every agent reaching the
214
+ * browser carries one. It is the same env `stampProvenance()` already reads
215
+ * for `computer.action` events, so both tool surfaces key on one signal.
216
+ */
217
+ sessionId?: string;
199
218
  }
200
219
  /** Subset of IPCResponse describing a recording start result. */
201
220
  export interface RecordStartFields {
@@ -20,6 +20,8 @@ export interface ByokUsageResult {
20
20
  error: string | null;
21
21
  }
22
22
  export declare function setByokFetchForTest(fn: typeof globalThis.fetch): void;
23
+ export declare const BYOK_REFRESH_INTERVAL_MS: number;
24
+ export declare function setByokCachePathForTest(value: string | null): string | null;
23
25
  export declare function resetByokCacheForTest(): void;
24
26
  export declare function hasByokProvider(provider: string): boolean;
25
27
  export declare function renderByokBar(result: ByokUsageResult): string;
@@ -30,9 +32,14 @@ export declare function renderByokBar(result: ByokUsageResult): string;
30
32
  * Returns a `ByokUsageResult` with `budget: null` when the token is absent
31
33
  * from the keychain (so the caller can skip rendering a bar without error).
32
34
  *
33
- * Results are SWR-cached per `keychainItem` so harnesses sharing one API key
34
- * deduplicate to a single network request.
35
+ * Ordinary reads are cache-only. Explicit refreshes are serialized per provider
36
+ * credential across every agents-cli process on the device.
35
37
  */
36
38
  export declare function getByokUsageForHarness(profile: Profile, opts?: {
37
39
  forceRefresh?: boolean;
38
40
  }): Promise<ByokUsageResult | null>;
41
+ /** Refresh each configured BYOK credential when its daemon-owned snapshot is due. */
42
+ export declare function refreshDueByokUsage(profiles: Profile[], now?: number): Promise<{
43
+ refreshed: number;
44
+ skipped: number;
45
+ }>;