@phnx-labs/agents-cli 1.22.117 → 1.22.119

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 (271) hide show
  1. package/CHANGELOG.md +301 -0
  2. package/dist/bootstrap.js +4 -11
  3. package/dist/commands/accounts.js +7 -4
  4. package/dist/commands/browser.d.ts +52 -70
  5. package/dist/commands/browser.js +192 -3562
  6. package/dist/commands/daemon.d.ts +39 -2
  7. package/dist/commands/daemon.js +72 -73
  8. package/dist/commands/events.js +1 -1
  9. package/dist/commands/exec.js +53 -1
  10. package/dist/commands/projects.js +92 -7
  11. package/dist/commands/repo.js +13 -49
  12. package/dist/commands/route.js +5 -5
  13. package/dist/commands/routines.js +39 -12
  14. package/dist/commands/sessions-render.d.ts +1 -1
  15. package/dist/commands/sessions-render.js +0 -1
  16. package/dist/commands/sessions.test-fixture.d.ts +0 -1
  17. package/dist/commands/sessions.test-fixture.js +0 -37
  18. package/dist/commands/setup-browser.d.ts +17 -12
  19. package/dist/commands/setup-browser.js +52 -87
  20. package/dist/commands/setup-preferences.d.ts +0 -17
  21. package/dist/commands/setup-preferences.js +18 -49
  22. package/dist/commands/setup.js +9 -9
  23. package/dist/commands/ssh.js +10 -1
  24. package/dist/commands/sync.js +6 -44
  25. package/dist/commands/teams.js +0 -1
  26. package/dist/commands/update.d.ts +19 -0
  27. package/dist/commands/update.js +34 -6
  28. package/dist/commands/view.d.ts +12 -1
  29. package/dist/commands/view.js +47 -2
  30. package/dist/index.js +107 -26
  31. package/dist/lib/account-capabilities.js +0 -2
  32. package/dist/lib/account-catalog.d.ts +38 -0
  33. package/dist/lib/account-catalog.js +110 -26
  34. package/dist/lib/account-provider-registry.js +1 -1
  35. package/dist/lib/account-registry.d.ts +1 -1
  36. package/dist/lib/account-registry.js +36 -2
  37. package/dist/lib/accounting/rotate.js +22 -8
  38. package/dist/lib/accounting/usage-ingest.d.ts +6 -1
  39. package/dist/lib/accounting/usage-ingest.js +115 -45
  40. package/dist/lib/accounting/usage-sync.d.ts +134 -31
  41. package/dist/lib/accounting/usage-sync.js +227 -66
  42. package/dist/lib/accounting/usage.d.ts +16 -3
  43. package/dist/lib/accounting/usage.js +26 -8
  44. package/dist/lib/accounts/add.d.ts +3 -1
  45. package/dist/lib/accounts/add.js +24 -13
  46. package/dist/lib/accounts/slots.d.ts +8 -0
  47. package/dist/lib/accounts/slots.js +17 -0
  48. package/dist/lib/add-dir.js +0 -1
  49. package/dist/lib/agent-cli-commands.js +0 -1
  50. package/dist/lib/agent-spec/agents.d.ts +6 -7
  51. package/dist/lib/agent-spec/agents.js +7 -60
  52. package/dist/lib/auth-health.d.ts +69 -1
  53. package/dist/lib/auth-health.js +133 -4
  54. package/dist/lib/browser/context.d.ts +82 -0
  55. package/dist/lib/browser/context.js +88 -0
  56. package/dist/lib/browser/paths.d.ts +25 -0
  57. package/dist/lib/browser/paths.js +51 -0
  58. package/dist/lib/browser/record.d.ts +38 -0
  59. package/dist/lib/browser/record.js +57 -0
  60. package/dist/lib/browser/sessions-list.js +1 -2
  61. package/dist/lib/browser-client.d.ts +158 -0
  62. package/dist/lib/browser-client.js +234 -0
  63. package/dist/lib/channels/owner-sink.d.ts +1 -18
  64. package/dist/lib/channels/owner-sink.js +29 -82
  65. package/dist/lib/channels/providers/rush.d.ts +7 -7
  66. package/dist/lib/channels/providers/rush.js +127 -57
  67. package/dist/lib/claude-account-token.d.ts +7 -1
  68. package/dist/lib/claude-account-token.js +26 -4
  69. package/dist/lib/claude-statusline.d.ts +1 -1
  70. package/dist/lib/claude-statusline.js +15 -3
  71. package/dist/lib/commands.js +1 -1
  72. package/dist/lib/crabbox/lease.js +1 -1
  73. package/dist/lib/crabbox/runtimes.js +1 -3
  74. package/dist/lib/daemon/account-state-daemon-service.js +1 -0
  75. package/dist/lib/daemon/auth-sync-service.d.ts +21 -18
  76. package/dist/lib/daemon/auth-sync-service.js +37 -43
  77. package/dist/lib/daemon/daemon.d.ts +25 -14
  78. package/dist/lib/daemon/daemon.js +92 -154
  79. package/dist/lib/daemon/runner.d.ts +2 -2
  80. package/dist/lib/daemon/runner.js +32 -9
  81. package/dist/lib/daemon/self-update-service.d.ts +35 -34
  82. package/dist/lib/daemon/self-update-service.js +40 -36
  83. package/dist/lib/daemon/service.d.ts +12 -8
  84. package/dist/lib/daemon/supervisor.d.ts +65 -54
  85. package/dist/lib/daemon/supervisor.js +136 -171
  86. package/dist/lib/daemon/testdata/process-view-start.js +5 -2
  87. package/dist/lib/daemon/usage-sync-service.d.ts +21 -30
  88. package/dist/lib/daemon/usage-sync-service.js +46 -78
  89. package/dist/lib/daemon-health.d.ts +22 -5
  90. package/dist/lib/daemon-health.js +47 -3
  91. package/dist/lib/daemon-services.d.ts +1 -1
  92. package/dist/lib/daemon-services.js +0 -10
  93. package/dist/lib/daemon-ticks.js +4 -2
  94. package/dist/lib/devices/doctor-findings.js +8 -11
  95. package/dist/lib/devices/harness-inventory.js +14 -5
  96. package/dist/lib/exec-account-home.js +5 -0
  97. package/dist/lib/exec.js +10 -13
  98. package/dist/lib/feed/events.js +0 -1
  99. package/dist/lib/feed/tool-activity.js +5 -2
  100. package/dist/lib/fleet-shared-state.d.ts +45 -0
  101. package/dist/lib/fleet-shared-state.js +78 -9
  102. package/dist/lib/fs-atomic.js +25 -0
  103. package/dist/lib/github/pr-mergeable.d.ts +4 -2
  104. package/dist/lib/github/pr-mergeable.js +5 -3
  105. package/dist/lib/github/project-prs.d.ts +58 -3
  106. package/dist/lib/github/project-prs.js +205 -7
  107. package/dist/lib/harness/adapters/cursor.js +14 -4
  108. package/dist/lib/harness-auth-capabilities.d.ts +4 -3
  109. package/dist/lib/harness-auth-capabilities.js +1 -2
  110. package/dist/lib/helper-versions.js +1 -1
  111. package/dist/lib/hooks/cache.d.ts +7 -0
  112. package/dist/lib/hooks/cache.js +27 -2
  113. package/dist/lib/hooks/install.js +7 -1
  114. package/dist/lib/hosts/ready.d.ts +38 -8
  115. package/dist/lib/hosts/ready.js +62 -14
  116. package/dist/lib/installations/active-check.d.ts +27 -0
  117. package/dist/lib/installations/active-check.js +61 -0
  118. package/dist/lib/installations/migrate.js +6 -3
  119. package/dist/lib/installations/shims.d.ts +1 -1
  120. package/dist/lib/installations/shims.js +32 -12
  121. package/dist/lib/installations/store.d.ts +9 -0
  122. package/dist/lib/installations/store.js +24 -0
  123. package/dist/lib/installations/update.js +21 -15
  124. package/dist/lib/installations/versions.js +15 -3
  125. package/dist/lib/manifest.js +1 -1
  126. package/dist/lib/models.js +0 -2
  127. package/dist/lib/open-url.js +28 -54
  128. package/dist/lib/profiles.js +0 -2
  129. package/dist/lib/projects.d.ts +16 -0
  130. package/dist/lib/projects.js +31 -0
  131. package/dist/lib/refresh.js +1 -1
  132. package/dist/lib/routine-readiness.d.ts +35 -0
  133. package/dist/lib/routine-readiness.js +74 -16
  134. package/dist/lib/rules/compile.js +6 -0
  135. package/dist/lib/sandbox.js +0 -2
  136. package/dist/lib/secrets-policy.d.ts +89 -11
  137. package/dist/lib/secrets-policy.js +175 -28
  138. package/dist/lib/session/active.d.ts +17 -6
  139. package/dist/lib/session/active.js +105 -49
  140. package/dist/lib/session/db.d.ts +1 -1
  141. package/dist/lib/session/db.js +65 -18
  142. package/dist/lib/session/discover.js +1 -283
  143. package/dist/lib/session/mirror.d.ts +4 -3
  144. package/dist/lib/session/mirror.js +4 -3
  145. package/dist/lib/session/parse.d.ts +0 -2
  146. package/dist/lib/session/parse.js +1 -138
  147. package/dist/lib/session/pid-registry.d.ts +6 -3
  148. package/dist/lib/session/pid-registry.js +18 -8
  149. package/dist/lib/session/remote/watch.d.ts +1 -1
  150. package/dist/lib/session/remote/watch.js +7 -3
  151. package/dist/lib/session/throughput.d.ts +1 -3
  152. package/dist/lib/session/throughput.js +0 -20
  153. package/dist/lib/session/types.d.ts +2 -2
  154. package/dist/lib/session/types.js +2 -2
  155. package/dist/lib/sessions-client.d.ts +60 -1
  156. package/dist/lib/sessions-client.js +227 -4
  157. package/dist/lib/setup-tool-status.js +5 -10
  158. package/dist/lib/signin-badge.d.ts +3 -2
  159. package/dist/lib/signin-badge.js +6 -3
  160. package/dist/lib/smart-launch.js +4 -1
  161. package/dist/lib/staleness/detectors/commands.d.ts +1 -1
  162. package/dist/lib/staleness/detectors/hooks.d.ts +1 -1
  163. package/dist/lib/staleness/detectors/mcp.d.ts +1 -1
  164. package/dist/lib/staleness/detectors/permissions.d.ts +1 -1
  165. package/dist/lib/staleness/detectors/plugins.d.ts +1 -1
  166. package/dist/lib/staleness/detectors/rules.d.ts +1 -1
  167. package/dist/lib/staleness/detectors/skills.d.ts +1 -1
  168. package/dist/lib/staleness/detectors/subagents.d.ts +1 -1
  169. package/dist/lib/staleness/detectors/workflows.d.ts +1 -1
  170. package/dist/lib/staleness/writers/commands.d.ts +1 -1
  171. package/dist/lib/staleness/writers/hooks.d.ts +1 -1
  172. package/dist/lib/staleness/writers/mcp.d.ts +1 -1
  173. package/dist/lib/staleness/writers/permissions.d.ts +1 -1
  174. package/dist/lib/staleness/writers/plugins.d.ts +1 -1
  175. package/dist/lib/staleness/writers/rules.d.ts +1 -1
  176. package/dist/lib/staleness/writers/skills.d.ts +1 -1
  177. package/dist/lib/staleness/writers/sources.js +5 -0
  178. package/dist/lib/staleness/writers/subagents.d.ts +1 -1
  179. package/dist/lib/staleness/writers/workflows.d.ts +1 -1
  180. package/dist/lib/state.d.ts +6 -4
  181. package/dist/lib/state.js +7 -17
  182. package/dist/lib/teams/parsers.d.ts +1 -1
  183. package/dist/lib/teams/parsers.js +1 -136
  184. package/dist/lib/teams/placement-probe.js +50 -15
  185. package/dist/lib/teams/scheduler.d.ts +7 -0
  186. package/dist/lib/types.d.ts +16 -1
  187. package/dist/lib/types.js +1 -1
  188. package/dist/lib/view-types.d.ts +32 -0
  189. package/dist/lib/watchdog/read.js +0 -1
  190. package/dist/lib/watchdog/rotate.js +1 -2
  191. package/dist/lib/watchdog/runner.js +2 -2
  192. package/dist/lib/watchdog/watchdog.d.ts +1 -1
  193. package/dist/lib/watchdog/watchdogTail.js +0 -31
  194. package/package.json +1 -1
  195. package/scripts/postinstall.js +8 -8
  196. package/dist/browser.d.ts +0 -2
  197. package/dist/browser.js +0 -17
  198. package/dist/commands/browser-picker.d.ts +0 -18
  199. package/dist/commands/browser-picker.js +0 -97
  200. package/dist/lib/browser/arc-discovery.d.ts +0 -52
  201. package/dist/lib/browser/arc-discovery.js +0 -197
  202. package/dist/lib/browser/arc-dom.d.ts +0 -14
  203. package/dist/lib/browser/arc-dom.js +0 -121
  204. package/dist/lib/browser/caller-identity.d.ts +0 -40
  205. package/dist/lib/browser/caller-identity.js +0 -175
  206. package/dist/lib/browser/cdp.d.ts +0 -51
  207. package/dist/lib/browser/cdp.js +0 -254
  208. package/dist/lib/browser/chrome.d.ts +0 -141
  209. package/dist/lib/browser/chrome.js +0 -704
  210. package/dist/lib/browser/chromium-discovery.d.ts +0 -28
  211. package/dist/lib/browser/chromium-discovery.js +0 -96
  212. package/dist/lib/browser/devices.d.ts +0 -34
  213. package/dist/lib/browser/devices.js +0 -61
  214. package/dist/lib/browser/domain-skills.d.ts +0 -71
  215. package/dist/lib/browser/domain-skills.js +0 -195
  216. package/dist/lib/browser/drivers/arc.d.ts +0 -40
  217. package/dist/lib/browser/drivers/arc.js +0 -276
  218. package/dist/lib/browser/drivers/firefox.d.ts +0 -99
  219. package/dist/lib/browser/drivers/firefox.js +0 -377
  220. package/dist/lib/browser/drivers/local.d.ts +0 -55
  221. package/dist/lib/browser/drivers/local.js +0 -266
  222. package/dist/lib/browser/drivers/ssh.d.ts +0 -120
  223. package/dist/lib/browser/drivers/ssh.js +0 -467
  224. package/dist/lib/browser/editor.d.ts +0 -3
  225. package/dist/lib/browser/editor.js +0 -50
  226. package/dist/lib/browser/ffmpeg.d.ts +0 -12
  227. package/dist/lib/browser/ffmpeg.js +0 -184
  228. package/dist/lib/browser/firefox-discovery.d.ts +0 -69
  229. package/dist/lib/browser/firefox-discovery.js +0 -162
  230. package/dist/lib/browser/har.d.ts +0 -85
  231. package/dist/lib/browser/har.js +0 -77
  232. package/dist/lib/browser/hygiene.d.ts +0 -97
  233. package/dist/lib/browser/hygiene.js +0 -153
  234. package/dist/lib/browser/index.d.ts +0 -5
  235. package/dist/lib/browser/index.js +0 -5
  236. package/dist/lib/browser/input.d.ts +0 -7
  237. package/dist/lib/browser/input.js +0 -92
  238. package/dist/lib/browser/ipc.d.ts +0 -204
  239. package/dist/lib/browser/ipc.js +0 -1453
  240. package/dist/lib/browser/login-detection.d.ts +0 -87
  241. package/dist/lib/browser/login-detection.js +0 -274
  242. package/dist/lib/browser/profiles.d.ts +0 -422
  243. package/dist/lib/browser/profiles.js +0 -1157
  244. package/dist/lib/browser/refs.d.ts +0 -89
  245. package/dist/lib/browser/refs.js +0 -191
  246. package/dist/lib/browser/registry.d.ts +0 -70
  247. package/dist/lib/browser/registry.js +0 -252
  248. package/dist/lib/browser/remote-control.d.ts +0 -59
  249. package/dist/lib/browser/remote-control.js +0 -85
  250. package/dist/lib/browser/resolve-target.d.ts +0 -66
  251. package/dist/lib/browser/resolve-target.js +0 -264
  252. package/dist/lib/browser/runtime-state.d.ts +0 -291
  253. package/dist/lib/browser/runtime-state.js +0 -584
  254. package/dist/lib/browser/secret-ref.d.ts +0 -10
  255. package/dist/lib/browser/secret-ref.js +0 -14
  256. package/dist/lib/browser/service.d.ts +0 -812
  257. package/dist/lib/browser/service.js +0 -4693
  258. package/dist/lib/browser/stream.d.ts +0 -17
  259. package/dist/lib/browser/stream.js +0 -72
  260. package/dist/lib/browser/task-index.d.ts +0 -78
  261. package/dist/lib/browser/task-index.js +0 -199
  262. package/dist/lib/browser/types.d.ts +0 -647
  263. package/dist/lib/browser/types.js +0 -61
  264. package/dist/lib/browser/upload.d.ts +0 -29
  265. package/dist/lib/browser/upload.js +0 -298
  266. package/dist/lib/daemon/browser-ipc-service.d.ts +0 -20
  267. package/dist/lib/daemon/browser-ipc-service.js +0 -46
  268. package/dist/lib/daemon/browser-task-reap-service.d.ts +0 -14
  269. package/dist/lib/daemon/browser-task-reap-service.js +0 -26
  270. package/dist/lib/fleet-shared-repo-sync.d.ts +0 -55
  271. package/dist/lib/fleet-shared-repo-sync.js +0 -490
package/CHANGELOG.md CHANGED
@@ -1,5 +1,298 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.22.119
4
+
5
+ - **A setup-token (provider) Claude account no longer opens on Claude Code's first-run
6
+ theme picker on a worker.** A provider account has no slot, so it runs in the
7
+ executable's shared version home, and nothing ever marked that home onboarded: an AGI
8
+ EXT tab dispatched to a worker landed on "Choose the text style…" instead of the agent.
9
+ A credentialed Claude spawn on a non-headed device now seeds `hasCompletedOnboarding` in
10
+ the home it runs in, right after the worker login-trap preflight in `spawnAgentLeased`
11
+ (explicit `#account`, default account, balanced pick, interactive tmux). Headless paths
12
+ that spawn elsewhere (`--loop`, routines) never show onboarding in print mode; the
13
+ Windows `.cmd` shim passthrough is not covered. With no email the seed writes only the
14
+ flag, so the home's own login identity is untouched; it writes through the
15
+ `.claude/.claude.json -> ../.claude.json` link instead of replacing it; and a document
16
+ already onboarded is left byte-identical. Source: `cli/src/lib/exec.ts`,
17
+ `cli/src/lib/claude-account-token.ts`.
18
+
19
+ - **A headless Cursor run in plan mode now runs in folders Cursor has not seen
20
+ before, and prints its answer.** Two bugs stopped `agents run cursor "…" --mode
21
+ plan`, a Cursor teammate (`agents teams add … cursor …`), and a plan-mode Cursor
22
+ routine from working unattended:
23
+ - They passed `--plan` without `--trust`. In a directory Cursor had not seen,
24
+ Cursor stopped on "Do you trust the contents of this directory?" and exited
25
+ with no one to answer, so a teammate failed in 7 seconds with 0 tools. Every
26
+ headless mode except skip (which passes `-f`) now passes `--trust`. `--trust`
27
+ only accepts the configured working directory and does not bypass tool
28
+ permissions.
29
+ - In `--plan` mode Cursor delivers its answer through its createPlan tool, which
30
+ `-p` text output never prints. A run would read the repo for 3 minutes, exit 0,
31
+ and leave an empty log. A headless plan run now uses Cursor's read-only ask
32
+ mode (`--mode ask`), which refuses file writes the same way and prints its
33
+ answer.
34
+
35
+ Interactive Cursor runs keep `--plan` and Cursor's own trust prompt. Source:
36
+ `cli/src/lib/harness/adapters/cursor.ts`.
37
+
38
+ - **Grok subscription seats log in per worker through the device-code flow.** `grok` now has the
39
+ same `per-device:device-auth` worker path as `codex`: `agents accounts add grok <name> --per-device`
40
+ registers the account with no API key, and `agents accounts login grok#<name> --per-device` on a
41
+ worker runs `grok login --device-auth` into that account's slot. The box prints a URL and code
42
+ that you approve in your own browser, so SuperGrok / X Premium+ seats run on workers without an
43
+ `XAI_API_KEY`, which bills API credits rather than the subscription. `accounts login --per-device`
44
+ is new and is the one login a worker may run for a dual-path harness (codex too); the plain
45
+ re-login stays headed-only. Source: `cli/src/lib/harness-auth-capabilities.ts`,
46
+ `cli/src/lib/accounts/add.ts`, `cli/src/commands/accounts.ts`.
47
+
48
+ - **The `grok` shim runs the release `grok update` installed.** Grok's updater now writes
49
+ `~/.grok/bin/grok-<version>` and repoints `~/.grok/bin/grok`, leaving `downloads/` alone, but the
50
+ shim only scanned `downloads/`, so it kept running the old binary after an update (on one worker,
51
+ 1.0.4, which xAI rejects with `426 ... outdated`). The shim, the `grok@<version>` alias, and
52
+ `getBinaryPath` now follow grok's own `bin/grok` pointer first and fall back to the `downloads/`
53
+ scan for older layouts. The shim schema version is bumped so installed shims regenerate.
54
+ Source: `cli/src/lib/installations/shims.ts`, `cli/src/lib/installations/store.ts`.
55
+
56
+ - **Editor terminals follow the current agent session after a restart (PHNX-4218).**
57
+ Active/watch rows adopt the live agent descendant's recorded session, transcript,
58
+ terminal ID and launch ID while keeping the tab's shell PID and metadata. Only the
59
+ nearest recorded agents qualify, so nested agents cannot take over the tab. The most
60
+ recent recorded start wins at that depth, with PID as a stable tie-breaker; known
61
+ tab kinds must match. Windows retains the published identity until process starts
62
+ can be verified. Published terminal IDs
63
+ also survive when no descendant supplies one. Rows expose a display-only `accountLabel`
64
+ when the indexed account identifies one registered native slot; ambiguous identities
65
+ stay unlabeled, and org-only keys require a matching email.
66
+
67
+ - **`agents projects prs` scopes a shared monorepo per project, and `agents projects prs merge` merges one PR (PHNX-4215).** When several projects share one repository, each project now lists only the PRs whose changed files touch the paths it claims (`scope: project`) or touch no sharing project's paths (`scope: repo-wide`). It uses the same `defaultPath`/`subpath` claim that attributes a session's cwd, and changed files are cached per head SHA. Rows gain `createdAt`. The envelope gains `viewer` and a per-repo `sharedWith`, and the `--number` detail adds `mergeable`/`mergeableState`. `agents projects prs merge <name> --repo … --number … --sha <head>` merges with one REST call pinned to the reviewed head, so GitHub refuses if the branch moved since. Repo canonicalization moved from GraphQL `gh repo view` to a cached REST read, which drops a warm refresh from about 2s to under 1s. Source: `cli/src/lib/github/project-prs.ts`, `cli/src/lib/projects.ts`, `cli/src/commands/projects.ts`.
68
+
69
+ ## 1.22.118
70
+
71
+ - **`agents sessions <read> --device <name>` routes a SINGLE-device READ through the standalone `sessions --host` when both sides support it (PHNX-4012).**
72
+ A read `--device` query (search / list / id lookup, and no explicit `--host`) that names exactly one
73
+ device now resolves it to its SSH target and forwards `sessions <read args> --host ssh://<target>` to
74
+ the local standalone — the local-orchestration collapse where `sessions` owns the remote hop, instead
75
+ of the in-repo peer fan-out. `--host` is point-to-one, so a **multi-device** read (`--device box
76
+ mac-mini`, a repeated `--device`, or a `--device all`/`fleet` sentinel) stays on the in-repo `--device`
77
+ fan-out, which merges the peers. It takes the standalone path only when THIS box's `sessions` is ≥ 0.2.1. If the PEER
78
+ lacks the standalone the remote `bash -lc` command-not-found surfaces as exit 127, on which the read
79
+ falls through to the existing in-repo `--device` fan-out so it still succeeds — a capability gate
80
+ keyed on that specific signal (same spirit as the 0.2.1 `--host` version gate), a migration bridge
81
+ until the fleet is uniformly on 0.2.1. Below the host floor, or with no standalone installed, a
82
+ `--device` read stays on the in-repo engine exactly as before. Lifecycle `--device` (resume / watch /
83
+ inject / focus / …) is untouched, and an explicit `--host` still wins. Internal routing change with no
84
+ user-visible behavior change on a healthy fleet. Source: `cli/src/lib/sessions-client.ts`,
85
+ `cli/src/index.ts`.
86
+
87
+ - **`agents sessions … --host <target>` forwards to the standalone `sessions` CLI (PHNX-4012).**
88
+ A point-to-one remote read (`agents sessions <query> --host box` — SSH to ONE box, run
89
+ `sessions … --local`, stream JSON back) now takes the standalone fast path when the installed
90
+ `sessions` is ≥ 0.2.1, mirroring how the 0.2.0 filter/sort flags are version-gated. A box with
91
+ `sessions` below the 0.2.1 host floor — or none installed — keeps the query on the in-repo engine
92
+ exactly as before (which resolves `--device` against the fleet), so nothing mis-routes or crashes.
93
+ This is an internal routing change: `--host` behaves the same for callers, only the engine that
94
+ answers it changes. Source: `cli/src/lib/sessions-client.ts`, `cli/src/index.ts`.
95
+
96
+ - **`agents browser` is now a thin consumer of the standalone `browser` CLI (PHNX-4101).** The
97
+ duplicate in-repo browser engine — the CDP/BiDi/Arc drivers, the browser IPC service, the
98
+ chrome-data/profile store and the network-capture pipeline — is deleted; every verb forwards
99
+ verbatim to `@phnx-labs/browser-cli` (`browser`), which owns the engine and keeps every on-disk
100
+ path the old subsystem used. agents-cli supplies only what the fleet CLI knows: `--device`
101
+ resolved to an SSH target (bound once at `start`), remote-control consent, the acting session
102
+ identity, and the capture/session history behind `agents browser sessions`. The daemon no longer
103
+ hosts the browser IPC service or the browser-task reaper (browser-cli runs its own), and the
104
+ retired `browser` alias shim no longer shadows the standalone binary on PATH. Install it with
105
+ `npm i -g @phnx-labs/browser-cli` or `agents setup browser`. Source: `cli/src/lib/browser-client.ts`,
106
+ `cli/src/commands/browser.ts`, `cli/src/lib/browser/{context,record,sessions-list,paths}.ts`,
107
+ `cli/src/lib/daemon/daemon.ts`, `cli/docs/browser.md`.
108
+
109
+ - **A PreToolUse hook whose script is missing now denies the tool call instead of allowing it (PHNX-4106).**
110
+ Generated hook shims embed one source path inside a version home; when that file was gone (a
111
+ pruned version, sync rewriting `hooks/`) the shim exited 127, which Claude Code, Codex and Droid
112
+ read as "allow". On one laptop the primary-checkout guard was silently disabled for about 17
113
+ hours this way. A `PreToolUse` shim now exits 2 with the repair named (`agents hooks sync`) and
114
+ logs `cache: missing-source`, after the `matches:` gate and only for a PreToolUse firing; other
115
+ events and skipped fires stay fail-open. `agents prune <harness>@<version>` also re-points the
116
+ shims at the surviving home immediately instead of waiting for the daemon. Source:
117
+ `cli/src/lib/hooks/cache.ts`, `cli/src/lib/installations/versions.ts`.
118
+
119
+ - **Claude no longer gets every plugin skill twice.** Sync flattened each plugin's `skills/` into
120
+ the top-level `skills/` of every harness, but Claude Code already loads them from the plugin
121
+ registration, namespaced (`/sessions:continue`), so the picker listed `/continue` and
122
+ `/sessions:continue` side by side for 47 skills. Claude is flagged `nativePluginSkills`: sync
123
+ stops flattening there, and the leftover copies are swept by the next full `agents sync claude`
124
+ (or `agents prune cleanup skills`). Harnesses that only see plugin skills through the flat copy
125
+ (Codex) are unchanged. Source: `cli/src/lib/staleness/writers/sources.ts`,
126
+ `cli/src/lib/agent-spec/agents.ts`.
127
+
128
+ - **`auth-sync` credential pushes plan per peer off that peer's own first-hand reply, with no fleet-wide freshness gate (PHNX-4116).**
129
+ The daemon's `auth-sync` tick no longer skips **every** credential push when the newest fleet exchange goes
130
+ stale — the old `readLastSuccessfulExchangeMs` marker and its "skipping credential push … need one within
131
+ 900s" WARN are gone. Reserved-key presence on a peer is now `verdict ∧ fingerprint`: the peer's own per-account
132
+ verdict row (`accounts.rows`) must be non-`missing` AND the credential fingerprint (`workerCredential.mintedAt`)
133
+ the publisher last delivered to that peer must match the account's current one. The verdict half is first-hand
134
+ — a key removed on a worker flips its next verdict to `missing` and the push resumes. The fingerprint half
135
+ catches a re-mint: `agents accounts login <harness>#<name>` rotates the reserved key and bumps `mintedAt` while
136
+ the worker's OLD token still authenticates (verdict stays live), so a publisher-side rotation cursor
137
+ (`reserved-sync-delivered.json`, local-only, never synced) re-pushes the new key within one tick instead of
138
+ reading present forever. A peer that has never replied, or whose reply carries no `accounts.rows` field at all
139
+ (an older CLI — fail closed), is skipped this tick and logged at INFO, not WARN. The push stays idempotent, so
140
+ a stale reply is safe. No user-visible surface change; a re-authed account now reaches every worker within a
141
+ tick, and a briefly-quiet exchange no longer stalls provisioning. Source: `cli/src/lib/daemon/auth-sync-service.ts`,
142
+ `cli/src/lib/secrets-policy.ts`.
143
+
144
+ - **Drop stale worker account slots and their credentials (PHNX-4116).** On a
145
+ worker, `reconcileLocalWorkerSlots` now removes any `deviceAccounts.slots`
146
+ record whose account is no longer registered — the leftovers of an older
147
+ account-id generation, each a full HOME carrying a live `.claude/.oauth_token`
148
+ — deleting the 0600 credential while KEEPING the directory (its
149
+ `.claude/projects` holds transcripts) and logging one line per drop. It fails
150
+ closed: an empty or unreadable account registry drops nothing, so a transient
151
+ read can never strip a healthy box's whole slot set. Source:
152
+ `cli/src/lib/secrets-policy.ts`, `cli/src/lib/accounts/slots.ts`.
153
+
154
+ - **A routine skipped by an overlapping run reads `blocked`, not "wedged"
155
+ (PHNX-4116).** Since there is no longer a "wedged" daemon state, a routine
156
+ whose prior run is still active now reports `blocked: run <id> active since
157
+ <t>` — naming the live run and when it started — instead of the stale "wedged:
158
+ a prior run is still active". Source: `cli/src/commands/routines.ts`.
159
+
160
+ - **`agents daemon status` no longer calls a worker's absent secrets broker
161
+ `down` (PHNX-4116).** On a box that reads file-backed secret stores (every
162
+ headless worker), an unreachable broker is expected — secrets read one-shot
163
+ with no broker — so the health line now reads `info secrets agent not running
164
+ (file-backed stores)` instead of `down secrets broker (unreachable)`. A
165
+ keychain-backed box with no broker is still a real fault and still reads
166
+ `down`. Source: `cli/src/commands/daemon.ts`.
167
+
168
+ - **A balanced pick or the account picker now launches the account it chose (PHNX-4116).**
169
+ Since accounts became registered slots (PHNX-3940), a `balanced` pick and the "no fresh usage"
170
+ picker only set the executable version, so the run started in that version's home with whatever
171
+ login it held. On yosemite-m0 the picker chose `trp` and Claude Code opened as another account,
172
+ in its first-run wizard. Both paths now resolve the picked candidate through the same local
173
+ launch resolver an explicit `--account` uses, so the spawn gets the slot's home and durable
174
+ credential env. Source: `cli/src/commands/exec.ts`.
175
+
176
+ - **One run-readiness gate, computed on the box that runs (PHNX-4116).** `agents view --json`
177
+ now carries a per-agent `runReady` (`{ ready, reason, accounts: [{ name, ready, reason }] }`)
178
+ computed from the router's own enumeration — native account slots AND version homes
179
+ (`collectRunCandidates` → `readinessFromCandidate`), not the per-version list, which missed the
180
+ slots a run actually picks from. `--device auto` reads that answer instead of re-deriving usage
181
+ freshness on the dispatching box, so a worker holding a valid setup-token is schedulable on that
182
+ fact: a synced-only usage row (its poller lives on the headed box that published it) is never
183
+ refused for being old — its age weights the pick, it never decides eligibility — and a
184
+ rate-limit window whose reset has already passed reads as available. A placement error now names
185
+ the box's own reason, e.g. `no ready harness account (all signed_out)`, instead of a bare
186
+ `no ready harness account`. `agents devices harnesses` now derives its displayed usage
187
+ percentage from the SAME live windows as the status verdict (`liveUsageWindows`), so a
188
+ maxed-then-reset account no longer reads `available` next to a stale ~100%. The one-release
189
+ fallback for an older remote CLI without `runReady` keeps the pre-fix throttle exclusion — a
190
+ FRESH `rate_limited`/`out_of_credits` or a FRESH dead auth verdict still disqualifies a
191
+ launchable version, while a STALE reading stays unverified — so a throttled worker cannot slip
192
+ into `--device auto` during a rolling upgrade. Source: `cli/src/commands/view.ts`,
193
+ `cli/src/lib/hosts/ready.ts`, `cli/src/lib/accounting/rotate.ts`,
194
+ `cli/src/lib/accounting/usage.ts`, `cli/src/lib/devices/harness-inventory.ts`,
195
+ `cli/src/lib/smart-launch.ts`.
196
+
197
+ - **A wedged daemon service now restarts the whole daemon instead of parking a dead service or reading `wedged` forever (PHNX-4116).**
198
+ A supervised daemon service that HANGS past its deadline (a stuck usage refresh, a frozen heartbeat)
199
+ no longer parks and waits for an in-process backoff restart that could stall for days — the
200
+ supervisor records the cause and exits the process (code 70), and systemd (`Restart=always`,
201
+ `RestartSec=30`, `StartLimitIntervalSec=0`, `KillMode=process`) / launchd (`KeepAlive` +
202
+ `ThrottleInterval=30`) restart the daemon within ~30s, so it recovers on its own like any
203
+ well-behaved service. A service whose tick merely THROWS is recorded and keeps ticking. The
204
+ `parked` service state and the `wedged` daemon state are gone: `agents daemon status` now reports
205
+ `running`/`stopped`, the daemon's PID, uptime, heartbeat age, and the count of supervised restarts
206
+ in the last 24h with the last cause. Source: `cli/src/lib/daemon/supervisor.ts`,
207
+ `cli/src/lib/daemon/daemon.ts`.
208
+
209
+ - **Usage rows and daemon state travel over SSH; the shared user repo carries no daemon state (PHNX-4116).**
210
+ The 15-minute `usage-sync` tick used to commit every device's `devices/<device>/daemon-state.json`
211
+ into the fleet-synced user repo and exchange it under a lock and a 45 s deadline. That grew the
212
+ shared store to 1.1 GiB and 18,358 commits (100% of the last 2,000 were `chore(devices): publish
213
+ <device> daemon state`), one worker's clone fell 10,398 commits behind with `git fetch timed out`
214
+ on every tick, and a box holding a valid setup-token could not be scheduled because a repo was
215
+ bloated. A headed (`personal`/`desktop`) daemon now dials every dialable peer in parallel with
216
+ `agents __usage-ingest --reply` (20 s per peer; a timed-out peer is skipped for that tick), sending
217
+ its own envelope on stdin; the peer merges the usage rows into its cache newest-wins, stores the
218
+ envelope as that peer's file, and prints its own state back, which the headed box stores stamped
219
+ `receivedAt`. Workers never initiate. The placement probe ingests the dispatcher's usage rows on the
220
+ same round-trip, so the chosen worker holds current numbers at dispatch. `agents repo sync user` is
221
+ a plain fetch-and-fast-forward of human-authored resources again; the 8-minute kickoff offset that
222
+ only existed to dodge the repo lock is gone. `__usage-ingest` gains `--reply`; the legacy v1 payload
223
+ from an older headed peer is still accepted. Source: `cli/src/lib/accounting/usage-sync.ts`,
224
+ `cli/src/lib/accounting/usage-ingest.ts`, `cli/src/lib/daemon/usage-sync-service.ts`.
225
+
226
+ - **`agents update claude#work` works, and a refused update names the process holding the installation (PHNX-4116).**
227
+ The `<agent>#<account>` selector `agents run` already takes was rejected by `update` as
228
+ "Unknown agent 'claude#work'"; it now resolves to the managed installation that account runs on
229
+ and refuses only an account the registry does not know. "Account home is in use; retry after its
230
+ sessions finish" is replaced by the actual holder, e.g. `pid 2173999, up 01:10:22, pts/1:
231
+ …/claude --resume 3ef30267…`, with `agents sessions stop <id>` as the way out. Source:
232
+ `cli/src/commands/update.ts`, `cli/src/lib/installations/active-check.ts`.
233
+
234
+ - **`agents view` / `agents accounts list` show FACTS per account per box, never a
235
+ word that means "we did not look" (PHNX-4116).** Each account row now states its
236
+ evidence: the **token** on disk (`sk-ant-oat01 (Sep 16)` = the slot's
237
+ `.claude/.oauth_token` scheme prefix + file date, `api key (present)`, or
238
+ `no token`), what happened when it was last **used** (`last used ok 12m ago` /
239
+ `last auth failure 401 Sep 20 14:02` / `rate-limited until 15:00` / `not used on
240
+ this box yet`), and a **usage** reading that names its origin when it came from
241
+ another box (`S 12% W 40% … (from zion)`). The auth fact is recorded from real run
242
+ outcomes into the auth-health cache with a new `source: 'run'` field — an auth
243
+ failure at the routine runner's `isAuthFailureFromLog` sites, a success at
244
+ statusline ingest and a clean headless `agents run` exit. `agents view <harness>
245
+ --json` accounts now carry `token` and `lastAuth` for the emitting box. Source:
246
+ `cli/src/lib/auth-health.ts`, `cli/src/lib/account-catalog.ts`,
247
+ `cli/src/commands/accounts.ts`, `cli/src/commands/view.ts`.
248
+
249
+ - **A synced usage file no longer masquerades as a live auth verdict, and a worker
250
+ no longer publishes a `unverified` probe row (PHNX-4116).** `verdictFromFreshUsage`
251
+ refuses a `freshness.source === 'sync'` snapshot — a fresh reading from another
252
+ box's poller proves the shared token works somewhere, not that THIS box can
253
+ authenticate. A worker's setup-token box, which cannot read the usage endpoint,
254
+ now returns the honest `no_evidence` verdict (dropped from the published probe
255
+ rows) instead of the overloaded `unverified`, so eight identical workers read one
256
+ distinct picture instead of five. Source: `cli/src/lib/auth-health.ts`.
257
+
258
+ - **A `--host <worker>` routine activates on a token-backed worker again
259
+ (PHNX-4116).** Dropping the worker's `no_evidence` probe row left `agents devices
260
+ ping --local --json` with no row for the agent, so host-placed routine readiness
261
+ read the absent row as `unconfigured` and reported `agent_auth_failed` with a
262
+ valid token on disk. `devices ping --local --json` now also emits `launchable`
263
+ (the agents this box holds a launchable signed-in credential for, from the same
264
+ `collectRunCandidates` the run router uses), and one shared decision
265
+ (`decideRoutineAuthReadiness`) is used by both the local and host readiness paths:
266
+ an absent row plus a launchable credential is ready, a box with no credential
267
+ fails, and a fresh `revoked` blocks — so both paths reach the same answer for the
268
+ same box. Source: `cli/src/lib/routine-readiness.ts`, `cli/src/commands/ssh.ts`.
269
+
270
+ - **`--device auto` no longer refuses a worker whose usage reading is merely old (PHNX-4116).**
271
+ Remote readiness re-derived a 40-minute usage-freshness refusal from `agents view --json`'s
272
+ per-version list, so one broken usage-sync made every worker read `no ready harness account`
273
+ while `--device <name>` on the same box launched fine. The dispatcher now READS the running box's
274
+ own `runReady` verdict instead of re-deriving it (see the readiness fragment); usage age weights
275
+ the pick, it never decides eligibility. Source: `cli/src/lib/hosts/ready.ts`.
276
+
277
+ - **The daemon no longer freezes for minutes on session-index and mirror writes (PHNX-4154).**
278
+ `session_text` FTS rows now sit at the rowid of the `sessions` row they describe and are
279
+ addressed by it (schema v51, a one-time rebuild: 24 s for a 669 MB index). Every delete and
280
+ content read used to filter on the UNINDEXED `session_id`, a full scan of the FTS content per
281
+ statement; the fleet session mirror runs one per mirrored row inside a daemon tick, so the
282
+ daemon's event loop stalled for 10+ minutes per tick, every service logged `tick exceeded
283
+ deadline`, and `agents browser` verbs on the same loop timed out with
284
+ `Arc Apple Event timed out`. Source: `cli/src/lib/session/db.ts`.
285
+
286
+ - **Fix `ENOTDIR` crash on stale lock files.** `withFileLock` and `withFileLockAsync`
287
+ now self-heal when a prior crash left a regular file instead of the directory
288
+ `proper-lockfile` expects, matching the caller's `realpath` option when computing
289
+ the lock path. Source: `cli/src/lib/fs-atomic.ts`.
290
+
291
+ - **Fix `Unknown account` for unregistered native logins.** `ag run claude#email`
292
+ now discovers a native OAuth login from version-home `.claude.json` files when the
293
+ account is not yet in `accounts.native`, and correctly routes it through the
294
+ provider-backed harness guard. Source: `cli/src/lib/account-registry.ts`.
295
+
3
296
  ## 1.22.117
4
297
 
5
298
  - **`agents run --local`, and `--device <this machine>` no longer SSHes to itself.** A bare
@@ -11,6 +304,14 @@
11
304
  MagicDNS name, loopback, or the `interactive` sentinel now resolves to the same local
12
305
  run. The placement-failure hint names `--local`. Source: `cli/src/commands/exec.ts`
13
306
  (`pinLocalWhenTargetIsSelf`), `cli/src/lib/placement.ts`, `cli/src/lib/hosts/remote-cmd.ts`.
307
+ - **`agents sessions` filter/sort queries take the standalone fast path when it's new enough.**
308
+ `--project`/`-p`, `--since`, `--until`, `--sort`, and the harness shorthands
309
+ (`--claude`/`--codex`/…) now route to the standalone `sessions` binary when the installed one is
310
+ ≥ 0.2.0 (which implements them), and stay on the in-process engine otherwise — a version probe
311
+ (`sessions --version`, cached, run only when such a flag is present) gates it, so an older binary
312
+ never gets a flag it would mis-read as an FTS token. `--json`/`--limit`/`--agent` and a bare
313
+ query/id already route unconditionally, unchanged. Behavior is unchanged; the fast path just
314
+ covers more queries. Source: `cli/src/lib/sessions-client.ts`, `cli/src/index.ts`.
14
315
 
15
316
  ## 1.22.116
16
317
 
package/dist/bootstrap.js CHANGED
@@ -1193,18 +1193,11 @@ catch (err) {
1193
1193
  if (err instanceof Error && err.name === 'ExitPromptError') {
1194
1194
  process.exit(130);
1195
1195
  }
1196
- // Browser-service-not-running and CDP-not-reachable surface as typed errors
1197
- // from src/lib/browser/. Don't dump a Node stacktrace for these — they are
1198
- // user-actionable, not engineering bugs. See issues #41 and #43.
1199
1196
  if (err instanceof Error) {
1200
- const isBrowserServiceNotRunning = err.name === 'BrowserServiceNotRunningError';
1201
- const isBrowserCdpUnreachable = err.name === 'BrowserCdpConnectionError';
1202
- const isBrowserIpcDown = err.message.startsWith('IPC error:') &&
1203
- (err.message.includes('ECONNREFUSED') || err.message.includes('ENOENT'));
1204
- if (isBrowserServiceNotRunning || isBrowserCdpUnreachable || isBrowserIpcDown) {
1205
- console.error(err.message);
1206
- process.exit(1);
1207
- }
1197
+ // (The browser-service-not-running / CDP-unreachable / IPC-down typed errors
1198
+ // were thrown by the in-repo browser engine, deleted with PHNX-4101; the
1199
+ // standalone `browser` CLI now prints its own user-actionable errors and
1200
+ // agents-cli forwards its exit code, so there is nothing to special-case here.)
1208
1201
  // A --device targeting a password-auth device throws this from resolveHost.
1209
1202
  // It carries an actionable message (switch to key auth / enroll as a host);
1210
1203
  // handling it here covers every resolveHost caller (run, hosts check/rm,
@@ -364,7 +364,7 @@ agents accounts list --fleet`,
364
364
  const addCmd = accounts.command('add <target> [name]')
365
365
  .description('Add an account. Harness form: add <harness> [name] runs the native login in a fresh credential slot and provisions workers. Provider form: add <name> --provider <p> --auth <t> stores a durable credential.')
366
366
  .option('--api-key <key>', 'Worker credential for api-key harnesses (codex/grok/cursor/opencode); prompted when omitted')
367
- .option('--per-device', 'codex: ChatGPT-plan account — no API key stored; workers log in per box')
367
+ .option('--per-device', 'codex/grok: subscription seat (ChatGPT plan, SuperGrok, X Premium+) — no API key stored; workers log in per box')
368
368
  .option('--no-worker-token', 'Skip minting/collecting the worker credential (this device only)')
369
369
  .option('--provider <provider>', `Provider form: credential provider (${listAccountProviders().join(', ')})`)
370
370
  .option('--auth <type>', 'Provider form: api-key | setup-token | bearer-token')
@@ -428,12 +428,13 @@ agents accounts add codex gmail --per-device # ChatGPT-plan seat; workers
428
428
  agents accounts add claude # name derived from the login's email
429
429
  agents accounts add work --provider anthropic --auth setup-token # provider form (non-harness name)
430
430
  agents run claude#work`,
431
- notes: `Headed devices only: on a worker, add refuses before any slot, install, or browser — workers are provisioned automatically from the durable credential the add mints (claude: a setup-token; codex/grok/cursor/opencode: an API key via --api-key or a prompt; codex also accepts --per-device for a ChatGPT-plan seat; kimi/antigravity log in per box). An account is a credential SLOT, not a second installation: the harness has one managed install and each account is a HOME-shaped slot with its own native OAuth login (never copied, never fleet-synced). Re-running add for an already-added identity points at 'agents accounts login <harness>#<name>'. Supported: ${addSupportedList()}; other harnesses fail with the reason. An ambient CLAUDE_CODE_OAUTH_TOKEN in your shell refuses the mint (unset it or pass --no-worker-token).`,
431
+ notes: `Headed devices only: on a worker, add refuses before any slot, install, or browser — workers are provisioned automatically from the durable credential the add mints (claude: a setup-token; codex/grok/cursor/opencode: an API key via --api-key or a prompt; codex and grok also accept --per-device for a subscription seat; kimi/antigravity log in per box). An account is a credential SLOT, not a second installation: the harness has one managed install and each account is a HOME-shaped slot with its own native OAuth login (never copied, never fleet-synced). Re-running add for an already-added identity points at 'agents accounts login <harness>#<name>'. Supported: ${addSupportedList()}; other harnesses fail with the reason. An ambient CLAUDE_CODE_OAUTH_TOKEN in your shell refuses the mint (unset it or pass --no-worker-token).`,
432
432
  });
433
433
  const loginCmd = accounts.command('login <account>')
434
434
  .description('Re-authenticate an account into its slot on this device (<harness>#<name>); re-mints and re-syncs the worker credential')
435
435
  .option('--api-key <key>', 'Rotate the stored worker API key (api-key harnesses)')
436
436
  .option('--no-worker-token', 'Skip re-minting the worker credential')
437
+ .option('--per-device', 'codex/grok: sign this box in to the subscription seat via the device-code flow (allowed on workers)')
437
438
  .option('--json', 'Machine-readable result (never includes a credential)')
438
439
  .action(async (selector, o, command) => {
439
440
  await runAccountsAction(command, async () => {
@@ -448,6 +449,7 @@ agents run claude#work`,
448
449
  console.log(chalk.gray(` ${m}`)); },
449
450
  apiKey: o.apiKey,
450
451
  noWorkerToken: o.workerToken === false,
452
+ perDevice: o.perDevice,
451
453
  });
452
454
  printAddResult(result, json);
453
455
  });
@@ -455,8 +457,9 @@ agents run claude#work`,
455
457
  setHelpSections(loginCmd, {
456
458
  examples: `agents accounts login claude#work
457
459
  agents accounts login codex#personal --api-key sk-… # rotate the worker key
458
- agents accounts login kimi#main # per-device: logs THIS box in`,
459
- notes: 'Re-runs the native login into the SAME slot (never a new home) and fails closed when the completed login is a different identity than the account. Headed devices only for harnesses with a portable worker credential; a per-device harness (kimi) may log in on any box — that is how that box gets its login. The daemon re-syncs the account row and worker credential after a successful login.',
460
+ agents accounts login kimi#main # per-device: logs THIS box in
461
+ agents ssh <worker> agents accounts login grok#work --per-device # the worker signs in to the subscription seat`,
462
+ notes: 'Re-runs the native login into the SAME slot (never a new home) and fails closed when the completed login is a different identity than the account. Headed devices only for harnesses with a portable worker credential; a per-device harness (kimi) may log in on any box — that is how that box gets its login. With --per-device a codex or grok account signs THIS box in to its subscription seat through the device-code flow: the box prints a URL and code, you approve it in your own browser, and no API key is stored or synced. The daemon re-syncs the account row and worker credential after a successful login.',
460
463
  });
461
464
  const defaultCmd = accounts.command('default <harness> [name]')
462
465
  .description('Set the fleet-wide default account for a harness (picker when no name)')
@@ -1,82 +1,64 @@
1
- import { Command } from 'commander';
2
- import { type BrowserProfile } from '../lib/browser/profiles.js';
3
- import { listInstalledBrowsers } from '../lib/browser/chrome.js';
4
- import type { DeviceProfile } from '../lib/devices/registry.js';
5
- export declare function remoteStartTaskName(stdout: string, explicit?: string): string | undefined;
6
1
  /**
7
- * Fetch an absolute remote file into a private local path, bounded.
2
+ * `agents browser` — the consumer surface over the standalone `browser` CLI
3
+ * (@phnx-labs/browser-cli, PHNX-4101).
8
4
  *
9
- * Bounded for real, not by a pre-flight `stat`: the byte budget is enforced on the
10
- * stream as it arrives (`sshExecRawStream` + `cat`), so a file that grows between
11
- * a size check and the copy — or a peer that lies about the size — still cannot
12
- * spend more than the budget. `scp` could not do this; it would transfer
13
- * everything before this process got a chance to refuse.
5
+ * WHAT THIS FILE IS NOW. Every verb below forwards its arguments verbatim to the
6
+ * standalone engine and propagates its exit code. agents-cli contributes what the
7
+ * engine cannot know, carried on the fd-3 context (`lib/browser/context.ts`):
14
8
  *
15
- * The local file is written 0600 inside a 0700 directory, because a capture can
16
- * show anything that was on the peer's screen and a world-readable temp path
17
- * would publish it to every local user.
18
- */
19
- /**
20
- * The command that streams one file's RAW BYTES to stdout on the device's shell.
9
+ * 1. `--device <name>` resolved against the fleet — the device registry, ssh
10
+ * identity and platform — so the engine drives the right remote box without
11
+ * a fleet registry of its own (it matches the alias against `context.target`,
12
+ * then `~/.ssh/config`);
13
+ * 2. whether THIS machine consents to being driven by a peer
14
+ * (`browser.remote-control`); the engine enforces the resolved flag;
15
+ * 3. the acting actor and agent session, so an action lands in the right
16
+ * session history.
21
17
  *
22
- * Platform-correct, not one command with a portable-looking name. On Windows
23
- * `cat` is an alias for `Get-Content`, which is a TEXT reader: it decodes the
24
- * file, splits it into lines, and re-encodes on output — so a screenshot arrives
25
- * corrupted rather than merely reordered. The .NET path opens a `FileStream` and
26
- * copies it into the raw stdout handle, bypassing PowerShell's object/text
27
- * pipeline entirely, which is the only way binary survives.
28
- */
29
- export declare function remoteReadFileArgv(remotePath: string, shell: DeviceProfile['shell']): string[];
30
- /**
31
- * Largest capture `browser show --device` will pull. A capture is a screenshot,
32
- * a PDF or a short recording; anything past this is not something a viewer should
33
- * stream over ssh, and the cap is what makes the transfer BOUNDED rather than
34
- * "however big the peer's file happens to be".
18
+ * The engine streams back the actions it performed on fd 4, and agents-cli — which
19
+ * owns `sessions.db` — records each into the durable `browser_sessions` row that
20
+ * `agents browser sessions` and `agents sessions --browser` read
21
+ * (`lib/browser/record.ts`).
22
+ *
23
+ * THE REMOTE PATH IS THE ENGINE's. `--device <name>` is resolved to an ssh target
24
+ * here and forwarded verbatim (the engine binds the device once at `start` and
25
+ * runs page verbs against the task's bound device). agents-cli opens no tunnel and
26
+ * publishes no endpoint: the engine owns the CDP/BiDi/Arc drivers, the IPC service,
27
+ * the chrome-data store and the profile declarations, keeping every on-disk path
28
+ * the in-repo subsystem used (integration contract §4).
29
+ *
30
+ * WHY VERB FLAGS ARE NOT REDECLARED HERE. Each passthrough verb takes everything
31
+ * as opaque operands via `allowUnknownOption`. Mirroring the engine's flags would
32
+ * create a second, silently drifting copy of its surface: a flag added upstream
33
+ * would be rejected here as unknown until someone noticed. The engine also owns
34
+ * per-verb `--help` for the same reason. What agents-cli keeps is the verb CATALOG
35
+ * — names, one-line descriptions, help groups — because that is what makes the
36
+ * surface discoverable from `agents browser --help`.
37
+ *
38
+ * `sessions` is the one verb that never reaches the engine: it reads agents-cli's
39
+ * own capture/session history (`browser-sessions-picker.ts`).
35
40
  */
36
- export declare const REMOTE_VIEW_MAX_BYTES: number;
41
+ import { Command } from 'commander';
37
42
  /**
38
- * Fetch an absolute remote file into a private local path, bounded.
43
+ * The verb catalog. Descriptions are the consumer's (they appear in
44
+ * `agents browser --help`); flags are the engine's.
39
45
  *
40
- * Auth is the CANONICAL device path, not a hand-rolled ssh: `buildSshInvocation`
41
- * supplies the askpass shim for a password-auth box, `-i`/`IdentitiesOnly` for an
42
- * explicit identity file, and the managed known-hosts pinning. Building the ssh
43
- * args here instead meant a password-auth device could not be reached at all and
44
- * an explicit `identityFile` was silently ignored.
46
+ * This list is the contract with the engine: a verb the engine drops should fail
47
+ * loud here rather than silently vanish, and `browser.test.ts` pins the names so a
48
+ * drift shows up as a failing test. `sessions` is deliberately NOT in the list —
49
+ * it is agents-cli's own reader, registered separately.
45
50
  *
46
- * Bounded for real, not by a pre-flight `stat`: the byte budget is enforced on the
47
- * stream as it arrives, so a file that grows between a size check and the copy — or
48
- * a peer that misreports its size — still cannot spend more than the budget.
49
- *
50
- * The local file is written 0600 inside a 0700 directory, because a capture can
51
- * show anything that was on the peer's screen and a world-readable temp path
52
- * would publish it to every local user.
51
+ * `start` is the ONE verb that resolves `--device`; the engine binds the device
52
+ * there and rejects `--device` on the page verbs itself.
53
53
  */
54
- export declare function fetchRemoteFileForViewing(device: string, remotePath: string, localPath: string, opts?: {
55
- maxBytes?: number;
56
- timeoutMs?: number;
57
- }): Promise<void>;
54
+ export declare const BROWSER_PASSTHROUGH_VERBS: ReadonlyArray<{
55
+ name: string;
56
+ description: string;
57
+ }>;
58
58
  /**
59
- * The fleet browser hub this box drives by default (`browser.device`), or
60
- * undefined to drive locally. It is one fleet-synced value in the central
61
- * agents.yaml, so every box reads the same hub name — but the hub itself resolves
62
- * to a self-host, and a fleet-dispatched invocation is already ON its target, so
63
- * both return undefined. That self short-circuit is what lets a single synced
64
- * value be safe: only the boxes that are NOT the hub forward to it, and the hub
65
- * never forwards to itself.
59
+ * Peek `--device <name>` (or `--device=name`) out of a raw argv without consuming
60
+ * it — the flag is forwarded to the engine verbatim, and agents-cli only reads it
61
+ * to resolve the fleet target for the fd-3 context. Pure, so it is unit-testable.
66
62
  */
67
- export declare function defaultBrowserHub(): string | undefined;
63
+ export declare function peekDevice(argv: string[]): string | undefined;
68
64
  export declare function registerBrowserCommand(program: Command): void;
69
- export declare function registerBrowserSubcommands(program: Command): void;
70
- interface BrowserUseOptions {
71
- unset?: boolean;
72
- }
73
- interface BrowserUseChoice {
74
- name: string;
75
- value: {
76
- name: string;
77
- installed?: ReturnType<typeof listInstalledBrowsers>[number];
78
- };
79
- }
80
- export declare function buildBrowserUseChoices(profiles: BrowserProfile[], installed: ReturnType<typeof listInstalledBrowsers>, current?: string): BrowserUseChoice[];
81
- export declare function runBrowserUse(name: string | undefined, opts: BrowserUseOptions, interactive?: boolean): Promise<boolean>;
82
- export {};