@phnx-labs/agents-cli 1.20.78 → 1.20.82
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.
- package/CHANGELOG.md +487 -0
- package/README.md +25 -25
- package/dist/bin/agents +0 -0
- package/dist/commands/activity.d.ts +9 -0
- package/dist/commands/activity.js +153 -24
- package/dist/commands/apply.js +11 -4
- package/dist/commands/cli.js +1 -1
- package/dist/commands/commands.d.ts +1 -1
- package/dist/commands/commands.js +7 -6
- package/dist/commands/defaults.js +3 -11
- package/dist/commands/doctor.d.ts +65 -0
- package/dist/commands/doctor.js +575 -31
- package/dist/commands/events.js +1 -1
- package/dist/commands/exec.js +24 -5
- package/dist/commands/feed.d.ts +4 -0
- package/dist/commands/feed.js +87 -11
- package/dist/commands/harness.js +2 -2
- package/dist/commands/hooks.js +1 -1
- package/dist/commands/import.js +8 -4
- package/dist/commands/logs.js +6 -0
- package/dist/commands/models.js +1 -1
- package/dist/commands/packages.js +6 -6
- package/dist/commands/permissions.js +1 -1
- package/dist/commands/profiles.js +1 -1
- package/dist/commands/pull.d.ts +1 -1
- package/dist/commands/pull.js +4 -4
- package/dist/commands/repo.d.ts +78 -0
- package/dist/commands/repo.js +187 -11
- package/dist/commands/routines.js +12 -2
- package/dist/commands/rules.js +13 -12
- package/dist/commands/secrets.d.ts +3 -1
- package/dist/commands/secrets.js +100 -32
- package/dist/commands/sessions-inject.d.ts +7 -4
- package/dist/commands/sessions-inject.js +18 -18
- package/dist/commands/sessions-picker.js +32 -3
- package/dist/commands/sessions-resume.d.ts +16 -0
- package/dist/commands/sessions-resume.js +14 -13
- package/dist/commands/sessions.d.ts +31 -0
- package/dist/commands/sessions.js +141 -16
- package/dist/commands/set.d.ts +15 -0
- package/dist/commands/set.js +79 -0
- package/dist/commands/setup-fleet.d.ts +21 -0
- package/dist/commands/setup-fleet.js +201 -0
- package/dist/commands/setup-secrets.d.ts +20 -0
- package/dist/commands/setup-secrets.js +223 -0
- package/dist/commands/setup.js +17 -3
- package/dist/commands/skills.js +1 -1
- package/dist/commands/sync.js +7 -2
- package/dist/commands/teams-picker.js +0 -1
- package/dist/commands/teams.d.ts +33 -1
- package/dist/commands/teams.js +208 -44
- package/dist/commands/versions.js +10 -5
- package/dist/commands/view.d.ts +1 -0
- package/dist/commands/view.js +11 -0
- package/dist/index.js +5 -8
- package/dist/lib/acp/harnesses.js +0 -7
- package/dist/lib/activity.d.ts +156 -0
- package/dist/lib/activity.js +282 -0
- package/dist/lib/agents.d.ts +9 -2
- package/dist/lib/agents.js +72 -63
- package/dist/lib/browser/service.js +3 -0
- package/dist/lib/browser/types.d.ts +7 -0
- package/dist/lib/capabilities.js +6 -2
- package/dist/lib/crabbox/lease.js +2 -2
- package/dist/lib/crabbox/setup-copy.d.ts +4 -4
- package/dist/lib/crabbox/setup-copy.js +4 -4
- package/dist/lib/daemon.d.ts +18 -0
- package/dist/lib/daemon.js +47 -6
- package/dist/lib/devices/fleet.d.ts +1 -1
- package/dist/lib/devices/fleet.js +1 -1
- package/dist/lib/doctor-diff.d.ts +20 -0
- package/dist/lib/doctor-diff.js +6 -1
- package/dist/lib/drift.d.ts +31 -11
- package/dist/lib/drift.js +58 -7
- package/dist/lib/events.d.ts +8 -1
- package/dist/lib/events.js +10 -1
- package/dist/lib/exec.js +35 -8
- package/dist/lib/feed-post.d.ts +28 -1
- package/dist/lib/feed-post.js +110 -2
- package/dist/lib/fleet/apply.js +8 -1
- package/dist/lib/fleet/auth-sync.d.ts +18 -1
- package/dist/lib/fleet/auth-sync.js +25 -11
- package/dist/lib/fleet/remote-login.js +5 -0
- package/dist/lib/git.d.ts +14 -14
- package/dist/lib/git.js +41 -44
- package/dist/lib/hooks.d.ts +42 -0
- package/dist/lib/hooks.js +137 -93
- package/dist/lib/hosts/dispatch.d.ts +28 -1
- package/dist/lib/hosts/dispatch.js +33 -5
- package/dist/lib/hosts/option.js +2 -2
- package/dist/lib/hosts/passthrough.d.ts +22 -1
- package/dist/lib/hosts/passthrough.js +238 -13
- package/dist/lib/hosts/run-target.d.ts +2 -0
- package/dist/lib/hosts/run-target.js +1 -0
- package/dist/lib/hq/floor.d.ts +1 -1
- package/dist/lib/hq/floor.js +6 -1
- package/dist/lib/mcp.js +3 -71
- package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
- package/dist/lib/menubar/notify-desktop.d.ts +15 -0
- package/dist/lib/menubar/notify-desktop.js +41 -5
- package/dist/lib/merged-resources.d.ts +11 -0
- package/dist/{commands/resources.js → lib/merged-resources.js} +11 -19
- package/dist/lib/permissions.d.ts +0 -32
- package/dist/lib/permissions.js +4 -157
- package/dist/lib/picker.js +1 -1
- package/dist/lib/platform/process.d.ts +16 -5
- package/dist/lib/platform/process.js +54 -0
- package/dist/lib/plugins.d.ts +0 -8
- package/dist/lib/plugins.js +4 -110
- package/dist/lib/project-resources.js +4 -1
- package/dist/lib/refresh.d.ts +5 -3
- package/dist/lib/refresh.js +7 -5
- package/dist/lib/resources/commands.js +4 -1
- package/dist/lib/resources/mcp.js +0 -4
- package/dist/lib/resources/permissions.d.ts +1 -1
- package/dist/lib/resources/permissions.js +1 -5
- package/dist/lib/resources/rules.js +4 -1
- package/dist/lib/resources/skills.js +4 -1
- package/dist/lib/resources/subagents.js +4 -0
- package/dist/lib/resources/types.d.ts +1 -1
- package/dist/lib/routines.d.ts +20 -0
- package/dist/lib/routines.js +6 -0
- package/dist/lib/run-defaults.d.ts +1 -0
- package/dist/lib/run-defaults.js +9 -0
- package/dist/lib/runner.d.ts +0 -12
- package/dist/lib/runner.js +49 -10
- package/dist/lib/secrets/Agents CLI.app/Contents/CodeResources +0 -0
- package/dist/lib/secrets/Agents CLI.app/Contents/MacOS/Agents CLI +0 -0
- package/dist/lib/secrets/agent.d.ts +16 -0
- package/dist/lib/secrets/agent.js +105 -3
- package/dist/lib/secrets/audit.d.ts +46 -0
- package/dist/lib/secrets/audit.js +56 -0
- package/dist/lib/secrets/bundles.d.ts +11 -8
- package/dist/lib/secrets/bundles.js +31 -23
- package/dist/lib/secrets/index.d.ts +2 -1
- package/dist/lib/secrets/index.js +8 -2
- package/dist/lib/secrets/remote.d.ts +75 -2
- package/dist/lib/secrets/remote.js +139 -5
- package/dist/lib/secrets/sync.js +3 -3
- package/dist/lib/session/active.d.ts +110 -26
- package/dist/lib/session/active.js +161 -50
- package/dist/lib/session/actor-sidecar.d.ts +23 -0
- package/dist/lib/session/actor-sidecar.js +101 -0
- package/dist/lib/session/db.d.ts +4 -1
- package/dist/lib/session/db.js +65 -8
- package/dist/lib/session/discover.d.ts +4 -0
- package/dist/lib/session/discover.js +13 -0
- package/dist/lib/session/hook-sessions.d.ts +9 -0
- package/dist/lib/session/hook-sessions.js +57 -8
- package/dist/lib/session/pid-registry.d.ts +13 -0
- package/dist/lib/session/render.d.ts +2 -0
- package/dist/lib/session/render.js +1 -1
- package/dist/lib/session/types.d.ts +16 -0
- package/dist/lib/staleness/detectors/commands.js +2 -2
- package/dist/lib/staleness/detectors/permissions.js +1 -45
- package/dist/lib/staleness/writers/commands.js +4 -5
- package/dist/lib/staleness/writers/hooks.js +1 -1
- package/dist/lib/startup/command-registry.d.ts +1 -2
- package/dist/lib/startup/command-registry.js +2 -4
- package/dist/lib/subagents-registry.js +5 -12
- package/dist/lib/subagents.d.ts +0 -10
- package/dist/lib/subagents.js +0 -12
- package/dist/lib/teams/agents.d.ts +0 -2
- package/dist/lib/teams/agents.js +10 -27
- package/dist/lib/teams/index.d.ts +1 -1
- package/dist/lib/teams/index.js +1 -1
- package/dist/lib/types.d.ts +17 -9
- package/dist/lib/usage.d.ts +28 -5
- package/dist/lib/usage.js +271 -8
- package/dist/lib/versions.js +7 -1
- package/dist/lib/watchdog/watchdog.d.ts +1 -1
- package/dist/lib/watchdog/watchdog.js +25 -13
- package/package.json +1 -2
- package/dist/commands/check.d.ts +0 -15
- package/dist/commands/check.js +0 -180
- package/dist/commands/resources.d.ts +0 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,492 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.20.82
|
|
4
|
+
|
|
5
|
+
- **Codex hook sync no longer leaves startup warnings after upgrades.** The Codex
|
|
6
|
+
hook registrar now prunes hook commands from sibling Codex version homes before
|
|
7
|
+
writing `hooks.json`, so removed versions such as `0.142.0` cannot leave dead
|
|
8
|
+
PreToolUse/Stop handlers that exit `127`. It also writes `SessionEnd` hook
|
|
9
|
+
timeouts at Codex's 3-second limit instead of emitting `timeout: 5` and making
|
|
10
|
+
Codex warn that it is clamping the value on every startup. Source:
|
|
11
|
+
`apps/cli/src/lib/hooks.ts`.
|
|
12
|
+
|
|
13
|
+
- **`agents secrets export`/`list`/`view` now accept `--device`/`--devices` as
|
|
14
|
+
aliases for `--host`/`--hosts`, and a keychain-backed `export --host` push is
|
|
15
|
+
verified.** `--device mac-mini` used to fail with "unknown option" on the secrets
|
|
16
|
+
commands even though the rest of the fleet vocabulary (`agents activity`,
|
|
17
|
+
`agents run --device`) accepts it; it now resolves identically to `--host`. And a
|
|
18
|
+
default keychain-backend push to a macOS host over headless SSH — the sign host a
|
|
19
|
+
Linux-driven release offloads `apple.com` provisioning to — used to land the bundle
|
|
20
|
+
metadata but no readable secret items (the remote login keychain is locked over
|
|
21
|
+
SSH), then fail every later read with the confusing `Bundle 'X' key 'Y': stored
|
|
22
|
+
item '...' not found`. The push now reads the bundle back the way a headless release
|
|
23
|
+
will and **fails loudly** when the keys didn't persist, naming the locked-login-keychain
|
|
24
|
+
cause and steering to `--remote-backend file` (headless-readable) or unlocking the
|
|
25
|
+
remote keychain. This unblocks headless Linux-driven releases. Source:
|
|
26
|
+
`apps/cli/src/commands/secrets.ts`, `apps/cli/src/lib/secrets/remote.ts`.
|
|
27
|
+
|
|
28
|
+
- **`agents sessions resume` shows session previews immediately and opens one tab
|
|
29
|
+
per session by default (RUSH-2023).** The multi-select picker now starts its
|
|
30
|
+
preview pane open whenever the caller supplies preview content; `tab` still
|
|
31
|
+
toggles it. Batch resume now uses full-width tabs across terminal backends,
|
|
32
|
+
with side-by-side two-per-tab packing available explicitly via `--splits`.
|
|
33
|
+
Source: `apps/cli/src/lib/picker.ts`,
|
|
34
|
+
`apps/cli/src/commands/sessions-resume.ts`.
|
|
35
|
+
|
|
36
|
+
- **`agents sessions --active` now distinguishes dead and abandoned sessions
|
|
37
|
+
(RUSH-2066).** The active-session engine computes lifecycle from PID liveness and
|
|
38
|
+
transcript mtime: a dead process reports `closed`, a transcript stale for
|
|
39
|
+
`ABANDONED_STALE_MS` reports `abandoned`, and a live opaque harness still reports
|
|
40
|
+
`running` as its honest floor. The default list, grouped active tallies, and
|
|
41
|
+
`agents hq floor` render `closed` / `abandoned` distinctly, and Factory maps
|
|
42
|
+
`closed` to done and `abandoned` to failed so dead work no longer appears idle.
|
|
43
|
+
Source:
|
|
44
|
+
`apps/cli/src/lib/session/active.ts`, `apps/cli/src/commands/sessions.ts`,
|
|
45
|
+
`apps/factory/src/core/remoteSessions.ts`.
|
|
46
|
+
|
|
47
|
+
- **`agents view` now surfaces the Cursor account and its usage.** Cursor was
|
|
48
|
+
absent from the account view; it now shows the signed-in account (email/authId
|
|
49
|
+
from `~/.cursor/cli-config.json`, token from `~/.config/cursor/auth.json`) and,
|
|
50
|
+
for request-capped (free/legacy) plans, a monthly request bar (`M`) from
|
|
51
|
+
`cursor.com/api/usage`. Usage-based plans have no request cap, so they render the
|
|
52
|
+
account row without a bar. Source: `apps/cli/src/lib/usage.ts`,
|
|
53
|
+
`apps/cli/src/lib/agents.ts`.
|
|
54
|
+
|
|
55
|
+
- **The routines daemon now anchors its working directory to `$HOME` on startup,
|
|
56
|
+
so a deleted launch directory no longer crashes every scheduled routine.** The
|
|
57
|
+
daemon is long-lived and inherited whatever cwd it was launched from — commonly a
|
|
58
|
+
git worktree under `.agents/worktrees/`. When that directory was later removed
|
|
59
|
+
(`git worktree remove`, `rm -rf`), the daemon kept the deleted inode as its cwd
|
|
60
|
+
(a process cannot chdir out of a deleted directory on its own), and every job it
|
|
61
|
+
spawned inherited the dead cwd — `spawnJobAttempt` and command runs pass no
|
|
62
|
+
explicit `cwd`. Bun then failed `getcwd()` at startup and *every* routine died at
|
|
63
|
+
0 seconds with `ENOENT: Bun could not find a file` (or `The current working
|
|
64
|
+
directory was deleted`) before the agent ran — a fleet-wide routine outage from a
|
|
65
|
+
single removed worktree. `runDaemon` now re-anchors to the home directory once at
|
|
66
|
+
startup (`anchorDaemonCwd`), making the scheduler immune regardless of how it was
|
|
67
|
+
launched. Source: `apps/cli/src/lib/daemon.ts` (`anchorDaemonCwd`, `runDaemon`).
|
|
68
|
+
|
|
69
|
+
- **`agents repo refresh` is deprecated in favor of `agents sync`.** The command is
|
|
70
|
+
now hidden from help and prints a deprecation notice on use, pointing at the
|
|
71
|
+
replacement: `agents sync --local` (reconcile all installed agents, no git) or
|
|
72
|
+
`agents sync <agent>` (one agent). It still runs for now so existing scripts and
|
|
73
|
+
muscle memory don't break — `refresh` was a partial variant of `sync` (it only
|
|
74
|
+
ever materialized the single global-default version, and silently no-op'd for an
|
|
75
|
+
agent with installed versions but no global default), whereas `sync` covers
|
|
76
|
+
every installed version. Internal callers (crabbox bootstrap, the `agents pull`
|
|
77
|
+
redirect, `agents setup` help) now use `agents sync --local`. The underlying
|
|
78
|
+
`refresh()` function stays — it is the reconcile stage behind `agents sync`.
|
|
79
|
+
Source: `apps/cli/src/commands/repo.ts`, `apps/cli/src/lib/crabbox/`.
|
|
80
|
+
|
|
81
|
+
- **`agents view` now shows Grok usage limits.** Grok's network usage endpoints
|
|
82
|
+
404, so usage is parsed from the local `~/.grok/logs/unified.jsonl` log instead —
|
|
83
|
+
the latest billing-period config and subscription tier render as a `W` window,
|
|
84
|
+
matching the other agents' live-usage display. Source: `apps/cli/src/lib/usage.ts`.
|
|
85
|
+
|
|
86
|
+
- **`agents run --host` now starts in the same project you launched it from, not the remote `$HOME`.** A host run with neither `--cwd` nor `--remote-cwd` sent no `cd` at all, so the remote agent opened in the home directory with no project context — every launch from a repo (including every Factory "Pick Host" tab) began with a manual `cd`. The dispatch now derives a working directory from the local cwd when the caller named none: a cwd under the local home is re-rooted onto the *remote* home (`~/src/x` → the host's `$HOME/src/x`), which is the normal fleet layout where the same checkout sits at the same home-relative path on every box. Because a derived directory is a best-effort mirror rather than something the user asked for, a host that lacks that checkout falls back to its home instead of failing the run; an explicit `--cwd`/`--remote-cwd` is never mirrored, so a directory you named that does not exist still fails loudly. A cwd outside the local home is not mirrored — a path like `/opt/thing` says nothing about the target's filesystem. Source: `apps/cli/src/lib/hosts/dispatch.ts` (`deriveMirroredCwd`, `remoteCdPrefix`), `apps/cli/src/commands/exec.ts`.
|
|
87
|
+
|
|
88
|
+
- **The Cmd+Shift+O quick-dispatch bar is now Plan / Run, and never runs an agent
|
|
89
|
+
in your home directory.** The two spotlight modes were renamed from File
|
|
90
|
+
Ticket / Fix to **Plan** (investigate → file a Linear ticket) and **Run**
|
|
91
|
+
(headless `agents run`). A new repo dropdown is populated from your recent
|
|
92
|
+
session working directories with `$HOME` dropped, and the pick is passed as
|
|
93
|
+
`--cwd` to both modes, so an agent is always scoped to a real repo instead of
|
|
94
|
+
the too-broad home dir; the last-picked repo is remembered. Run now always uses
|
|
95
|
+
`--strategy balanced` (auto load-balance across signed-in versions with
|
|
96
|
+
headroom, skipping rate-limited), and `--name` is seeded from a slug of your
|
|
97
|
+
task text instead of an opaque `quick-<timestamp>`. Source:
|
|
98
|
+
`apps/cli/menubar/Sources/MenubarHelper/PromptPanel.swift`,
|
|
99
|
+
`apps/cli/menubar/Sources/MenubarHelper/AgentsCLI.swift`.
|
|
100
|
+
|
|
101
|
+
- **The keychain Touch ID prompt now names the session that triggered the read
|
|
102
|
+
(RUSH-1971).** When a bundle read pops Touch ID, the operation prompt already
|
|
103
|
+
named the requesting agent, bundle, and reason; it now also carries the
|
|
104
|
+
triggering session's 8-char short-id — e.g. *"Claude is requesting to unlock the
|
|
105
|
+
'prod' bundle (session e0a1b2c3) for 7 days …"* — so an unexpected prompt is
|
|
106
|
+
attributable when an interactive agent, headless workers, and `secrets exec`
|
|
107
|
+
deploys all run at once. The short-id is derived from the `AGENT_SESSION_ID` the
|
|
108
|
+
exec env already exports; no keychain-helper re-sign is required (the enriched
|
|
109
|
+
string flows through the existing `AGENTS_KEYCHAIN_PROMPT` env). Source:
|
|
110
|
+
`apps/cli/src/lib/secrets/index.ts`, `apps/cli/src/lib/secrets/bundles.ts`.
|
|
111
|
+
|
|
112
|
+
- **`agents teams list` renders from cached team metadata instead of full status
|
|
113
|
+
probes (RUSH-1996).** The list and picker rows now read the team registry plus
|
|
114
|
+
teammate `meta.json` snapshots, so listing teams no longer blocks on remote log
|
|
115
|
+
pulls or unreachable hosts. Full teammate status is still loaded when a user picks
|
|
116
|
+
a team or runs `agents teams status <team>`. Source:
|
|
117
|
+
`apps/cli/src/commands/teams.ts`, `apps/cli/src/commands/teams.test.ts`,
|
|
118
|
+
`apps/cli/docs/teams.md`.
|
|
119
|
+
|
|
120
|
+
- **`agents setup secrets` now guides first-run secrets onboarding (RUSH-1999).**
|
|
121
|
+
The setup command registers a new `secrets` capability wizard that chooses a
|
|
122
|
+
default storage backend (`keychain`, encrypted `file`, or synced `vault`), sets
|
|
123
|
+
the existing default prompt policy (`daily`/`always`, with `never` gated for
|
|
124
|
+
explicit automation use), persists `secrets.backend` so future `agents
|
|
125
|
+
secrets create/import` commands use the selected backend when no backend flag is
|
|
126
|
+
passed, optionally delegates imports to `agents secrets import`, and writes
|
|
127
|
+
setup preferences under `~/.agents/.history/setup`. Source:
|
|
128
|
+
`apps/cli/src/commands/setup-secrets.ts`, `apps/cli/src/commands/secrets.ts`,
|
|
129
|
+
`apps/cli/src/commands/setup.ts`.
|
|
130
|
+
|
|
131
|
+
- **`agents setup fleet` now guides Tailscale device onboarding (RUSH-2000).**
|
|
132
|
+
The setup command registers a new `fleet` capability wizard that verifies
|
|
133
|
+
Tailscale, syncs discovered devices through the existing `agents devices sync`
|
|
134
|
+
path, applies SSH auth with `agents devices set`, optionally writes the
|
|
135
|
+
managed SSH config include, tests connectivity with `agents ssh <device>
|
|
136
|
+
uname`, and can run `agents fleet update` after registration. Source:
|
|
137
|
+
`apps/cli/src/commands/setup-fleet.ts`, `apps/cli/src/commands/setup.ts`.
|
|
138
|
+
|
|
139
|
+
- **`agents feed post` carries artifacts and a project chip, and progress posts
|
|
140
|
+
render rich (RUSH-2013 / RUSH-2014).** `feed post` gains `--attach <path-or-url…>`
|
|
141
|
+
(repeatable): a local file is copied under
|
|
142
|
+
`~/.agents/.history/attachments/<session>/<update>/` so the link survives a
|
|
143
|
+
worktree delete, and a URL is kept as a link — each classified to an
|
|
144
|
+
image/audio/video/file/link kind by extension. Every post is now stamped with its
|
|
145
|
+
project (basename of cwd, worktree-aware) on the activity event itself, so the
|
|
146
|
+
chip shows without a live-session join. A `status.posted` event renders as a
|
|
147
|
+
multi-line update — `agent · session · host · project` chips, the message, an
|
|
148
|
+
attachment row with per-kind glyphs, and a `↳ ag focus/sessions` hint — wherever
|
|
149
|
+
it appears (`feed post` echo, the feed activity lane, `agents feed --filter
|
|
150
|
+
updates`, and `agents activity`).
|
|
151
|
+
- **`agents feed --filter needs|updates|all` (RUSH-2015).** `needs` (default) is the
|
|
152
|
+
open-blocks inbox as before; `updates` shows only deliberate progress posts over
|
|
153
|
+
the local activity timeline (no block pipeline, no remote fan-out); `all` renders
|
|
154
|
+
the blocks then appends the updates view. `--json` under `--filter updates` emits
|
|
155
|
+
the raw `status.posted` events. Source:
|
|
156
|
+
`apps/cli/src/lib/activity.ts`, `apps/cli/src/lib/feed-post.ts`,
|
|
157
|
+
`apps/cli/src/commands/feed.ts`, `apps/cli/src/commands/activity.ts`.
|
|
158
|
+
|
|
159
|
+
- **Fix: actor attribution now actually reaches `agents sessions` and `--active`
|
|
160
|
+
for real runs (RUSH-2018/2019).** Two bugs, found by driving a real `agents run`
|
|
161
|
+
end-to-end: (1) the session index's `actor`/`initiated_by` were kept out of the
|
|
162
|
+
upsert `ON CONFLICT` entirely, so any row indexed *before* its actor sidecar
|
|
163
|
+
landed (an older scanner, or a scan racing the spawn-time write) was locked to
|
|
164
|
+
`NULL` forever — now `COALESCE(existing, incoming)` backfills a null while still
|
|
165
|
+
never clobbering a stored owner; (2) the live `--active` **owner** read only the
|
|
166
|
+
per-pid registry entry, which the SessionStart hook rewrites without an actor, so
|
|
167
|
+
real runs showed no owner — `--active` now falls back to the durable per-session
|
|
168
|
+
actor sidecar. Verified with a real `agents run`: the actor reaches `sessions.db`
|
|
169
|
+
and the `--active` owner resolves. Source: `apps/cli/src/lib/session/db.ts`,
|
|
170
|
+
`apps/cli/src/lib/session/active.ts` (`resolveOwner`).
|
|
171
|
+
|
|
172
|
+
- **Session lists expose the model and richer navigation metadata (RUSH-1981,
|
|
173
|
+
RUSH-1991, RUSH-1992, RUSH-1994).** Static flat rows add a compact model column
|
|
174
|
+
only when the result set has model data, with width sized to that set so an
|
|
175
|
+
80-column terminal does not wrap. Local CWD and ticket/PR cells are clickable
|
|
176
|
+
in supporting terminals, previews identify browser/computer use and sub-agent
|
|
177
|
+
counts, and `agents sessions --active --json` adds an always-present `prLink`
|
|
178
|
+
key. Existing session indexes migrate to schema v20 and rescan transcripts to
|
|
179
|
+
backfill model data.
|
|
180
|
+
|
|
181
|
+
## 1.20.81
|
|
182
|
+
|
|
183
|
+
- **Generic `--device all` / `--host all` fleet fan-out for every fleet-aware
|
|
184
|
+
command (RUSH-1969).** The passthrough now treats `all` as a sentinel value on
|
|
185
|
+
`--host`, `--device`, `--hosts`, and `--devices`. For any routable command
|
|
186
|
+
(`view`, `output`, `sync`, `doctor`, `list`, …) it runs `agents <cmd> --json`
|
|
187
|
+
on every registered device concurrently, then renders an OS-grouped roster
|
|
188
|
+
(`●` installed, `○` offline/skipped, `▸ … ← this machine`). Offline and
|
|
189
|
+
no-address devices render as rows instead of hanging the whole run. Add
|
|
190
|
+
`--json` to get a device-keyed object. Commands that already own `--all-hosts`
|
|
191
|
+
(`output`) keep their existing behavior. Source:
|
|
192
|
+
`apps/cli/src/lib/hosts/passthrough.ts`, `apps/cli/src/lib/hosts/option.ts`.
|
|
193
|
+
|
|
194
|
+
- **`agents apply` no longer propagates single-use rotating refresh tokens
|
|
195
|
+
(RUSH-1958).** Droid (WorkOS) credentials use a refresh token that rotates
|
|
196
|
+
server-side on every exchange; copying one credential file across N boxes
|
|
197
|
+
caused the first refresh on any box to invalidate every other holder, collapsing
|
|
198
|
+
the fleet to a single working login. `agents apply` now excludes droid — and any
|
|
199
|
+
future harness added to the shared `SINGLE_USE_ROTATING_REFRESH_AGENTS` set in
|
|
200
|
+
`src/lib/fleet/auth-sync.ts` — from credential propagation. The plan surfaces
|
|
201
|
+
these as `manual login needed (single-use rotating refresh token)` with the
|
|
202
|
+
device name, routing the user to log in on the target box itself. Source:
|
|
203
|
+
`src/lib/fleet/auth-sync.ts`, `src/lib/fleet/apply.ts`,
|
|
204
|
+
`src/commands/apply.ts`.
|
|
205
|
+
|
|
206
|
+
- **Non-Claude remote/tmux agent sessions now surface with their real id
|
|
207
|
+
(RUSH-2007).** `agents sessions --active` and the `agents sessions focus` picker
|
|
208
|
+
dropped every non-Claude tmux session (codex/gemini/kimi/grok/…) that lacked a
|
|
209
|
+
launch-minted id, so a live `agents run --device <host> <agent>` was invisible and
|
|
210
|
+
un-refocusable after an SSH drop. `listTmuxAgentSessions` now backfills the id from
|
|
211
|
+
the **deployed** SessionStart hook's own per-pid record at
|
|
212
|
+
`~/.agents/.cache/state/sessions/<pid>.json` — the CLI previously only read the
|
|
213
|
+
un-deployed session-tracker path (`terminals/sessions/`, empty on the fleet). A
|
|
214
|
+
targeted per-pid read (never a scan of that graveyard dir), freshness-guarded by
|
|
215
|
+
the launch's known start so a reused-pid record can't cross sessions. Source:
|
|
216
|
+
`apps/cli/src/lib/session/hook-sessions.ts`, `apps/cli/src/lib/session/active.ts`.
|
|
217
|
+
|
|
218
|
+
- **Releases publish the CI-tested tree, not a drifted merge.** On a busy default
|
|
219
|
+
branch, unrelated PRs merging during a release PR's CI window made the
|
|
220
|
+
squash-merge tree diverge from what CI actually tested, so `release.sh` refused
|
|
221
|
+
to publish (`merged tree != built tree`) and the release stalled — every attempt
|
|
222
|
+
merged a version bump it could never tag. The publish now tags the exact release
|
|
223
|
+
commit the full matrix went green on (the PR head), letting the intervening
|
|
224
|
+
commits ride the next release; the merge commit is still tagged when its tree
|
|
225
|
+
matches (no drift). The `wait_for_ci_green` gate is unchanged, so the published
|
|
226
|
+
tarball is always a tree the full matrix validated. The tree-comparison decision
|
|
227
|
+
is extracted into `scripts/select-publish-commit.sh` and unit-tested against a
|
|
228
|
+
real git repo. Source: `apps/cli/scripts/release.sh`,
|
|
229
|
+
`apps/cli/scripts/select-publish-commit.sh`.
|
|
230
|
+
|
|
231
|
+
- **Consolidate the observability + inspection commands into one role each; remove
|
|
232
|
+
`check` and `resources` (RUSH-1234).** Two overlapping command clusters had grown
|
|
233
|
+
ambiguous. `agents check` (the CI drift gate) is folded into `agents doctor --check`
|
|
234
|
+
— same drift engine, now with a scriptable exit code. `--check --quiet`,
|
|
235
|
+
`--check --json` (backward-compatible payload: every field the old `check --json`
|
|
236
|
+
emitted, plus additive `unwiredHookVersions`/`sourceBehind`), and `--check --devices`
|
|
237
|
+
all carry over; the standalone `check` command is removed. `agents resources` (the merged first-wins cross-layer
|
|
238
|
+
resource table) is folded into `agents view --merged`; the standalone `resources`
|
|
239
|
+
command is removed. The observability surfaces (`events`, `feed`, `activity`,
|
|
240
|
+
`output`, `sessions`) now have a documented one-role-each taxonomy — `events` is the
|
|
241
|
+
raw unified audit stream, `feed` the cross-agent decisions/status inbox, `activity`
|
|
242
|
+
the human milestone timeline, `output` productivity accounting, `sessions` the live
|
|
243
|
+
roster + transcripts. Running the removed `agents check` / `agents resources` now
|
|
244
|
+
reports `error: unknown command`. Source:
|
|
245
|
+
`apps/cli/src/commands/doctor.ts`, `apps/cli/src/commands/view.ts`,
|
|
246
|
+
`apps/cli/src/lib/merged-resources.ts`, `apps/cli/src/lib/startup/command-registry.ts`,
|
|
247
|
+
`apps/cli/docs/06-observability.md`.
|
|
248
|
+
|
|
249
|
+
- **`agents sessions --active` shows who launched each run (RUSH-2018).** New
|
|
250
|
+
**owner** column on the active-sessions table (and an `owner` field in
|
|
251
|
+
`--active --json`), sourced from the resolved actor stamped at spawn into the
|
|
252
|
+
per-pid registry and onto each teammate record. Displays the actor's short id
|
|
253
|
+
(an email's local-part) and stays honest — an unresolved local run shows `-`,
|
|
254
|
+
never a guessed box owner. The session index (`sessions.db`) also gains
|
|
255
|
+
write-once `actor` / `initiated_by` columns, kept out of the upsert
|
|
256
|
+
`ON CONFLICT` set so a content rescan never clobbers the original owner.
|
|
257
|
+
Source: `apps/cli/src/lib/session/pid-registry.ts`,
|
|
258
|
+
`apps/cli/src/lib/session/active.ts`, `apps/cli/src/commands/sessions.ts`
|
|
259
|
+
(`ownerLabel`), `apps/cli/src/lib/session/db.ts`, `apps/cli/src/lib/exec.ts`.
|
|
260
|
+
|
|
261
|
+
- **`agents sessions` attributes historical sessions to a person, and teams carry
|
|
262
|
+
spawn lineage (RUSH-2019).** Each run now writes a durable `sessionId -> actor`
|
|
263
|
+
sidecar at spawn (`~/.agents/.history/by-session/`, unlike the pruned pid
|
|
264
|
+
registry), and the session scanner joins it while indexing — so the write-once
|
|
265
|
+
`actor` / `initiated_by` columns added in RUSH-2018 populate automatically and the
|
|
266
|
+
durable `agents sessions` listing (not just `--active`) shows who launched each
|
|
267
|
+
session. Teammate spawns inherit the orchestrator's frozen actor and now record a
|
|
268
|
+
`parent_session_id` (the orchestrator's own `AGENTS_SESSION_ID`), so a team traces
|
|
269
|
+
back to the one human who started it and the spawn chain is walkable. Source:
|
|
270
|
+
`apps/cli/src/lib/session/actor-sidecar.ts`, `apps/cli/src/lib/exec.ts`,
|
|
271
|
+
`apps/cli/src/lib/session/db.ts`, `apps/cli/src/lib/teams/agents.ts`.
|
|
272
|
+
|
|
273
|
+
- **Actor provenance reaches events, routines, and browser tasks (RUSH-2020).**
|
|
274
|
+
Completes the actor layer's coverage beyond sessions: every emitted **event** now
|
|
275
|
+
records `actor` + `kind` through the audit origin (so `agents events` stats carry
|
|
276
|
+
a `byActor` breakdown in `agents logs stats`); a **routine** stamps its creator's
|
|
277
|
+
actor id at creation and seeds it into each fired run's env (`AGENTS_ACTOR`), so an
|
|
278
|
+
unattended cron's session and events attribute to the person who scheduled it
|
|
279
|
+
instead of `UNRESOLVED@<host>` — its run records gain `actor` (creator) and
|
|
280
|
+
`triggeredBy` (who kicked off that run); a **browser task** records the `owner` who
|
|
281
|
+
launched it, on the live task and in history. Source:
|
|
282
|
+
`apps/cli/src/lib/events.ts`, `apps/cli/src/lib/runner.ts`,
|
|
283
|
+
`apps/cli/src/lib/routines.ts`, `apps/cli/src/lib/browser/{types,service}.ts`.
|
|
284
|
+
|
|
285
|
+
- **`agents sessions` now shows an accurate working / waiting / idle status for
|
|
286
|
+
every harness, and shows it as text in the default list — not just a glyph.** Two
|
|
287
|
+
gaps are closed. (1) A live non-Claude/Codex agent (grok, droid, gemini, rush,
|
|
288
|
+
kimi, hermes, opencode, antigravity) used to fall through to a blanket `unknown`
|
|
289
|
+
because `findSessionFileForKind` / `computeLiveSignals` only resolved and parsed
|
|
290
|
+
Claude and Codex transcripts — a running Codex or grok session displayed
|
|
291
|
+
`unknown`. Every tracked harness whose transcript is locatable + parseable is now
|
|
292
|
+
wired into the same state engine: `findSessionFileForKind` resolves each kind's
|
|
293
|
+
transcript through the session index (`latestSessionFileForCwd`), and
|
|
294
|
+
`computeLiveSignals` parses it with that harness's own parser and runs it through
|
|
295
|
+
the same `inferSessionState`, so it gets a real `working` / `waiting_input` /
|
|
296
|
+
`idle` the principled way Claude/Codex do. For a genuinely opaque kind (cursor) or
|
|
297
|
+
an unreadable transcript, `resolveFallbackStatus` now reports `running` for any
|
|
298
|
+
live process — **a running agent never displays `unknown`** (that state is reserved
|
|
299
|
+
for the sole un-answerable case: a dead process whose transcript vanished
|
|
300
|
+
mid-read), and a live process is never downgraded to a fabricated `idle`. (2) The
|
|
301
|
+
default `agents sessions` list (flat, tree, and the project overview) showed only a
|
|
302
|
+
colored glyph for live rows; it now also prints the status **word** —
|
|
303
|
+
`working` / `waiting` / `idle` — next to the glyph, the same three states the
|
|
304
|
+
`--active` column shows, with `waiting` the unmistakable "needs you" case. The
|
|
305
|
+
single-session preview (`agents sessions <id> --preview`) leads with the same live
|
|
306
|
+
status line, flagging `← needs you` when the agent is waiting on a question,
|
|
307
|
+
permission, or plan review. Source: `apps/cli/src/lib/session/active.ts`
|
|
308
|
+
(`findSessionFileForKind`, `computeLiveSignals`, `resolveFallbackStatus`),
|
|
309
|
+
`apps/cli/src/commands/sessions.ts` (`liveStatusWord`, `flatSessionRow`,
|
|
310
|
+
`treeSessionRow`, `renderSessionPreview`).
|
|
311
|
+
|
|
312
|
+
- **`agents sessions inject` now addresses VSCodium / Cursor / VS Code and iTerm sessions, not just tmux.** It resolves targets through the same canonical resolver the watchdog uses (`resolveInjectTargetForSession`), so the manual unblock path and the watchdog agree on which sessions are reachable — and a failed resolve now surfaces the precise reason (host/rail) instead of a misleading "not running under tmux". Source: `apps/cli/src/commands/sessions-inject.ts`.
|
|
313
|
+
- **Watchdog brain focuses on driving idle agents to completion, with context-aware, tool-pointing nudges.** The decider prompt now reads the stalled agent's goal first, restates the conclusion it already reached, names the concrete next step (including a tool it forgot it has — `agents computer` / `agents browser` / `agents ssh <mac> "agents computer …"`), splits do-it-yourself from ask-the-human, and treats `idle` as its territory while leaving `waiting` prompts to the user's feed. Design + normative spec: `apps/cli/docs/watchdog.md`, `apps/cli/docs/specifications.md#watchdog`. Source: `apps/cli/src/lib/watchdog/watchdog.ts`.
|
|
314
|
+
|
|
315
|
+
## 1.20.80
|
|
316
|
+
|
|
317
|
+
- **`agents activity` goes fleet-wide, grouped, and session-enriched.** The activity
|
|
318
|
+
lane was a flat, local-only, newest-first list; it now shows progress-so-far across
|
|
319
|
+
the whole fleet — who did what, where, on which project, for which ticket. New flags:
|
|
320
|
+
`--devices-all` (alias `--hosts-all`) fans the same `activity --json` payload out to
|
|
321
|
+
every reachable device (feed-style, via `gatherRemoteAgentsJson`) and merges each
|
|
322
|
+
peer's stream host-tagged; `-H/--host` / `--device` scope to specific boxes; `--local`
|
|
323
|
+
forces local-only (still the default). `--group-by project|device|agent` buckets the
|
|
324
|
+
stream (e.g. per project, what each agent did and for which ticket) and `--filter
|
|
325
|
+
<text>` narrows by project/device/agent/event/ticket. Each item is enriched by JOINING
|
|
326
|
+
to live sessions — the resolved project (repo/worktree slug from cwd), the execution
|
|
327
|
+
host (`provenance.host`), and the Linear ticket (`ActiveSession.ticket`) — never by
|
|
328
|
+
re-parsing transcripts. Milestone tiering (`--milestones`) and the default collapse are
|
|
329
|
+
unchanged, and `--json` stays a mergeable per-host payload (now carrying the enriched
|
|
330
|
+
fields). Source: `apps/cli/src/commands/activity.ts`, `apps/cli/src/lib/activity.ts`
|
|
331
|
+
(`enrichActivityEvents`, `mergeActivityEvents`, `parseActivityPayload`, `groupActivity`,
|
|
332
|
+
`filterActivityEvents`, `projectFromCwd`).
|
|
333
|
+
|
|
334
|
+
- **Add `agents set` — a short front door for per-version run defaults.** `agents set claude@2.1.220 --model opus-5` pins the default model (and/or `--mode`) that `agents run` uses for that agent version. It reads and writes the same store as `agents defaults run set` (`agents.yaml` -> `run.defaults`), so the two stay consistent. Bare `agents set` lists every default; `agents set <selector>` shows one. Source: `apps/cli/src/commands/set.ts`.
|
|
335
|
+
|
|
336
|
+
- **`agents doctor` now reads as a triaged health report, not neutral status.**
|
|
337
|
+
The verdict was terse status text ("Verdict: 1 divergent, source ~/.agents 16
|
|
338
|
+
commits behind…") a user had to decode. It is now a severity-ranked health block
|
|
339
|
+
that leads with what is unhealthy, why it matters, and the exact fix — one row
|
|
340
|
+
per finding, tagged with a restrained terminal glyph (`✓` `✗` `⚠` and a subtle
|
|
341
|
+
info dot, colored via chalk to match the man-page voice):
|
|
342
|
+
```
|
|
343
|
+
Claude@2.1.220
|
|
344
|
+
✗ unhealthy — 3 issues (1 critical · 2 warnings)
|
|
345
|
+
|
|
346
|
+
✗ critical ask-user-question-guard — on disk but not wired into settings.json; the hook never fires
|
|
347
|
+
→ agents sync claude@2.1.220 --yes
|
|
348
|
+
⚠ warning ~/.agents — 16 commits behind origin/main; you're running stale config
|
|
349
|
+
→ agents repo pull user
|
|
350
|
+
⚠ warning 11-activity-log — differs from source
|
|
351
|
+
→ agents doctor claude@2.1.220 --fix
|
|
352
|
+
|
|
353
|
+
heal what's auto-fixable: agents doctor claude@2.1.220 --fix
|
|
354
|
+
```
|
|
355
|
+
A clean install collapses to one green line —
|
|
356
|
+
`✓ healthy — 34 resources reconciled · hooks wired · sources current`. Each
|
|
357
|
+
finding carries an agent-agnostic **severity**: **critical** (silent breakage —
|
|
358
|
+
an unwired hook, a missing/unparseable `settings.json`, a MISSING resource),
|
|
359
|
+
**warning** (stale/drift — a source layer behind origin, a DIVERGENT resource, a
|
|
360
|
+
stale/never-synced version), or **info** (an orphan/EXTRA resource →
|
|
361
|
+
`agents prune cleanup`). Both surfaces get the same treatment: the target report
|
|
362
|
+
`agents doctor <agent>@<version>` and the bare `agents doctor` overview, which
|
|
363
|
+
now opens with a `Health` banner aggregated across every installed version. The
|
|
364
|
+
existing per-resource detail rows are kept — the health block layers on top of
|
|
365
|
+
them as the verdict. `--json` gains a `verdict` field (target mode) and a
|
|
366
|
+
`health` field (overview), each carrying `severity`/`category`/`subject`/
|
|
367
|
+
`impact`/`fix` per issue; the existing `summary`/`kinds`/`hookWiring`/
|
|
368
|
+
`sourceBehind`/`sync`/`orphans` fields are unchanged. Source:
|
|
369
|
+
`apps/cli/src/commands/doctor.ts` (`computeVerdict`, `computeOverviewHealth`,
|
|
370
|
+
`healthBlockLines`, `renderHealthBlock`, `verdictIsAutoFixable`).
|
|
371
|
+
|
|
372
|
+
- **The daemon's `MenubarHelper --notify` one-shots can no longer pile up in the
|
|
373
|
+
menu bar.** Each routine notification (start/finish/overdue/heal) spawned a
|
|
374
|
+
fresh, detached, unsupervised `MenubarHelper --notify` process; on a stalled
|
|
375
|
+
delivery — a locked screen or a WindowServer/XPC hiccup — the helper's runloop
|
|
376
|
+
spin never reached its deadline and the process hung indefinitely, so duplicate
|
|
377
|
+
"Agents" instances accumulated. The one-shot is now bounded by two independent
|
|
378
|
+
watchdogs: `runOneShot` arms a background-thread force-exit at 3s (off the main
|
|
379
|
+
queue, so a wedged main thread can't starve it — unlike the 0.6s runloop
|
|
380
|
+
deadline it backs up), and the Node spawner (`spawnDetachedQuiet`) SIGKILLs the
|
|
381
|
+
child at 4s if it never self-exits. A notifier that posts normally (the common
|
|
382
|
+
sub-second path) is untouched; only a genuinely hung one is killed. Source:
|
|
383
|
+
`apps/cli/menubar/Sources/MenubarHelper/PromptPanel.swift` (`Notifier.runOneShot`),
|
|
384
|
+
`apps/cli/src/lib/menubar/notify-desktop.ts` (`spawnDetachedQuiet`,
|
|
385
|
+
`NOTIFY_TIMEOUT_MS`).
|
|
386
|
+
|
|
387
|
+
- **Removed the dead `commitOwnDeviceMeta` auto-commit from the pull path.** It
|
|
388
|
+
committed this machine's `devices/<host>/agents.yaml` pin snapshot to the user
|
|
389
|
+
repo's `main` on nearly every `pullRepo`, without pushing — so `main` diverged
|
|
390
|
+
N-ahead per machine and wedged `agents sync` across the fleet. Now that
|
|
391
|
+
per-device pins are gitignored (they are local runtime state — written by
|
|
392
|
+
`writeMetaUnlocked`, read on-disk by pinned-strategy resolution and the shim),
|
|
393
|
+
the function only ever no-ops, so it and its sole `pullRepo` call are deleted
|
|
394
|
+
along with their tests. `--strategy balanced` never read pins; the only behavior
|
|
395
|
+
removed is the never-reached auto-commit. Source: `apps/cli/src/lib/git.ts`
|
|
396
|
+
(`pullRepo`), `apps/cli/src/lib/git.test.ts`.
|
|
397
|
+
|
|
398
|
+
- **Remove Forge and hard-deprecate Gemini (RUSH-2060).** ForgeCode is no longer
|
|
399
|
+
an `AgentId`, install target, resource-sync target, subagent target, MCP target,
|
|
400
|
+
or permissions target. Gemini remains a legacy id so existing sessions/config can
|
|
401
|
+
still be read, but it is no longer a managed harness: `agents add gemini`,
|
|
402
|
+
`agents import gemini`, and `agents sync gemini` now fail and point users to
|
|
403
|
+
Antigravity. Gemini is also excluded from capability-driven resource writers,
|
|
404
|
+
staleness detectors, import choices, teams choices, model choices, fleet auth
|
|
405
|
+
sync, and plugin/MCP/permissions/subagent sync. Source:
|
|
406
|
+
`apps/cli/src/lib/agents.ts`, `apps/cli/src/lib/types.ts`,
|
|
407
|
+
`apps/cli/src/lib/capabilities.ts`, `apps/cli/src/commands/{versions,import,sync}.ts`,
|
|
408
|
+
and the resource writers under `apps/cli/src/lib/`.
|
|
409
|
+
(RUSH-2060)
|
|
410
|
+
|
|
411
|
+
- **Every agent secret access and unlock is now captured in the raw event stream and the audit log.** After the recent relaxation that lets agents read and unlock bundles more freely, `agents events --module secrets` now surfaces two typed, value-free events for the complete access picture. `secrets.get` records every path that resolves a secret VALUE out of a bundle (`run --secrets`, `secrets exec`/`export`, `view --reveal`, raw `get <item>`, `sync push`, remote `bundle@host`), and a new `secrets.unlocked` records the deliberate `agents secrets unlock` grant into the broker/durable session — the longer-lived grant a per-read event does not capture, carrying its TTL and the harness scope it was granted to (`*` = global). Every record is tagged with the resolving `agent` scope and lands at audit level in the append-only `~/.agents/events.jsonl` audit trail, but is non-milestone so it does not clutter `agents activity` / `agents feed`. The resolved value is never written — only bundle name, key NAMES, and counts. All value-read/unlock audits now funnel through one canonical `emitSecretAudit` helper (`apps/cli/src/lib/secrets/audit.ts`), wired into `lib/secrets/bundles.ts`, `commands/secrets.ts` (reveal / raw get / unlock), `lib/secrets/sync.ts`, and `lib/secrets/remote.ts`; the new event type is registered in `lib/events.ts`. Source: `apps/cli/src/lib/secrets/audit.ts`, `apps/cli/src/lib/events.ts`, `apps/cli/src/commands/secrets.ts`.
|
|
412
|
+
|
|
413
|
+
## 1.20.79
|
|
414
|
+
|
|
415
|
+
- **A daemon bounce no longer orphans the secrets broker.** Installing agents-cli ran `stopDaemon()`, which sent SIGTERM, scheduled its hard-kill escalation on a `setTimeout`, and cleared the daemon pid file immediately — without waiting for the process to actually exit. In a short-lived process like the npm postinstall the timer never fired at all, and the cleared pid file made `isDaemonRunning()` report false, so `startDaemon()` launched a second daemon alongside the live one. Its hosted broker then found the socket in use, missed one 700ms ping against the busy owner, unlinked the live socket and rebound — leaving the first broker running with every unlocked bundle in RAM that no client could reach. On a machine with two installs (nvm + homebrew) this reproduced on every upgrade: `lsof` showed two processes on one socket path at two different kernel socket addresses. `stopDaemon` now waits for the process to actually stop serving before clearing the pid file (and escalates to a tree-kill only if it does not), and `bindBrokerSocket` probes an in-use socket several times and refuses to reclaim it while a live process still owns the broker pid file, surfacing a clear error instead of silently starting a second broker. A zombie counts as exited — it holds no socket — so a daemon that is the caller's own child is not hard-killed after it has already gone. The socket owner is recorded in a dedicated `agent.owner` file rather than the standalone service's `agent.pid` single-instance claim, so the signal is present for the daemon-hosted broker (the primary configuration) without making a losing standalone service exit into a launchd restart loop; `ensureAgentRunning`'s one-off fallback and `teardownStaleBroker` also wait for a broker to stop serving before unlinking its socket and ownership record, instead of destroying the evidence the check depends on. Source: `apps/cli/src/lib/platform/process.ts` (`waitForExit`, `hasExited`), `apps/cli/src/lib/daemon.ts` (`stopDaemon`), `apps/cli/src/lib/secrets/agent.ts` (`ownerPath`, `brokerPidAlive`, `releaseBrokerPid`, `bindBrokerSocket`, `ensureAgentRunning`, `teardownStaleBroker`).
|
|
416
|
+
|
|
417
|
+
- **`agents doctor` now checks hook WIRING, not just hook files — and treats a
|
|
418
|
+
stale source layer as unhealthy.** Two blind spots let a version home read
|
|
419
|
+
"healthy" while its hooks were dead. (1) Doctor only compared hook FILES against
|
|
420
|
+
source, never that `settings.json` actually references each hook in the right
|
|
421
|
+
event array — so a hook whose script was byte-identical to source but never
|
|
422
|
+
wired into `PreToolUse`/`Stop`/… reported `ok` and silently never fired
|
|
423
|
+
(reproduced on `yosemite-s1`: `Claude@2.1.207` printed `hooks 32 items 32 ok`
|
|
424
|
+
while its `settings.json` PreToolUse array omitted `ask-user-question-guard.sh`).
|
|
425
|
+
Doctor now inspects the version's native `settings.json` (Claude-family: claude,
|
|
426
|
+
droid), verifying each hook per `(event, matcher)` group, and reports a
|
|
427
|
+
present-but-not-wired hook as `UNWIRED <hook> event=<event> matcher=<matcher>`,
|
|
428
|
+
counted against the verdict; a missing/unparseable `settings.json` is surfaced
|
|
429
|
+
too. `--fix` re-wires via the same `registerHooksToSettings` path `agents sync`
|
|
430
|
+
uses. (2) A source layer behind `origin/main` means the home is reconciled
|
|
431
|
+
against stale truth, yet the "N commits behind" fact was a buried preamble while
|
|
432
|
+
the verdict still said healthy — it now flips the per-version verdict to unhealthy
|
|
433
|
+
with the `agents repo pull` remediation. Both checks run in every mode, not just
|
|
434
|
+
`agents doctor <agent>@<version>`: bare `agents doctor` (overview) and the CI gate
|
|
435
|
+
`agents check` now flag a present-but-unwired hook and a behind-origin source
|
|
436
|
+
layer, and `agents check` exits non-zero on them. Source:
|
|
437
|
+
`apps/cli/src/lib/hooks.ts` (`checkVersionHookWiring`), `apps/cli/src/lib/drift.ts`
|
|
438
|
+
(`checkSyncStatus`/`computeSourceBehind`/`computeDrift`),
|
|
439
|
+
`apps/cli/src/lib/doctor-diff.ts`, `apps/cli/src/commands/doctor.ts`
|
|
440
|
+
(`computeVerdict`), `apps/cli/src/commands/check.ts`, `apps/cli/src/lib/git.ts`
|
|
441
|
+
(`commitsBehindUpstream`).
|
|
442
|
+
|
|
443
|
+
- **`agents repo pull` reconciles a diverged repo instead of wedging on it.** It ran
|
|
444
|
+
`git merge --ff-only`, which refuses *any* divergence — conflict or not — so a
|
|
445
|
+
single local commit permanently blocked every later pull with nothing actually in
|
|
446
|
+
conflict. Since `pullRepo` itself auto-commits the machine's own
|
|
447
|
+
`devices/<host>/agents.yaml` before pulling, every device eventually created that
|
|
448
|
+
commit and stopped receiving updates: on one fleet, nine machines sat 9 commits
|
|
449
|
+
behind and merged rule changes never reached any of them. It now rebases, which is
|
|
450
|
+
what its own documentation has always described. Per-device paths are disjoint, so
|
|
451
|
+
they replay cleanly. A genuine conflict aborts the rebase and rolls the checkout
|
|
452
|
+
back untouched, so a failed pull can never leave the repo detached, mid-rebase, or
|
|
453
|
+
with conflict markers in live config; a rebase already in progress is reported as
|
|
454
|
+
itself rather than as a dirty tree.
|
|
455
|
+
- **`agents repo pull` / `push` exit non-zero when a repo fails.** Both printed a
|
|
456
|
+
failure line and returned 0, so `agents fleet run "agents repo pull user"` reported
|
|
457
|
+
`11 ok` across a fleet that pulled nothing. Any automation gating on the exit code
|
|
458
|
+
read a total no-op as success. Matches `agents sync <repo>`, which already did this.
|
|
459
|
+
|
|
460
|
+
- **`agents repo status` reports across the fleet.** New `--devices-all` (alias
|
|
461
|
+
`--hosts-all`) fans `repo status`/`repo list` out to every reachable device and
|
|
462
|
+
renders one aggregated table (device · repo · sync · changes); `--devices <who>`
|
|
463
|
+
(alias `--hosts`) takes `all` or a comma-separated device list. Unreachable peers
|
|
464
|
+
are skipped with a clear marker, never failing the command, and a single
|
|
465
|
+
`--device`/`--host` still streams that one box as before. Source:
|
|
466
|
+
`apps/cli/src/commands/repo.ts`.
|
|
467
|
+
|
|
468
|
+
- **Routines now always authenticate as the machine they run on, never on an inherited Claude token.** The daemon was already forbidden from *injecting* a Claude OAuth token into a routine, but nothing stopped it *inheriting* one: `buildExecEnv` spreads the ambient `process.env`, and `sanitizeProcessEnv` only strips loader/interpreter variables, never credentials. So on any box whose daemon environment happened to carry `CLAUDE_CODE_OAUTH_TOKEN` — a provisioned fleet machine, a shell that exported it — every routine spawn silently ran on that one shared, rotating token instead of the host's own login. That is the fleet-wide-logout path the no-token design exists to prevent, reached by inheritance rather than injection: when the server rotates a refresh token, every other holder drops to "run /login". No CI runner has a token to inherit, so the existing test passed everywhere and the leak only appeared on a real machine (it surfaced on the release VM, halting a release). `buildRoutineSpawnEnv` now drops the variable, and the routine still authenticates exactly as before — `CLAUDE_CONFIG_DIR` is pinned to that box's per-account version home, so a routine uses whatever agent login is set up there and needs no token of its own. Source: `apps/cli/src/lib/runner.ts` (`buildRoutineSpawnEnv`).
|
|
469
|
+
|
|
470
|
+
- **The `daily` secrets policy is now called `hold`, because it was never daily.** The default prompt policy holds a bundle for `secrets.agent.holdMs` — 7 days out of the box — yet it was named `daily`, so `agents secrets policy --help` read as "you will be asked once a day" while the code comment beside it said "one Touch ID per ~7d". Both the CLI help and `docs/secrets.md` had resorted to apologising for it in prose ("Name is historical", "Despite the name, it is not tied to one calendar day"), which is a name stating something false, not a name that is merely unclear. It is not one day, not one session, and not any fixed period — it is the configured hold window, so it is now named for that. **`daily` and the wire token `session` remain accepted everywhere** (`agents secrets policy <bundle> daily`, `secrets.policy: daily` in agents.yaml, and the `tier: session` key already written into every bundle on every synced machine), so no config or stored bundle changes behaviour on upgrade. **One machine-readable surface does change**: `agents secrets list --json` and `agents secrets view --json` now report `"policy": "hold"` where a default-tier bundle previously reported `"daily"`. Anything matching on that string needs updating — the CLI keeps accepting `daily` as input, but it no longer emits it, because a JSON field that reports a name the CLI itself has retired is a worse trap than a one-line change. The help text now also states what the tier actually depends on: the hold is a property of the running broker plus the durable session, not of the stored keychain item, so a broker that is down degrades `hold` to prompt-every-read; only `never` is prompt-free independently of the broker. Source: `apps/cli/src/lib/secrets/bundles.ts` (`SecretsPolicy`, `parsePolicy`, `secretsDefaultPolicy`), `apps/cli/src/commands/secrets.ts` (`parsePolicyOpt`, `policy` command help), `apps/cli/src/lib/secrets/index.ts` (legacy token mapping for the signed helper), `apps/cli/docs/secrets.md`.
|
|
471
|
+
|
|
472
|
+
- **Claude usage/probe reads can authenticate with a file-based setup-token
|
|
473
|
+
instead of the login keychain — no Touch ID.** On macOS, reading a Claude
|
|
474
|
+
account's usage went through Claude Code's ACL-bound
|
|
475
|
+
`Claude Code-credentials-<hash>` keychain item (`loadClaudeOauth` →
|
|
476
|
+
`/usr/bin/security`), popping a Touch ID sheet on every cold read — per account,
|
|
477
|
+
roughly every 8h, and again on the routines daemon's 3-minute auth-health probe
|
|
478
|
+
(`probeLocalFleetAuth`), so `ag view` and the background warm both prompted.
|
|
479
|
+
`loadClaudeOauth` now first resolves a per-account `claude setup-token` from the
|
|
480
|
+
reserved **file-based** `auth` secrets bundle (keyed by account email as
|
|
481
|
+
`CLAUDE_CODE_OAUTH_TOKEN_<slug>`); when present, the usage endpoint is
|
|
482
|
+
authenticated with that long-lived, non-rotating token and the keychain is never
|
|
483
|
+
touched — killing the prompt. This applies only to the read-only usage/probe
|
|
484
|
+
callers (`accessTokenCache`); the full-credential run/export path (which needs the
|
|
485
|
+
refresh token) is unchanged, and an account with no provisioned setup-token still
|
|
486
|
+
falls through to the keychain for now. Keyed strictly per-account (never a bare
|
|
487
|
+
shared key) so one account's token can't be misapplied to another. Source:
|
|
488
|
+
`apps/cli/src/lib/usage.ts`; design: `docs/design/credential-management.md`.
|
|
489
|
+
|
|
3
490
|
## 1.20.78
|
|
4
491
|
|
|
5
492
|
- **`agents sessions <uuid>` now resolves a remote session exactly, across the
|