@phnx-labs/agents-cli 1.22.117 → 1.22.118

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 (248) hide show
  1. package/CHANGELOG.md +235 -0
  2. package/dist/bootstrap.js +4 -11
  3. package/dist/commands/browser.d.ts +52 -70
  4. package/dist/commands/browser.js +192 -3562
  5. package/dist/commands/daemon.d.ts +39 -2
  6. package/dist/commands/daemon.js +72 -73
  7. package/dist/commands/events.js +1 -1
  8. package/dist/commands/exec.js +53 -1
  9. package/dist/commands/repo.js +13 -49
  10. package/dist/commands/route.js +5 -5
  11. package/dist/commands/routines.js +39 -12
  12. package/dist/commands/sessions-render.d.ts +1 -1
  13. package/dist/commands/sessions-render.js +0 -1
  14. package/dist/commands/sessions.test-fixture.d.ts +0 -1
  15. package/dist/commands/sessions.test-fixture.js +0 -37
  16. package/dist/commands/setup-browser.d.ts +17 -12
  17. package/dist/commands/setup-browser.js +52 -87
  18. package/dist/commands/setup-preferences.d.ts +0 -17
  19. package/dist/commands/setup-preferences.js +18 -49
  20. package/dist/commands/setup.js +9 -9
  21. package/dist/commands/ssh.js +10 -1
  22. package/dist/commands/sync.js +6 -44
  23. package/dist/commands/teams.js +0 -1
  24. package/dist/commands/update.d.ts +19 -0
  25. package/dist/commands/update.js +34 -6
  26. package/dist/commands/view.d.ts +12 -1
  27. package/dist/commands/view.js +47 -2
  28. package/dist/index.js +107 -26
  29. package/dist/lib/account-capabilities.js +0 -2
  30. package/dist/lib/account-catalog.d.ts +38 -0
  31. package/dist/lib/account-catalog.js +110 -26
  32. package/dist/lib/account-provider-registry.js +1 -1
  33. package/dist/lib/account-registry.d.ts +1 -1
  34. package/dist/lib/account-registry.js +36 -2
  35. package/dist/lib/accounting/rotate.js +22 -8
  36. package/dist/lib/accounting/usage-ingest.d.ts +6 -1
  37. package/dist/lib/accounting/usage-ingest.js +115 -45
  38. package/dist/lib/accounting/usage-sync.d.ts +134 -31
  39. package/dist/lib/accounting/usage-sync.js +227 -66
  40. package/dist/lib/accounting/usage.d.ts +16 -3
  41. package/dist/lib/accounting/usage.js +26 -8
  42. package/dist/lib/accounts/slots.d.ts +8 -0
  43. package/dist/lib/accounts/slots.js +17 -0
  44. package/dist/lib/add-dir.js +0 -1
  45. package/dist/lib/agent-cli-commands.js +0 -1
  46. package/dist/lib/agent-spec/agents.d.ts +6 -7
  47. package/dist/lib/agent-spec/agents.js +6 -60
  48. package/dist/lib/auth-health.d.ts +69 -1
  49. package/dist/lib/auth-health.js +133 -4
  50. package/dist/lib/browser/context.d.ts +82 -0
  51. package/dist/lib/browser/context.js +88 -0
  52. package/dist/lib/browser/paths.d.ts +25 -0
  53. package/dist/lib/browser/paths.js +51 -0
  54. package/dist/lib/browser/record.d.ts +38 -0
  55. package/dist/lib/browser/record.js +57 -0
  56. package/dist/lib/browser/sessions-list.js +1 -2
  57. package/dist/lib/browser-client.d.ts +158 -0
  58. package/dist/lib/browser-client.js +234 -0
  59. package/dist/lib/channels/owner-sink.d.ts +1 -18
  60. package/dist/lib/channels/owner-sink.js +29 -82
  61. package/dist/lib/channels/providers/rush.d.ts +7 -7
  62. package/dist/lib/channels/providers/rush.js +127 -57
  63. package/dist/lib/claude-statusline.d.ts +1 -1
  64. package/dist/lib/claude-statusline.js +15 -3
  65. package/dist/lib/commands.js +1 -1
  66. package/dist/lib/crabbox/lease.js +1 -1
  67. package/dist/lib/crabbox/runtimes.js +1 -3
  68. package/dist/lib/daemon/account-state-daemon-service.js +1 -0
  69. package/dist/lib/daemon/auth-sync-service.d.ts +21 -18
  70. package/dist/lib/daemon/auth-sync-service.js +37 -43
  71. package/dist/lib/daemon/daemon.d.ts +25 -14
  72. package/dist/lib/daemon/daemon.js +92 -154
  73. package/dist/lib/daemon/runner.d.ts +2 -2
  74. package/dist/lib/daemon/runner.js +32 -9
  75. package/dist/lib/daemon/self-update-service.d.ts +35 -34
  76. package/dist/lib/daemon/self-update-service.js +40 -36
  77. package/dist/lib/daemon/service.d.ts +12 -8
  78. package/dist/lib/daemon/supervisor.d.ts +65 -54
  79. package/dist/lib/daemon/supervisor.js +136 -171
  80. package/dist/lib/daemon/testdata/process-view-start.js +5 -2
  81. package/dist/lib/daemon/usage-sync-service.d.ts +21 -30
  82. package/dist/lib/daemon/usage-sync-service.js +46 -78
  83. package/dist/lib/daemon-health.d.ts +22 -5
  84. package/dist/lib/daemon-health.js +47 -3
  85. package/dist/lib/daemon-services.d.ts +1 -1
  86. package/dist/lib/daemon-services.js +0 -10
  87. package/dist/lib/daemon-ticks.js +4 -2
  88. package/dist/lib/devices/doctor-findings.js +8 -11
  89. package/dist/lib/devices/harness-inventory.js +14 -5
  90. package/dist/lib/exec-account-home.js +5 -0
  91. package/dist/lib/exec.js +0 -11
  92. package/dist/lib/feed/events.js +0 -1
  93. package/dist/lib/feed/tool-activity.js +5 -2
  94. package/dist/lib/fleet-shared-state.d.ts +45 -0
  95. package/dist/lib/fleet-shared-state.js +78 -9
  96. package/dist/lib/fs-atomic.js +25 -0
  97. package/dist/lib/harness-auth-capabilities.js +0 -1
  98. package/dist/lib/helper-versions.js +1 -1
  99. package/dist/lib/hooks/cache.d.ts +7 -0
  100. package/dist/lib/hooks/cache.js +27 -2
  101. package/dist/lib/hooks/install.js +7 -1
  102. package/dist/lib/hosts/ready.d.ts +38 -8
  103. package/dist/lib/hosts/ready.js +62 -14
  104. package/dist/lib/installations/active-check.d.ts +27 -0
  105. package/dist/lib/installations/active-check.js +61 -0
  106. package/dist/lib/installations/migrate.js +6 -3
  107. package/dist/lib/installations/shims.js +9 -7
  108. package/dist/lib/installations/update.js +21 -15
  109. package/dist/lib/installations/versions.js +12 -1
  110. package/dist/lib/manifest.js +1 -1
  111. package/dist/lib/models.js +0 -2
  112. package/dist/lib/open-url.js +28 -54
  113. package/dist/lib/profiles.js +0 -2
  114. package/dist/lib/refresh.js +1 -1
  115. package/dist/lib/routine-readiness.d.ts +35 -0
  116. package/dist/lib/routine-readiness.js +74 -16
  117. package/dist/lib/rules/compile.js +6 -0
  118. package/dist/lib/sandbox.js +0 -2
  119. package/dist/lib/secrets-policy.d.ts +89 -11
  120. package/dist/lib/secrets-policy.js +175 -28
  121. package/dist/lib/session/db.d.ts +1 -1
  122. package/dist/lib/session/db.js +65 -18
  123. package/dist/lib/session/discover.js +1 -283
  124. package/dist/lib/session/mirror.d.ts +4 -3
  125. package/dist/lib/session/mirror.js +4 -3
  126. package/dist/lib/session/parse.d.ts +0 -2
  127. package/dist/lib/session/parse.js +1 -138
  128. package/dist/lib/session/throughput.d.ts +1 -3
  129. package/dist/lib/session/throughput.js +0 -20
  130. package/dist/lib/session/types.d.ts +2 -2
  131. package/dist/lib/session/types.js +2 -2
  132. package/dist/lib/sessions-client.d.ts +60 -1
  133. package/dist/lib/sessions-client.js +227 -4
  134. package/dist/lib/setup-tool-status.js +5 -10
  135. package/dist/lib/signin-badge.d.ts +3 -2
  136. package/dist/lib/signin-badge.js +6 -3
  137. package/dist/lib/smart-launch.js +4 -1
  138. package/dist/lib/staleness/detectors/commands.d.ts +1 -1
  139. package/dist/lib/staleness/detectors/hooks.d.ts +1 -1
  140. package/dist/lib/staleness/detectors/mcp.d.ts +1 -1
  141. package/dist/lib/staleness/detectors/permissions.d.ts +1 -1
  142. package/dist/lib/staleness/detectors/plugins.d.ts +1 -1
  143. package/dist/lib/staleness/detectors/rules.d.ts +1 -1
  144. package/dist/lib/staleness/detectors/skills.d.ts +1 -1
  145. package/dist/lib/staleness/detectors/subagents.d.ts +1 -1
  146. package/dist/lib/staleness/detectors/workflows.d.ts +1 -1
  147. package/dist/lib/staleness/writers/commands.d.ts +1 -1
  148. package/dist/lib/staleness/writers/hooks.d.ts +1 -1
  149. package/dist/lib/staleness/writers/mcp.d.ts +1 -1
  150. package/dist/lib/staleness/writers/permissions.d.ts +1 -1
  151. package/dist/lib/staleness/writers/plugins.d.ts +1 -1
  152. package/dist/lib/staleness/writers/rules.d.ts +1 -1
  153. package/dist/lib/staleness/writers/skills.d.ts +1 -1
  154. package/dist/lib/staleness/writers/sources.js +5 -0
  155. package/dist/lib/staleness/writers/subagents.d.ts +1 -1
  156. package/dist/lib/staleness/writers/workflows.d.ts +1 -1
  157. package/dist/lib/state.d.ts +6 -4
  158. package/dist/lib/state.js +7 -17
  159. package/dist/lib/teams/parsers.d.ts +1 -1
  160. package/dist/lib/teams/parsers.js +1 -136
  161. package/dist/lib/teams/placement-probe.js +50 -15
  162. package/dist/lib/teams/scheduler.d.ts +7 -0
  163. package/dist/lib/types.d.ts +10 -1
  164. package/dist/lib/types.js +1 -1
  165. package/dist/lib/view-types.d.ts +32 -0
  166. package/dist/lib/watchdog/read.js +0 -1
  167. package/dist/lib/watchdog/rotate.js +1 -2
  168. package/dist/lib/watchdog/runner.js +2 -2
  169. package/dist/lib/watchdog/watchdog.d.ts +1 -1
  170. package/dist/lib/watchdog/watchdogTail.js +0 -31
  171. package/package.json +1 -1
  172. package/scripts/postinstall.js +8 -8
  173. package/dist/browser.d.ts +0 -2
  174. package/dist/browser.js +0 -17
  175. package/dist/commands/browser-picker.d.ts +0 -18
  176. package/dist/commands/browser-picker.js +0 -97
  177. package/dist/lib/browser/arc-discovery.d.ts +0 -52
  178. package/dist/lib/browser/arc-discovery.js +0 -197
  179. package/dist/lib/browser/arc-dom.d.ts +0 -14
  180. package/dist/lib/browser/arc-dom.js +0 -121
  181. package/dist/lib/browser/caller-identity.d.ts +0 -40
  182. package/dist/lib/browser/caller-identity.js +0 -175
  183. package/dist/lib/browser/cdp.d.ts +0 -51
  184. package/dist/lib/browser/cdp.js +0 -254
  185. package/dist/lib/browser/chrome.d.ts +0 -141
  186. package/dist/lib/browser/chrome.js +0 -704
  187. package/dist/lib/browser/chromium-discovery.d.ts +0 -28
  188. package/dist/lib/browser/chromium-discovery.js +0 -96
  189. package/dist/lib/browser/devices.d.ts +0 -34
  190. package/dist/lib/browser/devices.js +0 -61
  191. package/dist/lib/browser/domain-skills.d.ts +0 -71
  192. package/dist/lib/browser/domain-skills.js +0 -195
  193. package/dist/lib/browser/drivers/arc.d.ts +0 -40
  194. package/dist/lib/browser/drivers/arc.js +0 -276
  195. package/dist/lib/browser/drivers/firefox.d.ts +0 -99
  196. package/dist/lib/browser/drivers/firefox.js +0 -377
  197. package/dist/lib/browser/drivers/local.d.ts +0 -55
  198. package/dist/lib/browser/drivers/local.js +0 -266
  199. package/dist/lib/browser/drivers/ssh.d.ts +0 -120
  200. package/dist/lib/browser/drivers/ssh.js +0 -467
  201. package/dist/lib/browser/editor.d.ts +0 -3
  202. package/dist/lib/browser/editor.js +0 -50
  203. package/dist/lib/browser/ffmpeg.d.ts +0 -12
  204. package/dist/lib/browser/ffmpeg.js +0 -184
  205. package/dist/lib/browser/firefox-discovery.d.ts +0 -69
  206. package/dist/lib/browser/firefox-discovery.js +0 -162
  207. package/dist/lib/browser/har.d.ts +0 -85
  208. package/dist/lib/browser/har.js +0 -77
  209. package/dist/lib/browser/hygiene.d.ts +0 -97
  210. package/dist/lib/browser/hygiene.js +0 -153
  211. package/dist/lib/browser/index.d.ts +0 -5
  212. package/dist/lib/browser/index.js +0 -5
  213. package/dist/lib/browser/input.d.ts +0 -7
  214. package/dist/lib/browser/input.js +0 -92
  215. package/dist/lib/browser/ipc.d.ts +0 -204
  216. package/dist/lib/browser/ipc.js +0 -1453
  217. package/dist/lib/browser/login-detection.d.ts +0 -87
  218. package/dist/lib/browser/login-detection.js +0 -274
  219. package/dist/lib/browser/profiles.d.ts +0 -422
  220. package/dist/lib/browser/profiles.js +0 -1157
  221. package/dist/lib/browser/refs.d.ts +0 -89
  222. package/dist/lib/browser/refs.js +0 -191
  223. package/dist/lib/browser/registry.d.ts +0 -70
  224. package/dist/lib/browser/registry.js +0 -252
  225. package/dist/lib/browser/remote-control.d.ts +0 -59
  226. package/dist/lib/browser/remote-control.js +0 -85
  227. package/dist/lib/browser/resolve-target.d.ts +0 -66
  228. package/dist/lib/browser/resolve-target.js +0 -264
  229. package/dist/lib/browser/runtime-state.d.ts +0 -291
  230. package/dist/lib/browser/runtime-state.js +0 -584
  231. package/dist/lib/browser/secret-ref.d.ts +0 -10
  232. package/dist/lib/browser/secret-ref.js +0 -14
  233. package/dist/lib/browser/service.d.ts +0 -812
  234. package/dist/lib/browser/service.js +0 -4693
  235. package/dist/lib/browser/stream.d.ts +0 -17
  236. package/dist/lib/browser/stream.js +0 -72
  237. package/dist/lib/browser/task-index.d.ts +0 -78
  238. package/dist/lib/browser/task-index.js +0 -199
  239. package/dist/lib/browser/types.d.ts +0 -647
  240. package/dist/lib/browser/types.js +0 -61
  241. package/dist/lib/browser/upload.d.ts +0 -29
  242. package/dist/lib/browser/upload.js +0 -298
  243. package/dist/lib/daemon/browser-ipc-service.d.ts +0 -20
  244. package/dist/lib/daemon/browser-ipc-service.js +0 -46
  245. package/dist/lib/daemon/browser-task-reap-service.d.ts +0 -14
  246. package/dist/lib/daemon/browser-task-reap-service.js +0 -26
  247. package/dist/lib/fleet-shared-repo-sync.d.ts +0 -55
  248. package/dist/lib/fleet-shared-repo-sync.js +0 -490
package/CHANGELOG.md CHANGED
@@ -1,5 +1,232 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.22.118
4
+
5
+ - **`agents sessions <read> --device <name>` routes a SINGLE-device READ through the standalone `sessions --host` when both sides support it (PHNX-4012).**
6
+ A read `--device` query (search / list / id lookup, and no explicit `--host`) that names exactly one
7
+ device now resolves it to its SSH target and forwards `sessions <read args> --host ssh://<target>` to
8
+ the local standalone — the local-orchestration collapse where `sessions` owns the remote hop, instead
9
+ of the in-repo peer fan-out. `--host` is point-to-one, so a **multi-device** read (`--device box
10
+ mac-mini`, a repeated `--device`, or a `--device all`/`fleet` sentinel) stays on the in-repo `--device`
11
+ fan-out, which merges the peers. It takes the standalone path only when THIS box's `sessions` is ≥ 0.2.1. If the PEER
12
+ lacks the standalone the remote `bash -lc` command-not-found surfaces as exit 127, on which the read
13
+ falls through to the existing in-repo `--device` fan-out so it still succeeds — a capability gate
14
+ keyed on that specific signal (same spirit as the 0.2.1 `--host` version gate), a migration bridge
15
+ until the fleet is uniformly on 0.2.1. Below the host floor, or with no standalone installed, a
16
+ `--device` read stays on the in-repo engine exactly as before. Lifecycle `--device` (resume / watch /
17
+ inject / focus / …) is untouched, and an explicit `--host` still wins. Internal routing change with no
18
+ user-visible behavior change on a healthy fleet. Source: `cli/src/lib/sessions-client.ts`,
19
+ `cli/src/index.ts`.
20
+
21
+ - **`agents sessions … --host <target>` forwards to the standalone `sessions` CLI (PHNX-4012).**
22
+ A point-to-one remote read (`agents sessions <query> --host box` — SSH to ONE box, run
23
+ `sessions … --local`, stream JSON back) now takes the standalone fast path when the installed
24
+ `sessions` is ≥ 0.2.1, mirroring how the 0.2.0 filter/sort flags are version-gated. A box with
25
+ `sessions` below the 0.2.1 host floor — or none installed — keeps the query on the in-repo engine
26
+ exactly as before (which resolves `--device` against the fleet), so nothing mis-routes or crashes.
27
+ This is an internal routing change: `--host` behaves the same for callers, only the engine that
28
+ answers it changes. Source: `cli/src/lib/sessions-client.ts`, `cli/src/index.ts`.
29
+
30
+ - **`agents browser` is now a thin consumer of the standalone `browser` CLI (PHNX-4101).** The
31
+ duplicate in-repo browser engine — the CDP/BiDi/Arc drivers, the browser IPC service, the
32
+ chrome-data/profile store and the network-capture pipeline — is deleted; every verb forwards
33
+ verbatim to `@phnx-labs/browser-cli` (`browser`), which owns the engine and keeps every on-disk
34
+ path the old subsystem used. agents-cli supplies only what the fleet CLI knows: `--device`
35
+ resolved to an SSH target (bound once at `start`), remote-control consent, the acting session
36
+ identity, and the capture/session history behind `agents browser sessions`. The daemon no longer
37
+ hosts the browser IPC service or the browser-task reaper (browser-cli runs its own), and the
38
+ retired `browser` alias shim no longer shadows the standalone binary on PATH. Install it with
39
+ `npm i -g @phnx-labs/browser-cli` or `agents setup browser`. Source: `cli/src/lib/browser-client.ts`,
40
+ `cli/src/commands/browser.ts`, `cli/src/lib/browser/{context,record,sessions-list,paths}.ts`,
41
+ `cli/src/lib/daemon/daemon.ts`, `cli/docs/browser.md`.
42
+
43
+ - **A PreToolUse hook whose script is missing now denies the tool call instead of allowing it (PHNX-4106).**
44
+ Generated hook shims embed one source path inside a version home; when that file was gone (a
45
+ pruned version, sync rewriting `hooks/`) the shim exited 127, which Claude Code, Codex and Droid
46
+ read as "allow". On one laptop the primary-checkout guard was silently disabled for about 17
47
+ hours this way. A `PreToolUse` shim now exits 2 with the repair named (`agents hooks sync`) and
48
+ logs `cache: missing-source`, after the `matches:` gate and only for a PreToolUse firing; other
49
+ events and skipped fires stay fail-open. `agents prune <harness>@<version>` also re-points the
50
+ shims at the surviving home immediately instead of waiting for the daemon. Source:
51
+ `cli/src/lib/hooks/cache.ts`, `cli/src/lib/installations/versions.ts`.
52
+
53
+ - **Claude no longer gets every plugin skill twice.** Sync flattened each plugin's `skills/` into
54
+ the top-level `skills/` of every harness, but Claude Code already loads them from the plugin
55
+ registration, namespaced (`/sessions:continue`), so the picker listed `/continue` and
56
+ `/sessions:continue` side by side for 47 skills. Claude is flagged `nativePluginSkills`: sync
57
+ stops flattening there, and the leftover copies are swept by the next full `agents sync claude`
58
+ (or `agents prune cleanup skills`). Harnesses that only see plugin skills through the flat copy
59
+ (Codex) are unchanged. Source: `cli/src/lib/staleness/writers/sources.ts`,
60
+ `cli/src/lib/agent-spec/agents.ts`.
61
+
62
+ - **`auth-sync` credential pushes plan per peer off that peer's own first-hand reply, with no fleet-wide freshness gate (PHNX-4116).**
63
+ The daemon's `auth-sync` tick no longer skips **every** credential push when the newest fleet exchange goes
64
+ stale — the old `readLastSuccessfulExchangeMs` marker and its "skipping credential push … need one within
65
+ 900s" WARN are gone. Reserved-key presence on a peer is now `verdict ∧ fingerprint`: the peer's own per-account
66
+ verdict row (`accounts.rows`) must be non-`missing` AND the credential fingerprint (`workerCredential.mintedAt`)
67
+ the publisher last delivered to that peer must match the account's current one. The verdict half is first-hand
68
+ — a key removed on a worker flips its next verdict to `missing` and the push resumes. The fingerprint half
69
+ catches a re-mint: `agents accounts login <harness>#<name>` rotates the reserved key and bumps `mintedAt` while
70
+ the worker's OLD token still authenticates (verdict stays live), so a publisher-side rotation cursor
71
+ (`reserved-sync-delivered.json`, local-only, never synced) re-pushes the new key within one tick instead of
72
+ reading present forever. A peer that has never replied, or whose reply carries no `accounts.rows` field at all
73
+ (an older CLI — fail closed), is skipped this tick and logged at INFO, not WARN. The push stays idempotent, so
74
+ a stale reply is safe. No user-visible surface change; a re-authed account now reaches every worker within a
75
+ tick, and a briefly-quiet exchange no longer stalls provisioning. Source: `cli/src/lib/daemon/auth-sync-service.ts`,
76
+ `cli/src/lib/secrets-policy.ts`.
77
+
78
+ - **Drop stale worker account slots and their credentials (PHNX-4116).** On a
79
+ worker, `reconcileLocalWorkerSlots` now removes any `deviceAccounts.slots`
80
+ record whose account is no longer registered — the leftovers of an older
81
+ account-id generation, each a full HOME carrying a live `.claude/.oauth_token`
82
+ — deleting the 0600 credential while KEEPING the directory (its
83
+ `.claude/projects` holds transcripts) and logging one line per drop. It fails
84
+ closed: an empty or unreadable account registry drops nothing, so a transient
85
+ read can never strip a healthy box's whole slot set. Source:
86
+ `cli/src/lib/secrets-policy.ts`, `cli/src/lib/accounts/slots.ts`.
87
+
88
+ - **A routine skipped by an overlapping run reads `blocked`, not "wedged"
89
+ (PHNX-4116).** Since there is no longer a "wedged" daemon state, a routine
90
+ whose prior run is still active now reports `blocked: run <id> active since
91
+ <t>` — naming the live run and when it started — instead of the stale "wedged:
92
+ a prior run is still active". Source: `cli/src/commands/routines.ts`.
93
+
94
+ - **`agents daemon status` no longer calls a worker's absent secrets broker
95
+ `down` (PHNX-4116).** On a box that reads file-backed secret stores (every
96
+ headless worker), an unreachable broker is expected — secrets read one-shot
97
+ with no broker — so the health line now reads `info secrets agent not running
98
+ (file-backed stores)` instead of `down secrets broker (unreachable)`. A
99
+ keychain-backed box with no broker is still a real fault and still reads
100
+ `down`. Source: `cli/src/commands/daemon.ts`.
101
+
102
+ - **A balanced pick or the account picker now launches the account it chose (PHNX-4116).**
103
+ Since accounts became registered slots (PHNX-3940), a `balanced` pick and the "no fresh usage"
104
+ picker only set the executable version, so the run started in that version's home with whatever
105
+ login it held. On yosemite-m0 the picker chose `trp` and Claude Code opened as another account,
106
+ in its first-run wizard. Both paths now resolve the picked candidate through the same local
107
+ launch resolver an explicit `--account` uses, so the spawn gets the slot's home and durable
108
+ credential env. Source: `cli/src/commands/exec.ts`.
109
+
110
+ - **One run-readiness gate, computed on the box that runs (PHNX-4116).** `agents view --json`
111
+ now carries a per-agent `runReady` (`{ ready, reason, accounts: [{ name, ready, reason }] }`)
112
+ computed from the router's own enumeration — native account slots AND version homes
113
+ (`collectRunCandidates` → `readinessFromCandidate`), not the per-version list, which missed the
114
+ slots a run actually picks from. `--device auto` reads that answer instead of re-deriving usage
115
+ freshness on the dispatching box, so a worker holding a valid setup-token is schedulable on that
116
+ fact: a synced-only usage row (its poller lives on the headed box that published it) is never
117
+ refused for being old — its age weights the pick, it never decides eligibility — and a
118
+ rate-limit window whose reset has already passed reads as available. A placement error now names
119
+ the box's own reason, e.g. `no ready harness account (all signed_out)`, instead of a bare
120
+ `no ready harness account`. `agents devices harnesses` now derives its displayed usage
121
+ percentage from the SAME live windows as the status verdict (`liveUsageWindows`), so a
122
+ maxed-then-reset account no longer reads `available` next to a stale ~100%. The one-release
123
+ fallback for an older remote CLI without `runReady` keeps the pre-fix throttle exclusion — a
124
+ FRESH `rate_limited`/`out_of_credits` or a FRESH dead auth verdict still disqualifies a
125
+ launchable version, while a STALE reading stays unverified — so a throttled worker cannot slip
126
+ into `--device auto` during a rolling upgrade. Source: `cli/src/commands/view.ts`,
127
+ `cli/src/lib/hosts/ready.ts`, `cli/src/lib/accounting/rotate.ts`,
128
+ `cli/src/lib/accounting/usage.ts`, `cli/src/lib/devices/harness-inventory.ts`,
129
+ `cli/src/lib/smart-launch.ts`.
130
+
131
+ - **A wedged daemon service now restarts the whole daemon instead of parking a dead service or reading `wedged` forever (PHNX-4116).**
132
+ A supervised daemon service that HANGS past its deadline (a stuck usage refresh, a frozen heartbeat)
133
+ no longer parks and waits for an in-process backoff restart that could stall for days — the
134
+ supervisor records the cause and exits the process (code 70), and systemd (`Restart=always`,
135
+ `RestartSec=30`, `StartLimitIntervalSec=0`, `KillMode=process`) / launchd (`KeepAlive` +
136
+ `ThrottleInterval=30`) restart the daemon within ~30s, so it recovers on its own like any
137
+ well-behaved service. A service whose tick merely THROWS is recorded and keeps ticking. The
138
+ `parked` service state and the `wedged` daemon state are gone: `agents daemon status` now reports
139
+ `running`/`stopped`, the daemon's PID, uptime, heartbeat age, and the count of supervised restarts
140
+ in the last 24h with the last cause. Source: `cli/src/lib/daemon/supervisor.ts`,
141
+ `cli/src/lib/daemon/daemon.ts`.
142
+
143
+ - **Usage rows and daemon state travel over SSH; the shared user repo carries no daemon state (PHNX-4116).**
144
+ The 15-minute `usage-sync` tick used to commit every device's `devices/<device>/daemon-state.json`
145
+ into the fleet-synced user repo and exchange it under a lock and a 45 s deadline. That grew the
146
+ shared store to 1.1 GiB and 18,358 commits (100% of the last 2,000 were `chore(devices): publish
147
+ <device> daemon state`), one worker's clone fell 10,398 commits behind with `git fetch timed out`
148
+ on every tick, and a box holding a valid setup-token could not be scheduled because a repo was
149
+ bloated. A headed (`personal`/`desktop`) daemon now dials every dialable peer in parallel with
150
+ `agents __usage-ingest --reply` (20 s per peer; a timed-out peer is skipped for that tick), sending
151
+ its own envelope on stdin; the peer merges the usage rows into its cache newest-wins, stores the
152
+ envelope as that peer's file, and prints its own state back, which the headed box stores stamped
153
+ `receivedAt`. Workers never initiate. The placement probe ingests the dispatcher's usage rows on the
154
+ same round-trip, so the chosen worker holds current numbers at dispatch. `agents repo sync user` is
155
+ a plain fetch-and-fast-forward of human-authored resources again; the 8-minute kickoff offset that
156
+ only existed to dodge the repo lock is gone. `__usage-ingest` gains `--reply`; the legacy v1 payload
157
+ from an older headed peer is still accepted. Source: `cli/src/lib/accounting/usage-sync.ts`,
158
+ `cli/src/lib/accounting/usage-ingest.ts`, `cli/src/lib/daemon/usage-sync-service.ts`.
159
+
160
+ - **`agents update claude#work` works, and a refused update names the process holding the installation (PHNX-4116).**
161
+ The `<agent>#<account>` selector `agents run` already takes was rejected by `update` as
162
+ "Unknown agent 'claude#work'"; it now resolves to the managed installation that account runs on
163
+ and refuses only an account the registry does not know. "Account home is in use; retry after its
164
+ sessions finish" is replaced by the actual holder, e.g. `pid 2173999, up 01:10:22, pts/1:
165
+ …/claude --resume 3ef30267…`, with `agents sessions stop <id>` as the way out. Source:
166
+ `cli/src/commands/update.ts`, `cli/src/lib/installations/active-check.ts`.
167
+
168
+ - **`agents view` / `agents accounts list` show FACTS per account per box, never a
169
+ word that means "we did not look" (PHNX-4116).** Each account row now states its
170
+ evidence: the **token** on disk (`sk-ant-oat01 (Sep 16)` = the slot's
171
+ `.claude/.oauth_token` scheme prefix + file date, `api key (present)`, or
172
+ `no token`), what happened when it was last **used** (`last used ok 12m ago` /
173
+ `last auth failure 401 Sep 20 14:02` / `rate-limited until 15:00` / `not used on
174
+ this box yet`), and a **usage** reading that names its origin when it came from
175
+ another box (`S 12% W 40% … (from zion)`). The auth fact is recorded from real run
176
+ outcomes into the auth-health cache with a new `source: 'run'` field — an auth
177
+ failure at the routine runner's `isAuthFailureFromLog` sites, a success at
178
+ statusline ingest and a clean headless `agents run` exit. `agents view <harness>
179
+ --json` accounts now carry `token` and `lastAuth` for the emitting box. Source:
180
+ `cli/src/lib/auth-health.ts`, `cli/src/lib/account-catalog.ts`,
181
+ `cli/src/commands/accounts.ts`, `cli/src/commands/view.ts`.
182
+
183
+ - **A synced usage file no longer masquerades as a live auth verdict, and a worker
184
+ no longer publishes a `unverified` probe row (PHNX-4116).** `verdictFromFreshUsage`
185
+ refuses a `freshness.source === 'sync'` snapshot — a fresh reading from another
186
+ box's poller proves the shared token works somewhere, not that THIS box can
187
+ authenticate. A worker's setup-token box, which cannot read the usage endpoint,
188
+ now returns the honest `no_evidence` verdict (dropped from the published probe
189
+ rows) instead of the overloaded `unverified`, so eight identical workers read one
190
+ distinct picture instead of five. Source: `cli/src/lib/auth-health.ts`.
191
+
192
+ - **A `--host <worker>` routine activates on a token-backed worker again
193
+ (PHNX-4116).** Dropping the worker's `no_evidence` probe row left `agents devices
194
+ ping --local --json` with no row for the agent, so host-placed routine readiness
195
+ read the absent row as `unconfigured` and reported `agent_auth_failed` with a
196
+ valid token on disk. `devices ping --local --json` now also emits `launchable`
197
+ (the agents this box holds a launchable signed-in credential for, from the same
198
+ `collectRunCandidates` the run router uses), and one shared decision
199
+ (`decideRoutineAuthReadiness`) is used by both the local and host readiness paths:
200
+ an absent row plus a launchable credential is ready, a box with no credential
201
+ fails, and a fresh `revoked` blocks — so both paths reach the same answer for the
202
+ same box. Source: `cli/src/lib/routine-readiness.ts`, `cli/src/commands/ssh.ts`.
203
+
204
+ - **`--device auto` no longer refuses a worker whose usage reading is merely old (PHNX-4116).**
205
+ Remote readiness re-derived a 40-minute usage-freshness refusal from `agents view --json`'s
206
+ per-version list, so one broken usage-sync made every worker read `no ready harness account`
207
+ while `--device <name>` on the same box launched fine. The dispatcher now READS the running box's
208
+ own `runReady` verdict instead of re-deriving it (see the readiness fragment); usage age weights
209
+ the pick, it never decides eligibility. Source: `cli/src/lib/hosts/ready.ts`.
210
+
211
+ - **The daemon no longer freezes for minutes on session-index and mirror writes (PHNX-4154).**
212
+ `session_text` FTS rows now sit at the rowid of the `sessions` row they describe and are
213
+ addressed by it (schema v51, a one-time rebuild: 24 s for a 669 MB index). Every delete and
214
+ content read used to filter on the UNINDEXED `session_id`, a full scan of the FTS content per
215
+ statement; the fleet session mirror runs one per mirrored row inside a daemon tick, so the
216
+ daemon's event loop stalled for 10+ minutes per tick, every service logged `tick exceeded
217
+ deadline`, and `agents browser` verbs on the same loop timed out with
218
+ `Arc Apple Event timed out`. Source: `cli/src/lib/session/db.ts`.
219
+
220
+ - **Fix `ENOTDIR` crash on stale lock files.** `withFileLock` and `withFileLockAsync`
221
+ now self-heal when a prior crash left a regular file instead of the directory
222
+ `proper-lockfile` expects, matching the caller's `realpath` option when computing
223
+ the lock path. Source: `cli/src/lib/fs-atomic.ts`.
224
+
225
+ - **Fix `Unknown account` for unregistered native logins.** `ag run claude#email`
226
+ now discovers a native OAuth login from version-home `.claude.json` files when the
227
+ account is not yet in `accounts.native`, and correctly routes it through the
228
+ provider-backed harness guard. Source: `cli/src/lib/account-registry.ts`.
229
+
3
230
  ## 1.22.117
4
231
 
5
232
  - **`agents run --local`, and `--device <this machine>` no longer SSHes to itself.** A bare
@@ -11,6 +238,14 @@
11
238
  MagicDNS name, loopback, or the `interactive` sentinel now resolves to the same local
12
239
  run. The placement-failure hint names `--local`. Source: `cli/src/commands/exec.ts`
13
240
  (`pinLocalWhenTargetIsSelf`), `cli/src/lib/placement.ts`, `cli/src/lib/hosts/remote-cmd.ts`.
241
+ - **`agents sessions` filter/sort queries take the standalone fast path when it's new enough.**
242
+ `--project`/`-p`, `--since`, `--until`, `--sort`, and the harness shorthands
243
+ (`--claude`/`--codex`/…) now route to the standalone `sessions` binary when the installed one is
244
+ ≥ 0.2.0 (which implements them), and stay on the in-process engine otherwise — a version probe
245
+ (`sessions --version`, cached, run only when such a flag is present) gates it, so an older binary
246
+ never gets a flag it would mis-read as an FTS token. `--json`/`--limit`/`--agent` and a bare
247
+ query/id already route unconditionally, unchanged. Behavior is unchanged; the fast path just
248
+ covers more queries. Source: `cli/src/lib/sessions-client.ts`, `cli/src/index.ts`.
14
249
 
15
250
  ## 1.22.116
16
251
 
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,
@@ -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 {};