@phnx-labs/agents-cli 1.22.50 → 1.22.52

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 (85) hide show
  1. package/CHANGELOG.md +219 -0
  2. package/dist/bootstrap.js +1 -1
  3. package/dist/commands/attach.js +7 -0
  4. package/dist/commands/browser.d.ts +10 -0
  5. package/dist/commands/browser.js +191 -54
  6. package/dist/commands/config.js +20 -0
  7. package/dist/commands/daemon.d.ts +2 -0
  8. package/dist/commands/daemon.js +8 -4
  9. package/dist/commands/detach.js +1 -1
  10. package/dist/commands/feedback.js +1 -1
  11. package/dist/commands/focus.d.ts +1 -10
  12. package/dist/commands/focus.js +14 -79
  13. package/dist/commands/go.d.ts +26 -0
  14. package/dist/commands/go.js +63 -5
  15. package/dist/commands/menubar.js +6 -4
  16. package/dist/commands/monitors.js +1 -1
  17. package/dist/commands/repo.js +31 -3
  18. package/dist/commands/sessions-resume.d.ts +1 -0
  19. package/dist/commands/sessions-resume.js +13 -2
  20. package/dist/commands/sessions-stop.js +1 -1
  21. package/dist/commands/sessions.d.ts +23 -13
  22. package/dist/commands/sessions.js +40 -20
  23. package/dist/commands/setup-browser.d.ts +5 -2
  24. package/dist/commands/setup-browser.js +14 -29
  25. package/dist/commands/setup-preferences.d.ts +22 -3
  26. package/dist/commands/setup-preferences.js +25 -8
  27. package/dist/commands/share.js +12 -8
  28. package/dist/commands/status.js +5 -0
  29. package/dist/commands/sync.js +58 -2
  30. package/dist/commands/tmux.d.ts +8 -1
  31. package/dist/commands/tmux.js +167 -17
  32. package/dist/commands/traces.js +32 -4
  33. package/dist/lib/browser/ipc.d.ts +44 -0
  34. package/dist/lib/browser/ipc.js +120 -8
  35. package/dist/lib/browser/profiles.d.ts +39 -17
  36. package/dist/lib/browser/profiles.js +51 -52
  37. package/dist/lib/browser/runtime-state.d.ts +4 -2
  38. package/dist/lib/browser/runtime-state.js +4 -2
  39. package/dist/lib/browser/service.js +4 -3
  40. package/dist/lib/channels/owner-forward.d.ts +88 -0
  41. package/dist/lib/channels/owner-forward.js +116 -0
  42. package/dist/lib/channels/owner-sink.js +7 -0
  43. package/dist/lib/claude-statusline.d.ts +9 -0
  44. package/dist/lib/claude-statusline.js +45 -4
  45. package/dist/lib/computer/ssh-tunnel.d.ts +7 -6
  46. package/dist/lib/computer/ssh-tunnel.js +13 -8
  47. package/dist/lib/config-keys.d.ts +4 -3
  48. package/dist/lib/config-keys.js +9 -2
  49. package/dist/lib/device-config.js +23 -0
  50. package/dist/lib/exec.d.ts +8 -0
  51. package/dist/lib/exec.js +7 -0
  52. package/dist/lib/factory/snapshot.d.ts +1 -1
  53. package/dist/lib/factory/snapshot.js +1 -1
  54. package/dist/lib/feed-broadcast.js +15 -1
  55. package/dist/lib/git.d.ts +93 -0
  56. package/dist/lib/git.js +232 -0
  57. package/dist/lib/helper-download.d.ts +12 -2
  58. package/dist/lib/helper-download.js +12 -2
  59. package/dist/lib/installations/migrate.js +4 -4
  60. package/dist/lib/menubar/install-menubar.d.ts +71 -8
  61. package/dist/lib/menubar/install-menubar.js +183 -24
  62. package/dist/lib/monitors/remote.d.ts +18 -1
  63. package/dist/lib/monitors/remote.js +15 -2
  64. package/dist/lib/notify.d.ts +7 -0
  65. package/dist/lib/notify.js +15 -1
  66. package/dist/lib/session/local-tmux-attach.d.ts +69 -0
  67. package/dist/lib/session/local-tmux-attach.js +164 -0
  68. package/dist/lib/session/remote-active.d.ts +8 -0
  69. package/dist/lib/session/remote-active.js +1 -0
  70. package/dist/lib/share/publish.d.ts +8 -11
  71. package/dist/lib/share/publish.js +16 -20
  72. package/dist/lib/share/worker-template.js +99 -12
  73. package/dist/lib/star-nudge.d.ts +2 -2
  74. package/dist/lib/star-nudge.js +2 -2
  75. package/dist/lib/state.d.ts +1 -1
  76. package/dist/lib/state.js +2 -2
  77. package/dist/lib/sync-status.d.ts +17 -0
  78. package/dist/lib/sync-status.js +21 -2
  79. package/dist/lib/tmux/index.d.ts +1 -1
  80. package/dist/lib/tmux/index.js +1 -1
  81. package/dist/lib/tmux/session.d.ts +10 -0
  82. package/dist/lib/tmux/session.js +29 -0
  83. package/dist/lib/traces/sync.d.ts +30 -0
  84. package/dist/lib/traces/sync.js +91 -10
  85. package/package.json +3 -3
package/CHANGELOG.md CHANGED
@@ -1,5 +1,224 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.22.52
4
+
5
+ - **`agents artifacts share --visibility me|org` — identity-gated share pages (PHNX-3260).**
6
+ Extends the P1 `public|unlisted` tiers (RUSH-3135) with two Phoenix-gated GET
7
+ visibilities. `me` is visible only to the signed-in owner (the viewer's Phoenix
8
+ `userId` must equal the stamped `owner`); `org` is visible to any signed-in
9
+ Phoenix user whose **verified email domain** matches the owner's company domain
10
+ (`org_domain`, stamped from the owner's verified email on PUT). A mismatch on
11
+ either returns **404** — the same body as a missing object — so a wrong viewer
12
+ cannot even learn the page exists. Both are hidden from the public gallery and
13
+ `share list`, like `unlisted`. Publishing `org` from a public inbox
14
+ (gmail/googlemail/outlook/hotmail/live/icloud/me) is refused with **400**, and
15
+ `me`/`org` PUT without a Phoenix identity is a loud 400 (a BYO `WRITE_TOKEN`
16
+ alone cannot publish them). Browser GET of an unauthenticated `me`/`org` URL
17
+ **302**s to `${PHOENIX_ID_BASE}/login?return=<url>` (the same Google OAuth as
18
+ `/device`, no new IdP); the returned one-time `phoenix_ticket` is redeemed once
19
+ via `POST /api/v1/auth/ticket` and exchanged for an HttpOnly, HMAC-signed
20
+ `__Host-phoenix_share` cookie on the share host. An existing CLI
21
+ `Authorization: Bearer` still works with no redirect. `me`/`org` responses send
22
+ `Cache-Control: private, no-store` and `X-Robots-Tag: noindex`;
23
+ `public`/`unlisted` GET is unchanged (anonymous 200). Because the Worker template
24
+ changed, **already-provisioned BYO endpoints need `agents artifacts share update`**
25
+ to serve the new gate. Source: `cli/src/lib/share/worker-template.ts`,
26
+ `cli/src/lib/share/{backend,publish}.ts`, `cli/src/commands/share.ts`.
27
+
28
+ - **Harden the browser daemon against the socket-timeout wedge (PHNX-3289).** Four
29
+ fixes to the browser/daemon reliability surface. `agents daemon status` no longer
30
+ errors on macOS with `ps: etimes: keyword not found` — the process-uptime probe now
31
+ shells the portable `ps -o etime=` and parses it with the same helper the keychain
32
+ reaper uses. `waitForSocket` raises its ceiling from a flat 6s to 15s and re-probes
33
+ across an IPC-server restart (requiring two stable accepts), so a browser
34
+ start/navigate that lands in a restart window no longer intermittently throws
35
+ `Timeout waiting for browser daemon socket`. New `agents browser stop --daemon` stops
36
+ the browser daemon and clears a stale/wedged `browser.sock`, failing loud if a live
37
+ server still holds it, so the next `start` comes up clean. And `agents browser start
38
+ --device <host>` now resolves the browser/profile on the TARGET device instead of the
39
+ local one — a bare start from a browserless box forwards to `--device` instead of
40
+ failing with a misleading `No supported browser found`. Source:
41
+ `cli/src/commands/daemon.ts`, `cli/src/lib/browser/ipc.ts`, `cli/src/commands/browser.ts`.
42
+
43
+ - **Managed share: a BYO-published page no longer locks the rightful Phoenix owner out of their own handle (PHNX-3291).** The share Worker's handle-ownership check (`assertHandleOwner`) scanned every page under a namespace and 409'd `handle taken` when any page's stamped `owner` differed from the writer's Phoenix `userId`. But a BYO `WRITE_TOKEN` publish stamps `owner = SHARE_NAMESPACE` (the namespace string, e.g. `octocat`), not a userId — so once a namespace held any BYO page, its legitimate Phoenix handle owner got a 409 on every subsequent publish, and could neither publish nor change a page's `--visibility` (which blocked the me/org tiers from PHNX-3260 for that user entirely). The `__handles/<handle>` claim object is now authoritative when it exists: the recorded userId may write and anyone else is refused, regardless of a stray page's owner stamp. The page-owner scan remains as the pre-claim fallback but ignores BYO namespace stamps (`owner === handle`), so a first Phoenix publish can still claim a handle previously used only by BYO pages. Source: `cli/src/lib/share/worker-template.ts`. Requires `agents artifacts share update` on already-provisioned endpoints (the Worker template hash changed).
44
+
45
+ - **`sessions resume`/`sessions attach`/`sessions focus` no longer SSH-probe the fleet before attaching a live local tmux pane (PHNX-3292).** First unique match now wins: a selector naming a live pane on THIS box — the full `ag-<agent>-<8hex>` alias `agents tmux ls` prints, or its bare 8-hex suffix when it names exactly one live local pane — attaches with zero SSH, for bare `sessions resume <alias>` and deprecated `sessions attach <alias>` too, not just `--attach-only`. Previously `collectSessionCandidates` ran first — two fleet sweeps (transcript pool + live roster) that stall on offline devices (~2 minutes measured on yosemite-s0, two copies of `unreachable or no agents CLI — skipped`) — and bare `resume` of a live alias didn't even reach the tmux-attach path at all. A miss still races the reachable fleet in parallel: `isDefinitiveMatch`/`selectorAllowsEarlyExit` (RUSH-2203) now cover a tmux alias and an exact 8-hex short id, not just a full UUID, so the first peer to answer with that pane aborts the rest of the sweep instead of waiting out every offline box's timeout. Two LIVE panes (local or fleet-answered) sharing the same 8-hex suffix fail closed with both names printed, rather than guessing; a dead/retained pane is never attached. `--device` skips the local gate entirely and scopes the race to the named box(es). Source: `cli/src/lib/session/local-tmux-attach.ts` (new, `attachLocalLiveSelector`), `cli/src/commands/{sessions,sessions-resume,attach,focus}.ts`.
46
+
47
+ - **`agents tmux attach` tears the session down when the agent exits (PHNX-3293).**
48
+ Attaching to a wrapped pane and exiting the agent (`/exit`, Ctrl-c) used to
49
+ print `[detached]` and leave the tmux session in `tmux ls` — the v6 pane-died
50
+ hook only `detach-client`s when a client is attached, and the attach verbs
51
+ never killed the `remain-on-exit` husk. `tmux attach`, `sessions focus` /
52
+ `resume --attach-only`, and `go`'s local-tmux attach now destroy the session
53
+ when every pane is dead and still keep it on Ctrl-b d. A piped (no-TTY)
54
+ local `agents run --interactive` no longer wraps in tmux, so session-tracker
55
+ tests cannot leak live "trust this folder" panes. `agents tmux kill` with no
56
+ name opens a picker whose preview is the pane's last screen (so a leaked
57
+ first-run dialog is distinguishable from real work); `tmux ls` prints that
58
+ snippet on each row. Source:
59
+ `cli/src/lib/tmux/session.ts`, `cli/src/commands/tmux.ts`,
60
+ `cli/src/commands/focus.ts`, `cli/src/lib/exec.ts`.
61
+
62
+ - **`agents browser start` no longer silently mints a logged-out `auto-chrome` (PHNX-3296).** With no configured default and no existing launchable profile, start now errors and points at `agents setup` / `agents browser use <name>` / the `browser.device` fleet hub instead of popping a signed-out Chrome. A pre-existing `auto-chrome` or legacy `default` still resolves. `agents setup`'s browser pick replaces the misleading "auto-detect on first use" opt-out with an explicit "None — this box uses the fleet hub" choice. Source: `cli/src/lib/browser/profiles.ts`, `cli/src/commands/setup-preferences.ts`, `cli/src/commands/browser.ts`.
63
+
64
+ - **`sessions detach` / `sessions stop` of a unique live local session no longer wait for fleet SSH timeouts (PHNX-3298).** A live pane already visible locally is the hit: a full UUID or a unique 8-hex prefix skips `gatherRemoteActive` entirely, so a sleeping peer cannot print `unreachable or no agents CLI` or stall SIGTERM. Two local matches fail closed without waiting for unanswered boxes. A genuine miss still races the fleet and aborts remaining SSH on the first unique reachable live row; browse / `focus` with no id stays all-settle. Source: `cli/src/commands/go.ts`, `cli/src/commands/detach.ts`, `cli/src/commands/sessions-stop.ts`.
65
+
66
+ - **`agents monitors add` refuses immediately when a reachable peer already has the same watcher (PHNX-3299).** The fleet duplicate guard used to collect every peer before reporting a clash, so a single slow box forced the full 12-second timeout even when another peer had already answered with the same fingerprint. The fan-out now aborts remaining SSH captures the moment a peer reports a matching monitor, while the no-match path still waits for the whole fleet so uniqueness can be proved. Source: `cli/src/commands/monitors.ts`, `cli/src/lib/monitors/remote.ts`.
67
+
68
+ - **`agents repo sync user` self-heals a non-git or partial `~/.agents` by adopting it in place — no re-clone, no data loss (PHNX-3301).** When the user-layer checkout lost (or never had) its `.git`, sync hard-failed with `Not a git repo: ~/.agents` and the only fix was a destructive re-clone that wiped runtime state (`.cache` / `.history` / `scratch` / device config). It now git-backs the existing directory in place with plumbing only (`init` / `remote` / `fetch` / `update-ref` / `read-tree` / `checkout-index` / `restore`, so it never trips the fleet git-guard): materializes only the MISSING tracked files, restores a stale-stub top-level `agents.yaml` from origin (backing up the previous copy to `.history/agents.yaml.pre-adopt.bak` first), preserves gitignored runtime state, and surfaces (never clobbers) real local edits. The remote URL is resolved from an existing `origin`, `AGENTS_USER_REPO_URL`, or a device-local record left by a prior healthy sync — never hardcoded. `agents sync status` now flags a non-git `~/.agents` as a distinct drift state instead of burying it as "N missing". Source: `cli/src/lib/git.ts`, `cli/src/commands/sync.ts`, `cli/src/commands/repo.ts`, `cli/src/lib/sync-status.ts`, `cli/src/commands/status.ts`.
69
+
70
+ - **Owner notifications forward to a capable fleet peer when this box can't deliver (PHNX-3303).**
71
+ The owner's delivery provider for the rush-backed channels (imessage / telegram /
72
+ slack / discord via the `rush` CLI) is macOS-only, so `agents feed post --level
73
+ important` / `--blocked`, `agents notify`, and monitor `notify` actions run from a
74
+ headless Linux worker used to record the post but fail to reach the owner with
75
+ `owner failed: … rush CLI not found on PATH`. They now hand the delivery over SSH to
76
+ a reachable macOS peer that DOES have the provider — the same reroute
77
+ `agents message` already uses — instead of stranding the important post. It is
78
+ best-effort: it never throws or blocks the post, only the macOS-only rush family
79
+ triggers a forward (a Linux-capable transport like openclaw-telegram stays local),
80
+ and when no capable peer is reachable the existing clean local error stands. A box
81
+ that received a forward never forwards onward (`AGENTS_OWNER_NO_FORWARD` guard).
82
+ Source: `cli/src/lib/channels/owner-forward.ts`, `cli/src/lib/notify.ts`,
83
+ `cli/src/lib/feed-broadcast.ts`.
84
+
85
+ - **`agents artifacts share <file>` now derives a stable slug automatically (PHNX-3310).**
86
+ The default comes from the HTML `<title>` or Markdown frontmatter `title:`, then
87
+ the filename, so repeat publishes of a long-running artifact update the same URL;
88
+ `--slug` remains an optional explicit override. Source:
89
+ `cli/src/lib/share/publish.ts`, `cli/src/commands/share.ts`.
90
+
91
+ - **The release attestation now shards its test suite across the fleet instead of pinning one box.** `release-attestation-produce.sh` — the full-suite run that mints a release's exact-tree attestation — ran the ~13k-test suite on a single auto-picked box at `--maxWorkers=2` (~880s measured, ~14 min per attestation). It now fans the suite across the fleet via `test.sh --shard N` by default, resolving N from the eligible workers `agents devices pick` reports (capped) and falling back to a single box only when fewer than two are eligible. The suite is throughput-bound, so this is ~1/N the wall time (~269s on one box → ~31s on nine). Each shard still runs vitest at `--maxWorkers=2 --retry=2`, so the RUSH-3015 per-box flake mitigation is unchanged — sharding adds machines, not per-box concurrency. New `--test-shard <n>` / `--test-devices a,b,c` overrides mirror `test.sh`. Source: `cli/scripts/release-attestation-produce.sh`.
92
+
93
+ - **Shared pages now show who shared them and — the point — a visibility cue (PHNX-3260 follow-up).** The share Worker injects a slim attribution bar at the top of every served HTML page: `Shared by <handle>`, `Made with <agent>`, the date, and a colour-coded **visibility chip** — 🔒 `Only you` (me), 🏢 `Anyone at <org>` (org), 🌐 `Public`, 🔗 `Unlisted` — so a viewer can tell at a glance who can see the page, the thing the raw served HTML never surfaced. All values come from metadata the Worker already stamps (`visibility`, `owner`/handle, `org_domain`, `agent`, `date`); no new publish-time metadata and no CLI change, so it ships with `agents artifacts share update`. Non-HTML assets (images, JSON, the OG cover) are served byte-for-byte; metadata is HTML-escaped; the rewritten body drops the now-stale R2 etag. Source: `cli/src/lib/share/worker-template.ts`.
94
+
95
+ ## 1.22.51
96
+
97
+ - **`publish-computer-helper-mac.sh` cuts the helper's own tag (PHNX-3228).**
98
+ It published `ComputerHelper.app.zip` to the CLI's `v<version>` release, but since the
99
+ client was repointed at per-helper tags the resolver asks for `computer-mac/v<x.y.z>`
100
+ (`helperTag` in `cli/src/lib/helper-versions.ts`). The asset therefore landed at an
101
+ address nothing requests, and there was **no way to cut a new computer-mac release at
102
+ all** — the last publisher still coupled to the CLI's version line. It now cuts
103
+ `computer-mac/v<x.y.z>`, requires the helper's version explicitly instead of defaulting
104
+ to `cli/package.json` (that default was the coupling), and refuses an existing tag, since
105
+ the upload uses `--clobber` and would otherwise replace a binary an installed CLI already
106
+ pins. Symmetric with `publish-computer-win.sh`. Source:
107
+ `cli/scripts/publish-computer-helper-mac.sh`.
108
+ It also cuts the tag itself now. `gh release create --verify-tag` refuses to invent a
109
+ tag absent from the remote, and nothing else pushed `computer-mac/v<x.y.z>` — `release.sh`
110
+ delegates helper tagging to "where the helper is released", which is this script. So it
111
+ ran green through build + notarize and then failed at the release step, meaning no new
112
+ helper version could be cut. The tag is pushed AFTER a successful build, deliberately:
113
+ pushing first would leave a published, immutable address with nothing behind it whenever
114
+ notarization failed.
115
+ Origin, not the local ref, is what makes a helper release immutable. Adding tag creation
116
+ introduced a wedge: a run that tagged and then failed to push left a local tag, and the
117
+ guard read that as "published" and told the operator to cut the next patch — burning a
118
+ version over a transient network error, and (since the guard precedes the build) making
119
+ that version uncuttable from the checkout without a manual `git tag -d`. A local-only tag
120
+ now resumes the interrupted publish instead.
121
+ Immutability keys on the published RELEASE, not the tag. A tag with no release is an
122
+ interrupted run — whether the push failed or the release creation did — and both now
123
+ resume rather than burning the version. The asset is what an installed CLI downloads, so
124
+ the release is the thing that must never be replaced.
125
+ The published-release check fails CLOSED. A non-zero `gh` is not evidence of absence —
126
+ unauthenticated, offline, and rate-limited all exit non-zero — so reading that as "not
127
+ published" would have carried on into `gh release upload --clobber` over a live binary,
128
+ the exact outcome the guard exists to prevent. Only an explicit not-found means not-found;
129
+ anything else stops the release and prints what `gh` actually said.
130
+
131
+ - **`agents traces sync` retains and reports failed sessions instead of stranding them (PHNX-3267).**
132
+ The sync watermark advanced to the max mtime of *successful* uploads, so a later
133
+ success moved it past an earlier failed session and the next run's
134
+ `file_mtime_ms > watermark` filter skipped that session forever — the "failures are
135
+ retried" comment was false. A live 1.22.49 sync on a real device reported 11,073
136
+ uploaded and 6,050 errors with no way to tell a transcript cleaned off disk from a
137
+ genuine upload failure. Sync now records each failed session's identity and typed,
138
+ redacted evidence in the ledger and unions those retry-worthy ids back into the row
139
+ query regardless of the watermark, so a stranded session is re-attempted until it
140
+ succeeds. Failures are classified `transcript-unavailable` (the file is gone —
141
+ expected history, not re-read, aged out after 14 days), `parse-failed`, or
142
+ `upload-failed` (both retried); `agents traces sync` prints the breakdown
143
+ (`… errors (N transcripts no longer on disk · M parse/upload failures — will retry)`)
144
+ and `agents traces status` lists the outstanding retry set with example detail.
145
+ Source: `cli/src/lib/traces/sync.ts`, `cli/src/commands/traces.ts`.
146
+
147
+ - **Helper binaries no longer download through a repository-rename redirect.**
148
+ `HELPER_RELEASE_REPO` still named `phnx-labs/agents-cli` after the repository was renamed
149
+ to `phnx-labs/agi-cli`. Nothing was broken — GitHub redirects a renamed repo, and both
150
+ slugs returned HTTP 200 — but every signed helper asset (`MenubarHelper.app.zip`,
151
+ `Agents_CLI.app.zip`, `ComputerHelper.app.zip`, `computer-helper-win.exe`) was resolving
152
+ through that redirect, which is one re-created repository away from pointing elsewhere.
153
+ What actually protects the download is the sha256 + `codesign` + designated-requirement +
154
+ Team ID verification in `helper-download.ts`; this removes the reliance on the redirect.
155
+ The `agents.yaml` `$schema` URL, the CHANGELOG link, the star nudge, and the
156
+ `package.json` repository/issues metadata moved with it.
157
+ **The npm package name is deliberately unchanged** — it is still
158
+ `@phnx-labs/agents-cli`, and renaming it would orphan every installed CLI. That
159
+ distinction is now pinned by a test. Source: `cli/src/lib/helper-download.ts`.
160
+ `publish-computer-helper-mac.sh` carried the old slug too, and that one is a **write**
161
+ path: `REPO_SLUG` reaches `gh release view` (the immutability guard), `gh release create`,
162
+ and `gh release upload --clobber`. Publishing signed helper binaries was going through the
163
+ rename redirect. Found by sweeping `scripts/` and `.github/` after the source tree was
164
+ already clean — the source sweep alone would have missed it.
165
+ Three further live paths carried the old slug and were missed by the first sweep:
166
+ `ssh-tunnel.ts:170` `WIN_HELPER_RELEASE_REPO` (a **separately hardcoded** constant — the
167
+ download URL for `computer-helper-win.exe`, the fourth signed asset, which the first
168
+ version of this change claimed to cover and did not); `commands/feedback.ts:14`, which
169
+ opens real GitHub issues; and `factory/snapshot.ts:30`, which polls this repo's PRs.
170
+ `installations/migrate.ts` also wrote the old URL into the `agents.yaml` header it
171
+ generates. Separately, `.github/workflows/tests-windows-host-e2e.yml:54` gated on
172
+ `github.repository == 'phnx-labs/agents-cli'`, which is permanently false after a rename
173
+ — that job had silently stopped running on every push to main and on its daily cron.
174
+ The JSON Schema's own `$id` moved with it — `state.ts` and `migrate.ts` write that URL as
175
+ the `$schema` hint into every user's `agents.yaml`, so a mismatched `$id` would make
176
+ editors reject their own config.
177
+
178
+ - **The menu-bar helper's staleness check compares the HELPER's version, not the CLI's
179
+ (RUSH-3230).** `installAndStartService` stamped `getCliVersion()` as the installed
180
+ helper's version, and `menubarSetupStale()` compared against `getCliVersion()` too. Once
181
+ helpers gained their own version line that was wrong in both directions: every CLI
182
+ release made an unchanged helper look stale and reinstalled it — recopying the bundle
183
+ under the running helper, which `KeepAlive` then restarts (the #2109 storm: a new pid
184
+ every 5-15s, 578 launches in one log) — while a genuinely newer helper at the same CLI
185
+ version never looked stale at all, so it could never install.
186
+ The stamp is now JSON recording what the helper actually IS: `release` with its helper
187
+ version, or `local` with the source path + mtime for a dev build (menubar's build.sh
188
+ hardcodes `CFBundleShortVersionString`, so a local build has no version to compare).
189
+ Staleness compares like with like, treats a kind change (local <-> release) as stale, and
190
+ never downgrades when the installed helper is ahead of the floor. A pre-JSON stamp is
191
+ stale exactly once and is re-stamped in the new format, so the migration cannot loop.
192
+ `agents menubar status` / `doctor` now print three labelled lines — helper installed,
193
+ helper available, CLI version — instead of conflating two axes into one, and the
194
+ permanent false "(mismatch — `agents menubar setup` updates it)" hint is gone.
195
+ Source: `cli/src/lib/menubar/install-menubar.ts`.
196
+
197
+ - **The Windows helper's "asset missing" error names a tag that exists (RUSH-3230).**
198
+ `downloadWinHelperExe` built its error message from `` `v${version}` `` — the CLI's tag
199
+ shape — while the URL it had just tried came from `helperTag('computer-win', version)`.
200
+ So a genuine 404 sent the reader looking for `v1.0.0`, which does not exist, instead of
201
+ `computer-win/v1.0.0`, which does. The mac path was corrected when helpers moved to their
202
+ own tags; the Windows path was left behind. Also drops a `getCliVersion` import that had
203
+ no call site — the last trace of the old CLI-version coupling in that file.
204
+ Source: `cli/src/lib/computer/ssh-tunnel.ts`.
205
+
206
+ - **Claude status-line delegate no longer fork-bombs the machine.** The delegate
207
+ self-reference guard compared the saved command against the exact literal
208
+ `agents __claude-statusline`, so a delegate seeded with the same private
209
+ subcommand under a *different* binary name (e.g. `agents-dev __claude-statusline`
210
+ from a dev install, or an absolute path) was not recognized as us. Every
211
+ status-line render then `spawnSync`ed that command, which read the same delegate
212
+ and spawned another — unbounded recursion. Observed on a real box: ~4,900 live
213
+ `node __claude-statusline` processes accumulated over a 2-day uptime, exhausting
214
+ 96 GB of swap and driving load past 300, so keystrokes lagged. The guard now
215
+ matches the `__claude-statusline` subcommand under any binary name or path
216
+ (`isStatusLineSelfReference`), `installClaudeStatusLine` refuses to persist such
217
+ a command as a delegate (and deletes an already-poisoned delegate on re-install),
218
+ a `AGENTS_CLAUDE_STATUSLINE_DELEGATED` env marker hard-caps delegation at one hop,
219
+ and the delegate `spawnSync` now carries a 5 s timeout. Source:
220
+ `cli/src/lib/claude-statusline.ts`.
221
+
3
222
  ## 1.22.50
4
223
 
5
224
  ### Fixed
package/dist/bootstrap.js CHANGED
@@ -322,7 +322,7 @@ async function showWhatsNew(fromVersion, toVersion) {
322
322
  for (const line of relevantChanges) {
323
323
  console.log(line);
324
324
  }
325
- console.log(chalk.gray('\nFull notes: https://github.com/phnx-labs/agents-cli/blob/main/CHANGELOG.md'));
325
+ console.log(chalk.gray('\nFull notes: https://github.com/phnx-labs/agi-cli/blob/main/CHANGELOG.md'));
326
326
  console.log();
327
327
  }
328
328
  }
@@ -3,6 +3,7 @@ import { runOnPeer } from '../lib/session/remote-list.js';
3
3
  import { sessionRecoveryPeer } from '../lib/session/recovery.js';
4
4
  import { resolveSessionMetadataValue, resumeSessionInPlace } from './sessions.js';
5
5
  import { readDetachRecord, clearDetachRecord, isHeadlessAlive } from '../lib/session/detached.js';
6
+ import { attachLocalLiveSelector } from '../lib/session/local-tmux-attach.js';
6
7
  export function registerAttachCommand(program) {
7
8
  // Deprecated: superseded by `agents sessions resume`, which detects the state
8
9
  // (live pane / headless / ended) instead of making the caller pick a verb.
@@ -19,6 +20,12 @@ export function registerAttachCommand(program) {
19
20
  });
20
21
  }
21
22
  export async function attachAction(id) {
23
+ // PHNX-3292: this deprecated spelling still gets the local-pane fast path —
24
+ // a live tmux alias/short id on THIS box attaches with zero SSH, matching
25
+ // `sessions resume`. `attach` takes no `--device`, so hosts is always empty.
26
+ if (await attachLocalLiveSelector(id.trim(), [])) {
27
+ return;
28
+ }
22
29
  const outcome = await resolveSessionMetadataValue(id);
23
30
  if (outcome.kind === 'partial') {
24
31
  // RUSH-2492: an unreachable peer is a warning, not a hard failure. The
@@ -1,6 +1,16 @@
1
1
  import { Command } from 'commander';
2
2
  import { type BrowserProfile } from '../lib/browser/profiles.js';
3
3
  import { listInstalledBrowsers } from '../lib/browser/chrome.js';
4
+ /**
5
+ * The fleet browser hub this box drives by default (`browser.device`), or
6
+ * undefined to drive locally. It is one fleet-synced value in the central
7
+ * agents.yaml, so every box reads the same hub name — but the hub itself resolves
8
+ * to a self-host, and a fleet-dispatched invocation is already ON its target, so
9
+ * both return undefined. That self short-circuit is what lets a single synced
10
+ * value be safe: only the boxes that are NOT the hub forward to it, and the hub
11
+ * never forwards to itself.
12
+ */
13
+ export declare function defaultBrowserHub(): string | undefined;
4
14
  export declare function registerBrowserCommand(program: Command): void;
5
15
  export declare function registerBrowserSubcommands(program: Command): void;
6
16
  interface BrowserUseOptions {