@phnx-labs/agents-cli 1.20.92 → 1.21.0
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 +385 -0
- package/README.md +3 -0
- package/dist/bin/agents +0 -0
- package/dist/commands/beta.js +3 -5
- package/dist/commands/doctor.js +23 -0
- package/dist/commands/events.js +91 -1
- package/dist/commands/exec.js +13 -0
- package/dist/commands/mailboxes.js +39 -1
- package/dist/commands/message.js +12 -1
- package/dist/commands/packages.js +14 -5
- package/dist/commands/projects.d.ts +38 -0
- package/dist/commands/projects.js +355 -48
- package/dist/commands/routines.js +27 -1
- package/dist/commands/rules.js +6 -0
- package/dist/commands/secrets.d.ts +17 -0
- package/dist/commands/secrets.js +198 -7
- package/dist/commands/send.d.ts +14 -12
- package/dist/commands/send.js +105 -35
- package/dist/commands/sessions.d.ts +17 -0
- package/dist/commands/sessions.js +16 -8
- package/dist/commands/setup-browser.js +5 -1
- package/dist/commands/setup-fleet.js +5 -0
- package/dist/commands/setup-preferences.d.ts +53 -0
- package/dist/commands/setup-preferences.js +142 -0
- package/dist/commands/setup.js +8 -9
- package/dist/commands/ssh.js +220 -10
- package/dist/commands/sync.d.ts +2 -2
- package/dist/commands/sync.js +13 -12
- package/dist/commands/view.js +4 -0
- package/dist/commands/watchdog.js +26 -3
- package/dist/index.js +38 -6
- package/dist/lib/activity.d.ts +15 -0
- package/dist/lib/activity.js +26 -2
- package/dist/lib/auto-dispatch.d.ts +6 -1
- package/dist/lib/auto-dispatch.js +7 -2
- package/dist/lib/beta.d.ts +1 -1
- package/dist/lib/beta.js +1 -1
- package/dist/lib/channels/send.d.ts +83 -0
- package/dist/lib/channels/send.js +112 -0
- package/dist/lib/daemon.d.ts +13 -0
- package/dist/lib/daemon.js +80 -60
- package/dist/lib/device-config.d.ts +82 -0
- package/dist/lib/device-config.js +296 -0
- package/dist/lib/event-provenance.d.ts +19 -0
- package/dist/lib/event-provenance.js +48 -0
- package/dist/lib/events-ingest.d.ts +46 -0
- package/dist/lib/events-ingest.js +182 -0
- package/dist/lib/events.d.ts +17 -5
- package/dist/lib/events.js +59 -56
- package/dist/lib/feed.d.ts +1 -1
- package/dist/lib/feed.js +2 -0
- package/dist/lib/git.d.ts +13 -2
- package/dist/lib/git.js +38 -6
- package/dist/lib/linear-project-counts.d.ts +129 -0
- package/dist/lib/linear-project-counts.js +206 -0
- package/dist/lib/linear-projects.d.ts +62 -0
- package/dist/lib/linear-projects.js +144 -0
- package/dist/lib/mailbox-gc.js +30 -7
- package/dist/lib/mailbox.d.ts +14 -1
- package/dist/lib/mailbox.js +35 -3
- package/dist/lib/menubar/MenubarHelper.app/Contents/CodeResources +0 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
- package/dist/lib/menubar/install-menubar.d.ts +5 -21
- package/dist/lib/menubar/install-menubar.js +35 -44
- package/dist/lib/menubar/notify-desktop.d.ts +17 -2
- package/dist/lib/menubar/notify-desktop.js +8 -2
- package/dist/lib/migrate.js +1 -1
- package/dist/lib/models.js +21 -11
- package/dist/lib/overdue.d.ts +1 -1
- package/dist/lib/overdue.js +54 -19
- package/dist/lib/project-import.d.ts +96 -0
- package/dist/lib/project-import.js +171 -0
- package/dist/lib/project-probe.d.ts +75 -0
- package/dist/lib/project-probe.js +160 -0
- package/dist/lib/project-resources.d.ts +8 -0
- package/dist/lib/project-resources.js +31 -3
- package/dist/lib/project-status.d.ts +32 -1
- package/dist/lib/project-status.js +82 -1
- package/dist/lib/projects.d.ts +6 -0
- package/dist/lib/projects.js +12 -0
- package/dist/lib/remote-agents-json.d.ts +14 -1
- package/dist/lib/remote-agents-json.js +21 -3
- package/dist/lib/routine-notify.d.ts +11 -0
- package/dist/lib/routine-notify.js +22 -0
- package/dist/lib/routines.d.ts +53 -0
- package/dist/lib/routines.js +105 -4
- package/dist/lib/rules/run-sync.d.ts +18 -0
- package/dist/lib/rules/run-sync.js +92 -0
- package/dist/lib/run-notify.js +3 -0
- package/dist/lib/scheduler.js +12 -2
- 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/audit.d.ts +1 -1
- package/dist/lib/secrets/audit.js +53 -10
- package/dist/lib/secrets/index.d.ts +4 -5
- package/dist/lib/secrets/index.js +4 -5
- package/dist/lib/secrets/list-filter.d.ts +20 -5
- package/dist/lib/secrets/list-filter.js +22 -6
- package/dist/lib/secrets/usage-db.d.ts +106 -0
- package/dist/lib/secrets/usage-db.js +236 -0
- package/dist/lib/session/active.d.ts +16 -2
- package/dist/lib/session/active.js +8 -4
- package/dist/lib/session/bundle.js +5 -1
- package/dist/lib/session/remote-active.d.ts +5 -1
- package/dist/lib/session/remote-active.js +4 -1
- package/dist/lib/session/remote-list.d.ts +1 -15
- package/dist/lib/session/remote-list.js +22 -111
- package/dist/lib/session/sync/config.d.ts +13 -5
- package/dist/lib/session/sync/config.js +21 -13
- package/dist/lib/sqlite.js +28 -1
- package/dist/lib/startup/command-registry.d.ts +0 -2
- package/dist/lib/startup/command-registry.js +1 -5
- package/dist/lib/state.d.ts +19 -2
- package/dist/lib/state.js +99 -10
- package/dist/lib/sync-umbrella.d.ts +11 -23
- package/dist/lib/sync-umbrella.js +14 -45
- package/dist/lib/teams/agents.d.ts +35 -3
- package/dist/lib/teams/agents.js +52 -8
- package/dist/lib/teams/scheduler.d.ts +29 -2
- package/dist/lib/teams/scheduler.js +60 -16
- package/dist/lib/types.d.ts +22 -5
- package/dist/lib/versions.d.ts +6 -0
- package/dist/lib/versions.js +6 -4
- package/package.json +1 -2
- package/dist/commands/drive.d.ts +0 -10
- package/dist/commands/drive.js +0 -183
- package/dist/commands/hq.d.ts +0 -2
- package/dist/commands/hq.js +0 -58
- package/dist/commands/sessions-sync.d.ts +0 -17
- package/dist/commands/sessions-sync.js +0 -135
- package/dist/commands/sync-provision.d.ts +0 -23
- package/dist/commands/sync-provision.js +0 -107
- package/dist/lib/drive-sync.d.ts +0 -45
- package/dist/lib/drive-sync.js +0 -238
- package/dist/lib/hq/floor.d.ts +0 -87
- package/dist/lib/hq/floor.js +0 -243
- package/dist/lib/session/sync/crdt.d.ts +0 -44
- package/dist/lib/session/sync/crdt.js +0 -119
- package/dist/lib/session/sync/manifest.d.ts +0 -62
- package/dist/lib/session/sync/manifest.js +0 -100
- package/dist/lib/session/sync/provision.d.ts +0 -49
- package/dist/lib/session/sync/provision.js +0 -91
- package/dist/lib/session/sync/r2.d.ts +0 -32
- package/dist/lib/session/sync/r2.js +0 -121
- package/dist/lib/session/sync/sync.d.ts +0 -106
- package/dist/lib/session/sync/sync.js +0 -374
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,390 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.21.0
|
|
4
|
+
|
|
5
|
+
- **A clone of your own DotAgents repo no longer hijacks project-layer rule resolution (RUSH-2037).**
|
|
6
|
+
Cloning `~/.agents` to the canonical `~/src/github.com/<you>/.agents` path (to edit
|
|
7
|
+
rules in an editor) made that checkout eligible as a *project* layer whenever you
|
|
8
|
+
worked from its parent directory. Because project outranks user, a stale clone's
|
|
9
|
+
`rules/subrules/*` then silently shadowed the live user rules by filename, and the
|
|
10
|
+
compile planted an out-of-date `AGENTS.md` in an ancestor dir that every session
|
|
11
|
+
beneath it ingested. Project-layer discovery now identifies a DotAgents repo by
|
|
12
|
+
**repo identity** (git origin), not path: a `.agents/` that is itself a git checkout
|
|
13
|
+
whose origin matches the user's or system's DotAgents repo is skipped, so the live
|
|
14
|
+
user layer wins. Legitimate project `.agents/` layers (a plain subdirectory of a
|
|
15
|
+
project, or a git repo with an unrelated origin) are unaffected.
|
|
16
|
+
Source: `apps/cli/src/lib/state.ts`.
|
|
17
|
+
|
|
18
|
+
- **`agents sessions --local` no longer dials remote-host teammates over ssh,
|
|
19
|
+
in the default listing or `--active` (RUSH-2118).** `--local` is supposed to
|
|
20
|
+
mean this-machine-only, but the underlying `AgentManager` poll still fired a
|
|
21
|
+
real ssh round-trip for every teammate dispatched via
|
|
22
|
+
`agents teams add --device` — even a teammate that had already finished.
|
|
23
|
+
On a box with 30 completed remote-host teammates that measured out to 180
|
|
24
|
+
real `ssh` execve calls (6 per teammate: two ssh calls in
|
|
25
|
+
`syncRemoteMirror`, run three times per poll) and a ~4.3s
|
|
26
|
+
`--active --local` call. A `--local` query now reads a remote-host
|
|
27
|
+
teammate's last-persisted `meta.json` state instead of dialing it, and a
|
|
28
|
+
teammate that has already reached a terminal status (completed/failed/
|
|
29
|
+
stopped) is never re-dialed by ANY `--active` query, local or not — its
|
|
30
|
+
final log bytes and exit code were already captured on the poll that
|
|
31
|
+
resolved it. The same gate now covers every `--local` surface: the bare
|
|
32
|
+
default listing's live-glyph enrichment (`maybeLiveIndex`) and `--preview`
|
|
33
|
+
(`renderSessionPreview`, freely combinable with `--local`) both called the
|
|
34
|
+
local-only `getActiveSessions()` with no `localOnly` threaded through,
|
|
35
|
+
despite the `--local` help text already promising this-machine-only for
|
|
36
|
+
all of them. Source: `apps/cli/src/lib/teams/agents.ts`
|
|
37
|
+
(`syncRemoteMirror`, `readNewEvents`, `updateStatusFromProcess`,
|
|
38
|
+
`AgentManager`), `apps/cli/src/lib/session/active.ts` (`listTeamsActive`,
|
|
39
|
+
`getActiveSessions`), `apps/cli/src/commands/sessions.ts`
|
|
40
|
+
(`gatherActiveSessions`, `maybeLiveIndex`, `renderSessionPreview`).
|
|
41
|
+
|
|
42
|
+
- **A rules preset now applies at `agents run` time, not only after `agents
|
|
43
|
+
rules switch` (RUSH-2128).** `setActiveRulesPreset` used to take effect only on the next
|
|
44
|
+
explicit `agents rules switch`/`agents add`/`agents use` — a preset change
|
|
45
|
+
made any other way left the harness launching against a stale rules file
|
|
46
|
+
until someone remembered to re-sync. `agents run` now re-applies the active
|
|
47
|
+
preset for the resolved agent+version immediately before dispatch, every
|
|
48
|
+
time, with a skip-fast sentinel so an unchanged preset costs no recompose or
|
|
49
|
+
rewrite. Version-scoped only; per-model preset scoping is a follow-up.
|
|
50
|
+
Source: `apps/cli/src/lib/rules/run-sync.ts`, `apps/cli/src/commands/exec.ts`.
|
|
51
|
+
|
|
52
|
+
- **Activity events now carry the same actor and session lineage as operational events.**
|
|
53
|
+
The TypeScript activity writer and the embedded PostToolUse hook stamp actor kind,
|
|
54
|
+
launch id, and parent session id from the shared execution provenance floor, so
|
|
55
|
+
`agents events` no longer invents an agent name as the activity record's OS user.
|
|
56
|
+
Source: `apps/cli/src/lib/event-provenance.ts`, `apps/cli/src/lib/activity.ts`.
|
|
57
|
+
|
|
58
|
+
- **`agents view` no longer re-scans every installed Claude binary on each run.**
|
|
59
|
+
When a Claude model extractor produced zero models (a broken regex, or a
|
|
60
|
+
mid-install CLI), the result was never cached — so `getModelCatalog` re-ran a
|
|
61
|
+
full `readFileSync` scan of the 230-270MB Claude binary for every affected
|
|
62
|
+
installed version, on every invocation (~1.85s each). With 4 affected
|
|
63
|
+
versions installed, that was ~7.5s added to every `agents view`. A 0-model
|
|
64
|
+
extraction is now cached too, stamped with when it was attempted, and served
|
|
65
|
+
for 24 hours before self-healing by retrying; an upgrade/reinstall (a new
|
|
66
|
+
source mtime) still re-extracts immediately, as before. Measured on a real
|
|
67
|
+
install with 7 Claude versions (4 of them hitting the broken extractor): the
|
|
68
|
+
cold first-call cost (~12.5s, unavoidable) drops to ~1-2ms on every
|
|
69
|
+
subsequent call. Source: `apps/cli/src/lib/models.ts`.
|
|
70
|
+
|
|
71
|
+
- **Per-device and fleet-wide config keys now have a home: the `config:` block in
|
|
72
|
+
the two-tier agents.yaml store.** Three new subcommands under `agents devices`
|
|
73
|
+
(no new top-level noun): `agents devices set-interactive <name>` records the one
|
|
74
|
+
device agents show YOU artifacts on (browser opens, dashboards) as
|
|
75
|
+
`config.interactiveHost` in the central, synced agents.yaml — skills no longer
|
|
76
|
+
guess "the online macOS box", and the host is marked `★ interactive` in
|
|
77
|
+
`agents devices list`. `agents devices configure <name> --max-agents N
|
|
78
|
+
--scheduler on|off` and `agents devices note <name> "…"` (repeat
|
|
79
|
+
to append, `--clear` to empty) write device-scope keys under `config:` in
|
|
80
|
+
`~/.agents/devices/<name>/agents.yaml` — targetable for any device from any box
|
|
81
|
+
(the devices/ tree syncs; each machine reads only its own). The default browser
|
|
82
|
+
profile joins the same registry as `browser.profile`, routed to the existing
|
|
83
|
+
device-local `defaultBrowserProfile` field (no duplicate key, resolution order
|
|
84
|
+
unchanged). Unset keys always mean today's behavior; everything is scriptable
|
|
85
|
+
with `--json`, and `devices list --json` now carries each row's `config` and an
|
|
86
|
+
`interactive` flag. agents.yaml files the CLI writes now carry a
|
|
87
|
+
`yaml-language-server` hint pointing at the new
|
|
88
|
+
`apps/cli/schema/agents-yaml.schema.json`.
|
|
89
|
+
|
|
90
|
+
The keys are live inputs, not just stored values. `--scheduler off` stops the
|
|
91
|
+
routines scheduler from starting on that device — `routines add` skips the
|
|
92
|
+
auto-start with the reason, a manual `routines start` refuses, and the daemon
|
|
93
|
+
re-evaluates the gate on every SIGHUP reload (boot it again with
|
|
94
|
+
`agents devices configure <host> --scheduler on` + any reload, no daemon
|
|
95
|
+
restart). `--max-agents` feeds host ranking: Factory auto-launch excludes a
|
|
96
|
+
device at its cap (counting device-wide running agents) and names the cap when
|
|
97
|
+
a pool is exhausted; teams placement excludes it from the least-loaded
|
|
98
|
+
auto-pick (counting the team's own roster, local teammates included) and an
|
|
99
|
+
all-capped pool fails loud instead of over-filling a machine. Setup asks
|
|
100
|
+
instead of guessing: bare `agents setup` ends with a skippable preferences
|
|
101
|
+
step (which machine you sit at → interactive host; which browser agents drive
|
|
102
|
+
here → device default), `agents setup fleet` offers the interactive host after
|
|
103
|
+
a sync, and the `agents setup browser` picker highlights the auto-detect
|
|
104
|
+
winner. Source: `apps/cli/src/lib/device-config.ts`,
|
|
105
|
+
`apps/cli/src/lib/state.ts`, `apps/cli/src/lib/daemon.ts`,
|
|
106
|
+
`apps/cli/src/lib/teams/scheduler.ts`, `apps/cli/src/commands/ssh.ts`,
|
|
107
|
+
`apps/cli/src/commands/setup-preferences.ts`,
|
|
108
|
+
`apps/factory/src/core/launchHost.ts`,
|
|
109
|
+
`apps/cli/schema/agents-yaml.schema.json`.
|
|
110
|
+
|
|
111
|
+
- **Mailbox messages now expire and dead boxes are reaped automatically.** Messages
|
|
112
|
+
enqueued without an explicit TTL used to sit in the spool forever, so pending mail
|
|
113
|
+
would outlive the session that needed it. They now get a 24-hour default TTL
|
|
114
|
+
(`AGENTS_MAILBOX_TTL` overrides the default; `agents message … --ttl 2h` sets it
|
|
115
|
+
per message). When a message expires, a live-but-idle box archives it with a
|
|
116
|
+
`dropped: expired` receipt. The watchdog tick also runs a liveness sweep using the
|
|
117
|
+
same live-session set as `agents sessions --active`, archiving pending mail in dead
|
|
118
|
+
boxes as `dropped: dead` and pruning stale consumed entries. Dropped messages tied
|
|
119
|
+
to a feed block surface a failure receipt (`status: dropped` / `expired`) so the
|
|
120
|
+
sender sees the bounce instead of silence. Run the sweep manually with
|
|
121
|
+
`agents mailboxes gc` (`--json` supported). Source:
|
|
122
|
+
`apps/cli/src/lib/mailbox.ts`, `apps/cli/src/lib/mailbox-gc.ts`,
|
|
123
|
+
`apps/cli/src/commands/message.ts`, `apps/cli/src/commands/mailboxes.ts`,
|
|
124
|
+
`apps/cli/src/commands/watchdog.ts`, `apps/cli/src/lib/feed.ts`.
|
|
125
|
+
|
|
126
|
+
- **The menu-bar helper can no longer leak CLI processes until the machine is unusable.**
|
|
127
|
+
Its poll shelled `agents doctor --json` through an unbounded `Process` +
|
|
128
|
+
`readDataToEndOfFile()`. Two properties composed badly: the call had no deadline
|
|
129
|
+
(`doctor --json` measures **136s on an idle box**, against a 60s poll interval), and a
|
|
130
|
+
helper that died mid-call left the child reparented to launchd (PPID 1) with nothing
|
|
131
|
+
to reap it — along with the `node -e` version probes that child had forked. Both fire
|
|
132
|
+
together, because the helper crashes under exactly the conditions that make the CLI
|
|
133
|
+
slow: `NSApplication.shared` segfaults inside `SLSNewConnection` when WindowServer is
|
|
134
|
+
too starved to hand out a connection, launchd's `KeepAlive` restarts it, and the
|
|
135
|
+
restart spawns a new doctor while the old one keeps burning a core. Observed on a real
|
|
136
|
+
machine: 38 orphaned doctors + 92 orphaned probes, ~13 of 18 cores consumed, load
|
|
137
|
+
average 490, keystrokes visibly lagging.
|
|
138
|
+
The crash itself cannot be prevented from inside the app — it is AppKit dereferencing
|
|
139
|
+
a null connection before any of our code runs — so a crash no longer costs anything
|
|
140
|
+
permanent: every child carries a deadline (30s; 180s for `doctor --json`, above its
|
|
141
|
+
real measured cost); it is spawned as its own process-group leader so a timeout kills
|
|
142
|
+
the whole subtree rather than just the CLI; and each live child is recorded on disk so
|
|
143
|
+
the *next* launch reaps whatever a crash abandoned (no exit handler runs on SIGSEGV).
|
|
144
|
+
The doctor refresh also drops from every 60s to every 15 minutes, and the launchd job
|
|
145
|
+
gains `ThrottleInterval` 30 so a startup crash-loop cannot respawn every 10s.
|
|
146
|
+
A poll that blows its deadline now shows a stale menu instead of taking the machine
|
|
147
|
+
down with it. Source: `apps/cli/menubar/Sources/MenubarHelper/ChildProcess.swift`,
|
|
148
|
+
`AgentsCLI.swift`, `StatusItemController.swift`, `main.swift`,
|
|
149
|
+
`apps/cli/src/lib/menubar/install-menubar.ts`.
|
|
150
|
+
|
|
151
|
+
- **The macOS menu-bar helper is now notarized, ending the "app is damaged"
|
|
152
|
+
dialog and the per-run `no valid code signature; skipping launch` spam
|
|
153
|
+
(RUSH-2134).** The helper shipped Developer-ID signed but *not* notarized, so
|
|
154
|
+
Gatekeeper on macOS 26+ rejected it as damaged and the install path tried to
|
|
155
|
+
heal it by re-signing ad-hoc on every `agents` invocation — which can never
|
|
156
|
+
satisfy Gatekeeper, so the dialog and the noise persisted. The release now
|
|
157
|
+
notarizes + staples the helper (`menubar/scripts/build.sh`, mandatory for any
|
|
158
|
+
Developer-ID build, run under the release's `agents secrets exec apple.com`
|
|
159
|
+
context), the `prepack` gate refuses to pack an un-notarized bundle
|
|
160
|
+
(`scripts/verify-menubar-helper.sh` now requires a stapled ticket), and the
|
|
161
|
+
runtime ad-hoc re-sign band-aid is deleted — a notarized + stapled bundle
|
|
162
|
+
survives npm's tarball round-trip untouched, so the helper launches with no
|
|
163
|
+
per-machine healing. The launch guards now verify Gatekeeper acceptance (not
|
|
164
|
+
just `codesign --verify`) and fail loud pointing at an upgrade rather than
|
|
165
|
+
re-signing over it. Source: `apps/cli/menubar/scripts/build.sh`,
|
|
166
|
+
`apps/cli/scripts/verify-menubar-helper.sh`, `apps/cli/scripts/release.sh`,
|
|
167
|
+
`apps/cli/src/lib/menubar/install-menubar.ts`.
|
|
168
|
+
|
|
169
|
+
- **`agents projects import` gains Linear as a source, and gates the Factory guess.**
|
|
170
|
+
`import --from-linear` turns the workspace's Linear projects into definitions via the
|
|
171
|
+
`linear` CLI, binding a local checkout only on an exact name match so it never
|
|
172
|
+
silently points a project at the wrong repo. `--from-factory` now imports only
|
|
173
|
+
`high`-confidence rows by default (`--min-confidence low|medium|high`, `--all` to
|
|
174
|
+
take everything), and prints why each row was skipped — the auto-detected registry
|
|
175
|
+
used to absorb every stale clone it found. Source: `apps/cli/src/lib/project-import.ts`.
|
|
176
|
+
- **`agents projects list` columns line up again.** Widths are computed from the rows
|
|
177
|
+
being printed instead of a fixed 32-character path pad that every home-relative root
|
|
178
|
+
ran straight through. Source: `apps/cli/src/commands/projects.ts`.
|
|
179
|
+
|
|
180
|
+
- **`agents projects status` shows the next Linear milestone.** A new `next` line names
|
|
181
|
+
the project's earliest unfinished milestone with its progress and a human due date
|
|
182
|
+
(`Beta cut · 3/8 · due in 6 days`, `overdue by 3 days`, `due Aug 21`) — a percentage
|
|
183
|
+
says how far along a project is, the milestone says what it is due to hit next. The
|
|
184
|
+
milestone list comes from the project rather than from issue assignments, so a
|
|
185
|
+
milestone with nothing filed under it yet still shows; it rides along on the first
|
|
186
|
+
page of the existing issue fetch, costing no extra request. Source:
|
|
187
|
+
`apps/cli/src/lib/linear-project-counts.ts`.
|
|
188
|
+
|
|
189
|
+
- **`agents publish --branch <b>` now pushes the index to `<b>`, not just the printed URL (#1061).**
|
|
190
|
+
The flag rewrote the printed `raw.githubusercontent.com/.../<b>/skills-index.json`
|
|
191
|
+
URL, but the commit still landed on the checked-out branch — so `--branch dev` from a
|
|
192
|
+
`main` checkout published the index to `main` while advertising a `dev` URL that didn't
|
|
193
|
+
resolve. `commitAndPush` now takes an optional target branch and pushes
|
|
194
|
+
`<current>:<target>`, reporting back the branch the index actually landed on so the URL
|
|
195
|
+
references it. Omitting `--branch` still publishes to the repo's current branch.
|
|
196
|
+
Source: `apps/cli/src/lib/git.ts` (`commitAndPush`, `pushOrigin`, `getCurrentBranch`),
|
|
197
|
+
`apps/cli/src/commands/packages.ts`.
|
|
198
|
+
|
|
199
|
+
- **Remove the unused `agents hq` command.** `agents hq floor --json` was a
|
|
200
|
+
machine-readable bridge for an interactive Agents HQ floor UI that was never
|
|
201
|
+
built — `apps/factory` has zero references to it and it had no other consumer.
|
|
202
|
+
Typing `agents hq` now prints a clear removal notice and exits non-zero instead
|
|
203
|
+
of silently disappearing. Source: `apps/cli/src/index.ts`,
|
|
204
|
+
`apps/cli/src/lib/startup/command-registry.ts` (removed
|
|
205
|
+
`apps/cli/src/commands/hq.ts`, `apps/cli/src/lib/hq/`).
|
|
206
|
+
|
|
207
|
+
- **Removed `agents drive` and the R2/CRDT background session-sync beta.** Both
|
|
208
|
+
predate `agents sessions export`/`import`, which now cover the same ground
|
|
209
|
+
without a daemon: `agents drive` (rsync-based session/config mirroring) and
|
|
210
|
+
the opt-in `session-sync` beta (`agents sessions sync`, the daemon's ~90s R2
|
|
211
|
+
push/pull loop, `agents sync --sessions`) are gone. If you had `session-sync`
|
|
212
|
+
or `drive` enabled, re-enable is no longer possible — use `--host` for live
|
|
213
|
+
cross-machine reads or `agents sessions export --encrypt` /
|
|
214
|
+
`agents sessions import` for portable, encrypted transcript bundles instead.
|
|
215
|
+
The R2 network client and CRDT merge machinery are removed entirely with the
|
|
216
|
+
rest of the background sync. Export/import's own encrypted-bundle path
|
|
217
|
+
survives unchanged: it never talked to R2 over the network — it only reuses
|
|
218
|
+
the `r2.backups` bundle's shared `R2_SYNC_ENC_KEY` for local AES-256-GCM
|
|
219
|
+
encryption, falling back to a printed ephemeral key when that bundle isn't
|
|
220
|
+
configured. Source: `apps/cli/src/commands/drive.ts`,
|
|
221
|
+
`apps/cli/src/commands/sessions-sync.ts`, `apps/cli/src/lib/session/sync/crdt.ts`,
|
|
222
|
+
`apps/cli/src/lib/session/sync/sync.ts`, `apps/cli/src/lib/session/sync/r2.ts`,
|
|
223
|
+
`apps/cli/src/lib/daemon.ts`.
|
|
224
|
+
|
|
225
|
+
- **A routine that fires less often than weekly can now be caught up at all.** Overdue
|
|
226
|
+
detection walked a fixed one-week window for the most recent expected fire, so any cron whose
|
|
227
|
+
gap exceeds that returned nothing and the routine was skipped entirely — never flagged
|
|
228
|
+
overdue on any device, never caught up, no `missed` record, silently. Monthly, semi-monthly,
|
|
229
|
+
quarterly and annual routines were all in that class. Measured on a real schedule
|
|
230
|
+
(`0 9 1,13,25 * *`, 12-day gaps): on **10 of every 28 days** the routine could not be
|
|
231
|
+
evaluated. The lookback now widens (week → month → quarter → year) only when the narrower
|
|
232
|
+
window finds nothing, so a dense schedule never walks more than a week of occurrences.
|
|
233
|
+
- **Catch-up no longer resurrects a retired routine.** `detectOverdueJobs` never checked
|
|
234
|
+
`endAt`, and the scheduler only auto-disables lazily inside a live cron tick — so a routine
|
|
235
|
+
whose `endAt` elapsed while the daemon was down was still enabled on disk, rescheduled on
|
|
236
|
+
restart, and executed by the catch-up pass.
|
|
237
|
+
- **One-shot detection matches the scheduler's.** Overdue used the raw `runOnce` flag while the
|
|
238
|
+
scheduler uses `isOneShotRoutine`, so a one-shot-*like* schedule (a fixed minute/hour/day/
|
|
239
|
+
month) that never carried the flag could be replayed by catch-up.
|
|
240
|
+
- **The creation floor now covers built-in routines.** `routineEffectiveStart` resolved a
|
|
241
|
+
routine's file through a user-layer-only lookup, but `listJobs` reads the system layer too —
|
|
242
|
+
so a built-in shipped in the system repo had neither a `createdAt` stamp nor a resolvable
|
|
243
|
+
path, the floor was skipped, and it read as instantly overdue on first daemon start. Added
|
|
244
|
+
`resolveJobFilePath`, which resolves across every layer the loader reads.
|
|
245
|
+
- **A `createdAt` in the future is clamped to now.** Left unclamped (clock skew, a hand-edited
|
|
246
|
+
year) it sits after every possible expected fire, so the routine could never be flagged
|
|
247
|
+
overdue until wall-clock time caught up.
|
|
248
|
+
|
|
249
|
+
- **A routine now runs on exactly one device, instead of once per device listed.** `devices:`
|
|
250
|
+
was an allowlist where *every* listed device fired independently, so a routine pinned to two
|
|
251
|
+
boxes ran twice on every schedule — two full agent sessions doing identical work and burning
|
|
252
|
+
double the agent quota. On one live fleet seven routines were in that state: `security-sweep`
|
|
253
|
+
ran at 15:30:02 on one box and 15:30:03 on the other, both completing. Ownership is now a pure
|
|
254
|
+
function of the config (the first device in normalized sort order), so every daemon reaches the
|
|
255
|
+
same answer with no lease, no cross-device coordination, and no split brain when the fleet
|
|
256
|
+
partitions. Omitting `devices` still means fleet-wide, which is what `watchdog` and
|
|
257
|
+
`check-updates` want.
|
|
258
|
+
- **`agents routines add --devices a,b` and `devices --set a,b` are now rejected.** A routine
|
|
259
|
+
belongs to one machine; the error names the fix. Routines already on disk with a multi-device
|
|
260
|
+
pin keep running — on their owner only — rather than being dropped.
|
|
261
|
+
- **`agents doctor` lists any routine still carrying a multi-device pin**, with the devices it
|
|
262
|
+
names, the one that now fires, and the command to make it explicit. Also in `doctor --json` as
|
|
263
|
+
`ambiguousDevicePins`. The remediation deliberately offers the candidates rather than
|
|
264
|
+
prescribing the owner: the lowest-sorted name can be a registry alias that matches no live
|
|
265
|
+
machine, and cementing that would keep the routine dead.
|
|
266
|
+
|
|
267
|
+
## 1.20.93
|
|
268
|
+
|
|
269
|
+
- **`agents send` is a real delivery envelope; `notify` is just `--to owner` (RUSH-2123).** Flag-first form: `--to`, `--text`, `--channel`, `--attach`, `--url`. `--to owner` expands from `notify.owner` in agents.yaml. Positional text still works. Help names the three planes (deliver / record / control) so send is not confused with `feed post`, `activity`, or `message`/`sessions inject`. Source: `apps/cli/src/commands/send.ts`, `apps/cli/src/lib/channels/send.ts`.
|
|
270
|
+
|
|
271
|
+
- **`agents events emit` — record events produced outside the CLI.** In-process code
|
|
272
|
+
calls `emit()` directly, but the producers that most need to record events are not
|
|
273
|
+
agents-cli processes: the Factory VS Code extension host, shell guards, external
|
|
274
|
+
tools. They now pipe JSONL on stdin —
|
|
275
|
+
`… | agents events emit --source factory`. `--source` is stamped as `module`, so
|
|
276
|
+
`agents events --module factory` filters to one producer. Routing is forced by the
|
|
277
|
+
stores rather than chosen: a milestone kind requires a `sessionId` and lands in that
|
|
278
|
+
session's activity log, everything else lands in the operational log. A milestone
|
|
279
|
+
with no `sessionId` is rejected, not quietly written elsewhere. Rejection is per
|
|
280
|
+
line, so one bad line never discards a batch, and the exit code is 1 if any line was
|
|
281
|
+
rejected. `--dry-run` validates without writing.
|
|
282
|
+
Source: `apps/cli/src/lib/events-ingest.ts`, `apps/cli/src/commands/events.ts`,
|
|
283
|
+
`apps/cli/docs/06-observability.md`.
|
|
284
|
+
|
|
285
|
+
- **Four `factory.*` event kinds.** `factory.command`, `factory.action`, `factory.uri`
|
|
286
|
+
and `factory.launch` describe what a user did in the Factory VS Code extension.
|
|
287
|
+
`factory.launch` is a milestone — it carries the `sessionId` and `terminalId` that
|
|
288
|
+
later events join through — and `factory.uri` is audit-level, since an external
|
|
289
|
+
process driving the user's editor is a "who reached in from outside" fact.
|
|
290
|
+
Source: `apps/cli/src/lib/events.ts`, `apps/cli/src/lib/activity.ts`.
|
|
291
|
+
|
|
292
|
+
- **`emit()` accepts a caller-supplied timestamp.** A batched producer records when
|
|
293
|
+
each event *happened* and flushes later; without this, every event in a flush was
|
|
294
|
+
stamped at flush time, collapsing their order and corrupting `--since` boundaries.
|
|
295
|
+
`ts` stays reserved against payload injection — only the explicit override can set
|
|
296
|
+
it. Source: `apps/cli/src/lib/events.ts`.
|
|
297
|
+
|
|
298
|
+
- **Fixed: `agents _internal friction` recorded its own invocation.** The command
|
|
299
|
+
exists precisely because shell guards run before any `agents` process exists and so
|
|
300
|
+
cannot emit in-process, but it still fired the `command.start` / `command.end` audit
|
|
301
|
+
hooks, writing two records on top of every friction record. Recorder commands are now
|
|
302
|
+
exempt. Source: `apps/cli/src/index.ts`.
|
|
303
|
+
|
|
304
|
+
- **Desktop notifications now show the agent on the right, not a second copy of
|
|
305
|
+
the app icon.** macOS draws two images on a banner: the sending app's icon on
|
|
306
|
+
the left and `contentImage` on the right (a YouTube notification uses the slots
|
|
307
|
+
for "YouTube" plus the channel avatar). agents-cli was putting its own lime mark
|
|
308
|
+
in the right slot, so both slots said the same thing. The right slot now carries
|
|
309
|
+
the harness the notification is *about* — a brand-colored tile with a two-letter
|
|
310
|
+
mark (`CL` claude, `CX` codex, `GK` grok, …), two letters because four harnesses
|
|
311
|
+
start with `c` and two with `g`. `agents run --notify` and agent/workflow
|
|
312
|
+
routines pass their harness through; a daemon heal, an overdue sweep, a command
|
|
313
|
+
routine, or a fan-out across several agents has no single agent and leaves the
|
|
314
|
+
right slot empty. Source:
|
|
315
|
+
`apps/cli/menubar/Sources/MenubarHelper/AgentAvatar.swift`,
|
|
316
|
+
`apps/cli/src/lib/menubar/notify-desktop.ts`, `apps/cli/src/lib/run-notify.ts`,
|
|
317
|
+
`apps/cli/src/lib/routine-notify.ts`, `apps/cli/docs/menubar.md`.
|
|
318
|
+
|
|
319
|
+
- **`MenubarHelper --notify` gains `--agent <id>`.** The one-shot notifier accepts
|
|
320
|
+
the harness id that drives the right-hand avatar; omitting it is how a caller
|
|
321
|
+
says "no single agent owns this event".
|
|
322
|
+
|
|
323
|
+
- **`agents projects status --fleet` — per-device workspace drift (beta).**
|
|
324
|
+
Projects are natively multi-device; `--fleet` adds a `fleet` line to the status
|
|
325
|
+
card showing, for each project, whether its workspace repos are present on every
|
|
326
|
+
fleet device, on which branch, ahead/behind their upstream (`↑`/`↓`), and how
|
|
327
|
+
many uncommitted changes they carry — plus a hidden `agents projects probe
|
|
328
|
+
--json <path...>` subcommand that is the peer half of the fan-out. One parallel
|
|
329
|
+
SSH call per device (12s timeout), **no `git fetch`** — drift is measured
|
|
330
|
+
against each peer's last-fetched upstream, and a repo with no upstream reports
|
|
331
|
+
no drift rather than zero. Peers that are unreachable or run an older CLI are
|
|
332
|
+
named once in a trailing note; `probe` itself is not beta-gated so peers answer
|
|
333
|
+
whenever their binary carries it. The schema gains `repos[].path` (home-relative
|
|
334
|
+
local checkout) to opt additional repos into probing beyond the primary `root`,
|
|
335
|
+
and `--json` gains per-project `workspaces[]` with the host-tagged probe rows.
|
|
336
|
+
The card's `live` line also counts agents on every box under `--fleet` via the
|
|
337
|
+
existing sessions fan-out. Source: `apps/cli/src/lib/project-probe.ts`,
|
|
338
|
+
`apps/cli/src/commands/projects.ts`, `apps/cli/src/lib/projects.ts`.
|
|
339
|
+
|
|
340
|
+
- **`agents projects` outcomes on the card — agent×project members, releases,
|
|
341
|
+
Linear counts, and `projects link --linear` (beta).** The status card gains an
|
|
342
|
+
`agents` line under `live` naming WHICH harness is on each project
|
|
343
|
+
(`claude · running · RUSH-2107 @zion`, sorted running-first, capped at 6 with a
|
|
344
|
+
`+N more` tail; under `--fleet` remote agents carry their peer's hostname), a
|
|
345
|
+
latest-release tag on the `ships` line (primary repo only, best-effort
|
|
346
|
+
`gh release list`), and a `linear` line counting the bound Linear project's
|
|
347
|
+
issues by state type (`12/30 done · 5 in progress`) — best-effort with an 8s
|
|
348
|
+
budget, skipped by `--no-remote`, and omitted when the def has no
|
|
349
|
+
`linear.projectId`. The new `agents projects link <name> --linear [query]`
|
|
350
|
+
writes that binding: no query auto-suggests from the def name + repo slug via
|
|
351
|
+
the normalized-key matcher (ported from Factory's `linearProjects.ts`),
|
|
352
|
+
ambiguous/none prints the candidate list and exits 1. `--json` gains
|
|
353
|
+
`members[]`, `latestRelease`, and `linear`. Source:
|
|
354
|
+
`apps/cli/src/lib/project-status.ts`, `apps/cli/src/lib/linear-projects.ts`,
|
|
355
|
+
`apps/cli/src/lib/linear-project-counts.ts`, `apps/cli/src/commands/projects.ts`.
|
|
356
|
+
|
|
357
|
+
- **Project sync no longer spams a warning per file it left alone.** Syncing a
|
|
358
|
+
project whose `.claude/commands/` you wrote yourself printed one wrapped
|
|
359
|
+
`Skipping project resource target …: already exists and is user-owned` line
|
|
360
|
+
per file — six hand-authored commands meant twelve lines of terminal noise in
|
|
361
|
+
the middle of `agents view claude`. Those files are the normal steady state,
|
|
362
|
+
not a warning, so the sync now reports them once, grouped, in plain words:
|
|
363
|
+
`Kept 6 of your own files in .claude/commands: debug.md, doc-gaps.md,
|
|
364
|
+
image-nbp.md, +3 more`. The list also rides out on `SyncResult.projectSkipped`
|
|
365
|
+
for callers that want it. Source: `apps/cli/src/lib/project-resources.ts`.
|
|
366
|
+
|
|
367
|
+
- **`agents secrets` now tracks per-bundle usage and surfaces it.** Every secret
|
|
368
|
+
lifecycle/access event — create, import, export, view, access (a value read for
|
|
369
|
+
injection), unlock — funnels through the one `emitSecretAudit` chokepoint, which
|
|
370
|
+
writes to BOTH the append-only `~/.agents/events.jsonl` audit log AND a derived,
|
|
371
|
+
value-free read-model at `~/.agents/secrets/secrets.db` (never a secret value —
|
|
372
|
+
bundle name, event kind, key count, resolving agent/host, status only).
|
|
373
|
+
`agents secrets view <bundle>` now shows whether the bundle is currently
|
|
374
|
+
**unlocked** (held by the secrets-agent, so reads are prompt-free), a **usage**
|
|
375
|
+
summary ("accessed 42× (last 2h ago) · exported 3× (last 1d ago)"), and
|
|
376
|
+
**per-agent** attribution, and nudges when a bundle has no description (also at
|
|
377
|
+
`create` time). `agents secrets list` gains **`--sort uses`** (most frequently
|
|
378
|
+
accessed) alongside the existing `--sort used`, and the `--json` payloads carry
|
|
379
|
+
`uses`, `usage`, and `heldExpiresAt`. A new **`agents secrets activity [bundle]`**
|
|
380
|
+
prints the recent value-free event timeline (bounded to 90 days). Naming guidance
|
|
381
|
+
is taught in the help and skill: name a website bundle after its domain
|
|
382
|
+
(`stripe.com`, `openai.ai`), a desktop-app bundle after its binary suffix
|
|
383
|
+
(`slack.app`, `photoshop.exe`). Recording is best-effort and
|
|
384
|
+
`AGENTS_NO_USAGE_TRACK=1` disables it. Source:
|
|
385
|
+
`apps/cli/src/lib/secrets/usage-db.ts`, `apps/cli/src/lib/secrets/audit.ts`,
|
|
386
|
+
`apps/cli/src/commands/secrets.ts`, `apps/cli/src/lib/secrets/list-filter.ts`.
|
|
387
|
+
|
|
3
388
|
## 1.20.92
|
|
4
389
|
|
|
5
390
|
- **`agents sessions` rows show creation time as well as last activity (RUSH-2107).**
|
package/README.md
CHANGED
|
@@ -476,6 +476,9 @@ agents devices list # fleet + headroom: load, mem, idle/busy
|
|
|
476
476
|
agents devices list --live # force a live probe of every device (alias of --refresh)
|
|
477
477
|
agents devices list --full # add per-device cores and free/total RAM
|
|
478
478
|
agents devices list --no-stats # instant: names/addresses only, skip the probe
|
|
479
|
+
agents devices set-interactive zion # the device agents show YOU artifacts on (★ in the list)
|
|
480
|
+
agents devices configure mac-mini --max-agents 4 --scheduler off # per-device config (syncs via devices/<name>/agents.yaml)
|
|
481
|
+
agents devices note mac-mini "runs the releases — don't reboot" # operator notes, repeat to append
|
|
479
482
|
agents ssh mac-mini # hardened SSH: fails fast if offline,
|
|
480
483
|
# PowerShell on Windows, password-from-Keychain,
|
|
481
484
|
# auto-syncs your terminfo (Ghostty/kitty/…) so
|
package/dist/bin/agents
CHANGED
|
Binary file
|
package/dist/commands/beta.js
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import { ALL_BETA_FEATURES, getBetaConfigLocation, getEnabledBetaFeatures, setBetaEnabled, } from '../lib/beta.js';
|
|
3
3
|
const BETA_DESCRIPTIONS = {
|
|
4
|
-
drive: 'Google Drive integration for reading and writing files',
|
|
5
4
|
factory: 'Cloud-based agent dispatch via Rush Factory',
|
|
6
|
-
'session-sync': 'Cross-machine session transcript sync via R2 (daemon push/pull)',
|
|
7
5
|
projects: 'Named multi-repo projects with a progress rollup (agents projects)',
|
|
8
6
|
};
|
|
9
7
|
function parseFeatures(values) {
|
|
@@ -19,12 +17,12 @@ function parseFeatures(values) {
|
|
|
19
17
|
export function registerBetaCommands(program) {
|
|
20
18
|
const beta = program
|
|
21
19
|
.command('beta')
|
|
22
|
-
.description('Enable or disable preview features like
|
|
20
|
+
.description('Enable or disable preview features like factory.')
|
|
23
21
|
.addHelpText('after', `
|
|
24
22
|
Examples:
|
|
25
23
|
agents beta list
|
|
26
|
-
agents beta enable
|
|
27
|
-
agents beta disable
|
|
24
|
+
agents beta enable factory
|
|
25
|
+
agents beta disable factory
|
|
28
26
|
`);
|
|
29
27
|
beta
|
|
30
28
|
.command('list')
|
package/dist/commands/doctor.js
CHANGED
|
@@ -13,6 +13,7 @@ import { resolveHost } from '../lib/hosts/registry.js';
|
|
|
13
13
|
import { sshExecAsync } from '../lib/ssh-exec.js';
|
|
14
14
|
import { sshTargetFor } from '../lib/hosts/types.js';
|
|
15
15
|
import { machineId, normalizeHost } from '../lib/session/sync/config.js';
|
|
16
|
+
import { findAmbiguousDevicePins } from '../lib/routines.js';
|
|
16
17
|
import chalk from 'chalk';
|
|
17
18
|
import { checkAllClis, collectTeamsDoctorData } from '../lib/teams/agents.js';
|
|
18
19
|
import { AGENTS, ALL_AGENT_IDS, resolveAgentName, formatAgentError, getAccountInfo } from '../lib/agents.js';
|
|
@@ -1298,6 +1299,10 @@ export function registerDoctorCommand(program) {
|
|
|
1298
1299
|
const inventory = await collectLocalFleetInventory(cwd);
|
|
1299
1300
|
const localName = machineId();
|
|
1300
1301
|
const duplicateHooks = inspectDuplicateVersionHooks(cwd);
|
|
1302
|
+
// A routine belongs to one device. A multi-device pin used to fire it
|
|
1303
|
+
// once per listed device — duplicate agent runs, duplicate spend — so
|
|
1304
|
+
// surface any that are still on disk with the exact fix.
|
|
1305
|
+
const ambiguousPins = findAmbiguousDevicePins(cwd);
|
|
1301
1306
|
// Legacy account-global sign-in map, kept for `--json` back-compat
|
|
1302
1307
|
// (ssh.ts RemoteDoctorJson / menubar read `signIn`). File-based, no home.
|
|
1303
1308
|
const signIn = {};
|
|
@@ -1361,6 +1366,9 @@ export function registerDoctorCommand(program) {
|
|
|
1361
1366
|
// reading `sync`/`orphans`/`repos` are unaffected.
|
|
1362
1367
|
health: computeOverviewHealth(syncRows, orphanRows, repoBehindMarkers, duplicateHooks),
|
|
1363
1368
|
duplicateHooks,
|
|
1369
|
+
// Routines whose `devices` names more than one machine — each used to
|
|
1370
|
+
// fire once per device. `owner` is the one that fires now.
|
|
1371
|
+
ambiguousDevicePins: ambiguousPins,
|
|
1364
1372
|
// Prioritized RUSH-2069 findings (critical/warning, per-version, with
|
|
1365
1373
|
// remediation). Additive alongside the legacy fields above.
|
|
1366
1374
|
findings,
|
|
@@ -1404,6 +1412,21 @@ export function registerDoctorCommand(program) {
|
|
|
1404
1412
|
if (syncRows.some((r) => r.status !== 'fresh' || (r.unwiredHooks ?? 0) > 0) || repoBehindMarkers.some((m) => m.behind > 0)) {
|
|
1405
1413
|
console.log(chalk.gray('\nRun `agents status` to review and sync what has drifted.'));
|
|
1406
1414
|
}
|
|
1415
|
+
// A routine runs on exactly one device. Each of these named several and
|
|
1416
|
+
// used to fire once per device — duplicate agent runs on every schedule.
|
|
1417
|
+
if (ambiguousPins.length > 0) {
|
|
1418
|
+
console.log();
|
|
1419
|
+
console.log(chalk.yellow(`${ambiguousPins.length} routine(s) pin more than one device — a routine runs on exactly one:`));
|
|
1420
|
+
for (const pin of ambiguousPins) {
|
|
1421
|
+
console.log(` ${chalk.cyan(pin.name)} ${chalk.gray(`[${pin.devices.join(', ')}]`)} ` +
|
|
1422
|
+
`${chalk.gray('→ fires only on')} ${pin.owner}`);
|
|
1423
|
+
// Deliberately not prescribing `--set ${pin.owner}`: ownership is the
|
|
1424
|
+
// lowest-sorted name, which can be a registry alias that matches no
|
|
1425
|
+
// live machine (`worker` here), and cementing that keeps the routine
|
|
1426
|
+
// dead. Name the candidates and let the operator pick the real box.
|
|
1427
|
+
console.log(chalk.gray(` fix: agents routines devices ${pin.name} --set <${pin.devices.join('|')}>`));
|
|
1428
|
+
}
|
|
1429
|
+
}
|
|
1407
1430
|
return;
|
|
1408
1431
|
}
|
|
1409
1432
|
const parsed = parseTargetArg(target);
|
package/dist/commands/events.js
CHANGED
|
@@ -17,6 +17,8 @@ import chalk from 'chalk';
|
|
|
17
17
|
import * as fs from 'fs';
|
|
18
18
|
import { getLogsPath } from '../lib/events.js';
|
|
19
19
|
import { readUnifiedEvents } from '../lib/event-stream.js';
|
|
20
|
+
import { ingestBatch } from '../lib/events-ingest.js';
|
|
21
|
+
import { setHelpSections } from '../lib/help.js';
|
|
20
22
|
/**
|
|
21
23
|
* Resolve `--limit` into a record cap. `0` means "no cap" — without it there is
|
|
22
24
|
* no way to read the whole stream, and any aggregation (group-by failure, count
|
|
@@ -97,8 +99,93 @@ function renderRow(r) {
|
|
|
97
99
|
const agent = r.agent ? chalk.gray(` ${r.agent}`) : '';
|
|
98
100
|
return `${time} ${originLabel(r).padEnd(24)} ${user.padEnd(22)} ${ev.padEnd(26)}${agent} ${detailFor(r)}`;
|
|
99
101
|
}
|
|
102
|
+
/** Read all of stdin. Returns '' when nothing is piped. */
|
|
103
|
+
async function readStdin() {
|
|
104
|
+
if (process.stdin.isTTY)
|
|
105
|
+
return '';
|
|
106
|
+
const chunks = [];
|
|
107
|
+
for await (const chunk of process.stdin)
|
|
108
|
+
chunks.push(Buffer.from(chunk));
|
|
109
|
+
return Buffer.concat(chunks).toString('utf-8');
|
|
110
|
+
}
|
|
111
|
+
function registerEmitSubcommand(events) {
|
|
112
|
+
const emitCmd = events
|
|
113
|
+
.command('emit')
|
|
114
|
+
.description('Record events produced outside this process (reads JSONL on stdin)')
|
|
115
|
+
.requiredOption('--source <name>', 'Producer name; stamped as `module` so `events --module <name>` filters to it')
|
|
116
|
+
.option('--dry-run', 'Validate and report without writing')
|
|
117
|
+
.option('--json', 'Report {written, rejected} as JSON')
|
|
118
|
+
.action(async (opts, cmd) => {
|
|
119
|
+
// The parent `events` command also declares `--json` (for its read view).
|
|
120
|
+
// Commander binds a flag declared on BOTH to the parent, so a bare
|
|
121
|
+
// `events emit … --json` lands on parent.opts().json and the child sees
|
|
122
|
+
// undefined — the human string would print where a caller expects JSON.
|
|
123
|
+
// Read both, same as `feed post`.
|
|
124
|
+
const wantJson = Boolean(opts?.json ?? cmd?.parent?.opts?.().json);
|
|
125
|
+
const input = await readStdin();
|
|
126
|
+
if (input.trim() === '') {
|
|
127
|
+
console.error('events emit: nothing on stdin — pipe one JSON object per line.');
|
|
128
|
+
process.exitCode = 1;
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
let result;
|
|
132
|
+
try {
|
|
133
|
+
result = ingestBatch(input, { source: opts.source, dryRun: opts.dryRun });
|
|
134
|
+
}
|
|
135
|
+
catch (err) {
|
|
136
|
+
console.error(`events emit: ${err instanceof Error ? err.message : String(err)}`);
|
|
137
|
+
process.exitCode = 1;
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
if (wantJson) {
|
|
141
|
+
console.log(JSON.stringify({ written: result.written, rejected: result.rejected, routed: result.routed }, null, 2));
|
|
142
|
+
}
|
|
143
|
+
else if (result.rejected.length === 0) {
|
|
144
|
+
console.log(`${result.written} event(s) recorded${opts.dryRun ? ' (dry run)' : ''}.`);
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
console.log(`${result.written} event(s) recorded${opts.dryRun ? ' (dry run)' : ''}.`);
|
|
148
|
+
console.error(`rejected ${result.rejected.length} line(s):`);
|
|
149
|
+
for (const r of result.rejected)
|
|
150
|
+
console.error(` line ${r.line}: ${r.reason}`);
|
|
151
|
+
}
|
|
152
|
+
// Valid siblings are already written; a non-zero exit reports that the
|
|
153
|
+
// batch was not fully accepted without pretending nothing landed.
|
|
154
|
+
if (result.rejected.length > 0)
|
|
155
|
+
process.exitCode = 1;
|
|
156
|
+
});
|
|
157
|
+
setHelpSections(emitCmd, {
|
|
158
|
+
examples: `
|
|
159
|
+
# 1. Produce one JSON object per line (this is the whole input format).
|
|
160
|
+
printf '%s\\n' '{"event":"factory.command","commandId":"agents.newClaude"}' \\
|
|
161
|
+
| agents events emit --source factory
|
|
162
|
+
|
|
163
|
+
# 2. Flush a batch and check what landed.
|
|
164
|
+
agents events emit --source factory --json < batch.jsonl
|
|
165
|
+
|
|
166
|
+
# 3. Read it back. --limit 0 matters whenever you aggregate.
|
|
167
|
+
agents events --module factory --limit 0 --json
|
|
168
|
+
`,
|
|
169
|
+
notes: `
|
|
170
|
+
\`event\` is required and must be a known kind. \`ts\` (ISO-8601) is optional
|
|
171
|
+
and defaults to now — pass it so a batched producer records when each event
|
|
172
|
+
HAPPENED rather than when it flushed.
|
|
173
|
+
|
|
174
|
+
Envelope keys: ts, sessionId, mailboxId, terminalId, launchId, tmuxPane,
|
|
175
|
+
host, runtime, agent, tool, detail, url, project, cwd. Any other key is
|
|
176
|
+
payload and passes through the usual redaction.
|
|
177
|
+
|
|
178
|
+
A milestone kind (e.g. factory.launch) REQUIRES a sessionId — the activity
|
|
179
|
+
log is one file per session. Milestones route there; everything else goes
|
|
180
|
+
to the operational log. \`agents events\` reads both.
|
|
181
|
+
|
|
182
|
+
Rejection is per line: one bad line never discards the batch. Exit is 1 if
|
|
183
|
+
any line was rejected.
|
|
184
|
+
`,
|
|
185
|
+
});
|
|
186
|
+
}
|
|
100
187
|
export function registerEventsCommand(program) {
|
|
101
|
-
program
|
|
188
|
+
const events = program
|
|
102
189
|
.command('events')
|
|
103
190
|
.description('Read the unified event stream (operational + agent activity)')
|
|
104
191
|
.option('--module <name>', 'Only events from this group (e.g. teams, secrets, activity)')
|
|
@@ -166,6 +253,9 @@ Examples:
|
|
|
166
253
|
if (truncated)
|
|
167
254
|
console.log(chalk.yellow(capNote));
|
|
168
255
|
});
|
|
256
|
+
// `events` both reads (its own action, above) and writes (this subcommand) —
|
|
257
|
+
// the same shape as `feed` / `feed post`.
|
|
258
|
+
registerEmitSubcommand(events);
|
|
169
259
|
}
|
|
170
260
|
/** commander repeatable-option collector. */
|
|
171
261
|
function collect(value, previous) {
|
package/dist/commands/exec.js
CHANGED
|
@@ -23,6 +23,7 @@ import * as os from 'os';
|
|
|
23
23
|
import { spawnSync } from 'child_process';
|
|
24
24
|
import { randomUUID } from 'crypto';
|
|
25
25
|
import { isSessionTrackedAgent } from '../lib/session/types.js';
|
|
26
|
+
import { applyActiveRulesPresetAtRun } from '../lib/rules/run-sync.js';
|
|
26
27
|
/** Distinguish a terminal account-picker marker from an explicit @version pin. */
|
|
27
28
|
export function parseRunAccountPickerRequest(agentSpec) {
|
|
28
29
|
const requested = agentSpec.endsWith('@');
|
|
@@ -1978,6 +1979,18 @@ export function registerRunCommand(program) {
|
|
|
1978
1979
|
}
|
|
1979
1980
|
}
|
|
1980
1981
|
const defaultVersion = version ?? resolveVersion(agent, cwd);
|
|
1982
|
+
// Re-apply the active rules preset before every launch (issue: preset
|
|
1983
|
+
// changes via `setActiveRulesPreset` only took effect after an explicit
|
|
1984
|
+
// `agents rules switch` / `agents sync`). Version-scoped, skip-fast when
|
|
1985
|
+
// nothing changed — see lib/rules/run-sync.ts. Placed here (immediately
|
|
1986
|
+
// after the resolved version is known, before ACP/loop/fallback branch
|
|
1987
|
+
// off) so every downstream dispatch path for this agent+version sees a
|
|
1988
|
+
// fresh rules file, not just the plain execAgent path. `defaultVersion`
|
|
1989
|
+
// is null when nothing is installed yet — execAgent handles that error
|
|
1990
|
+
// path itself; there's no version home to sync into.
|
|
1991
|
+
if (defaultVersion) {
|
|
1992
|
+
applyActiveRulesPresetAtRun(agent, defaultVersion, getVersionHomePath(agent, defaultVersion));
|
|
1993
|
+
}
|
|
1981
1994
|
// Login preflight (advisory, warn + continue). On a local INTERACTIVE
|
|
1982
1995
|
// launch, probe whether this agent's account has a credential and print a
|
|
1983
1996
|
// one-line warning if it looks logged out — so you find out BEFORE the TUI
|