@phnx-labs/agents-cli 1.21.1 → 1.21.2
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 +172 -0
- package/README.md +1 -0
- package/dist/bin/agents +0 -0
- package/dist/commands/doctor.js +5 -2
- package/dist/commands/feed.js +28 -19
- package/dist/commands/hooks.js +9 -45
- package/dist/commands/menubar.js +24 -24
- package/dist/commands/message.js +23 -3
- package/dist/commands/perf.d.ts +13 -0
- package/dist/commands/perf.js +80 -23
- package/dist/commands/projects.d.ts +11 -0
- package/dist/commands/projects.js +153 -21
- package/dist/commands/routines.js +46 -1
- package/dist/commands/ssh.js +69 -0
- package/dist/commands/trends.d.ts +2 -0
- package/dist/commands/trends.js +158 -0
- package/dist/commands/usage.d.ts +4 -4
- package/dist/commands/view.d.ts +6 -0
- package/dist/commands/view.js +90 -45
- package/dist/index.js +14 -1
- package/dist/lib/agents.js +2 -2
- package/dist/lib/analytics/dashboard.d.ts +11 -0
- package/dist/lib/analytics/dashboard.js +31 -0
- package/dist/lib/analytics/recipes.d.ts +32 -0
- package/dist/lib/analytics/recipes.js +316 -0
- package/dist/lib/analytics/usage-db.d.ts +84 -0
- package/dist/lib/analytics/usage-db.js +301 -0
- package/dist/lib/browser/service.js +18 -0
- package/dist/lib/cli-resources.d.ts +20 -0
- package/dist/lib/cli-resources.js +48 -1
- package/dist/lib/daemon.js +51 -14
- package/dist/lib/devices/health-report.d.ts +5 -0
- package/dist/lib/devices/health-report.js +3 -0
- package/dist/lib/feed-broadcast.d.ts +52 -7
- package/dist/lib/feed-broadcast.js +125 -18
- package/dist/lib/fleet-cache.d.ts +37 -0
- package/dist/lib/fleet-cache.js +40 -0
- package/dist/lib/fleet-status.d.ts +53 -0
- package/dist/lib/fleet-status.js +120 -0
- package/dist/lib/friction-heuristics.d.ts +32 -0
- package/dist/lib/friction-heuristics.js +47 -0
- package/dist/lib/hooks/cache.js +28 -6
- package/dist/lib/hooks/profile.d.ts +8 -0
- package/dist/lib/hooks/profile.js +14 -4
- package/dist/lib/hooks.js +72 -17
- package/dist/lib/linear-cache.d.ts +63 -0
- package/dist/lib/linear-cache.js +146 -0
- package/dist/lib/linear-project-counts.d.ts +35 -5
- package/dist/lib/linear-project-counts.js +61 -16
- package/dist/lib/menubar/MenubarHelper.app/Contents/CodeResources +0 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/Info.plist +3 -1
- package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
- package/dist/lib/menubar/install-menubar.d.ts +7 -0
- package/dist/lib/menubar/install-menubar.js +36 -6
- package/dist/lib/perf/db.d.ts +6 -1
- package/dist/lib/perf/db.js +35 -5
- package/dist/lib/perf/types.d.ts +10 -0
- package/dist/lib/project-doctor.d.ts +36 -0
- package/dist/lib/project-doctor.js +45 -0
- package/dist/lib/project-import.d.ts +11 -1
- package/dist/lib/project-import.js +17 -3
- package/dist/lib/project-status.d.ts +25 -5
- package/dist/lib/project-status.js +48 -6
- package/dist/lib/rotate.d.ts +27 -0
- package/dist/lib/rotate.js +44 -17
- package/dist/lib/routines.d.ts +16 -0
- package/dist/lib/routines.js +39 -0
- package/dist/lib/runner.js +34 -0
- 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/usage-db.d.ts +3 -63
- package/dist/lib/secrets/usage-db.js +46 -186
- package/dist/lib/session/db.d.ts +2 -1
- package/dist/lib/session/db.js +14 -3
- package/dist/lib/session/discover.d.ts +3 -0
- package/dist/lib/session/discover.js +8 -0
- package/dist/lib/session/types.d.ts +1 -0
- package/dist/lib/startup/command-registry.d.ts +1 -0
- package/dist/lib/startup/command-registry.js +2 -0
- package/dist/lib/state.d.ts +31 -3
- package/dist/lib/state.js +53 -10
- package/dist/lib/types.d.ts +8 -4
- package/dist/lib/usage-refresh.d.ts +106 -0
- package/dist/lib/usage-refresh.js +238 -0
- package/dist/lib/usage.d.ts +152 -17
- package/dist/lib/usage.js +393 -79
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,177 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.21.2
|
|
4
|
+
|
|
5
|
+
- **`agents trends` — resource and session analytics dashboard.** Baked recipes
|
|
6
|
+
(harness/model mix, tools per session, token ratio, secrets/browser hot lists)
|
|
7
|
+
read `sessions.db` plus a new value-free warehouse at
|
|
8
|
+
`~/.agents/.history/analytics/usage.db`. Secrets usage migrates once from
|
|
9
|
+
`secrets.db`; agent run and browser launch/close emit into the warehouse.
|
|
10
|
+
Quota stays on `agents usage`, latency on `agents perf`.
|
|
11
|
+
Source: `apps/cli/src/commands/trends.ts`, `apps/cli/src/lib/analytics/`.
|
|
12
|
+
|
|
13
|
+
- **The macOS menu bar app is now named AGI Menu in System Settings and
|
|
14
|
+
Accessibility prompts.** Privacy & Security previously showed the executable
|
|
15
|
+
name `MenubarHelper` because the bundle had no `CFBundleDisplayName`. The
|
|
16
|
+
bundle now ships `CFBundleName` / `CFBundleDisplayName` = `AGI Menu`, and
|
|
17
|
+
`agents menubar` status/enable/disable copy uses the same name. An install
|
|
18
|
+
that was left ad-hoc-signed by an older heal path is also replaced from the
|
|
19
|
+
Developer-ID source on the next `agents` run, so Accessibility stops
|
|
20
|
+
re-prompting for a new identity every upgrade. Source:
|
|
21
|
+
`apps/cli/menubar/scripts/build.sh`, `apps/cli/src/commands/menubar.ts`,
|
|
22
|
+
`apps/cli/src/lib/menubar/install-menubar.ts`.
|
|
23
|
+
|
|
24
|
+
- **Cursor usage bars now show Auto/API/Total, and Cursor sessions carry live todo progress.** `agents view` reads Cursor's dashboard `get-current-period-usage` first for the Auto + Composer (`A`) / API (`API`) / Total (`T`) percent breakdown, falls back to `usage-summary` for accounts without a usable `planUsage`, and only drops to the legacy monthly request bar (`M`) for request-capped free/legacy plans. `agents sessions` also now folds a Cursor session's `TodoWrite` calls into `SessionMeta.todos`, so the checklist progress shown for Claude/Codex/Kimi sessions renders for Cursor too. Source: `apps/cli/src/lib/usage.ts`, `apps/cli/src/lib/session/discover.ts`.
|
|
25
|
+
|
|
26
|
+
- **`feed.broadcast` gains an in-process `channel:` sink and an implicit owner
|
|
27
|
+
fallback (RUSH-2123).** A `feed.broadcast` sink can now declare `channel: <name>`
|
|
28
|
+
(plus `to:` for a non-owner destination) instead of `command: [argv...]` — it
|
|
29
|
+
delivers through the same channel-provider registry `agents send`/`agents notify`
|
|
30
|
+
use (`deliverEnvelope()`), no spawn. `channel: owner` is the address alias,
|
|
31
|
+
expanding to `notify.owner.{channel,to}`. When an operator has `notify.owner`
|
|
32
|
+
configured but never wrote a `feed.broadcast` block at all, an important-level
|
|
33
|
+
post (`--level important`, or any `--blocked` post) now falls back to that owner
|
|
34
|
+
address automatically instead of reaching nobody — previously a `feed post
|
|
35
|
+
--blocked` with `notify.owner` set and no `feed.broadcast` looked recorded but
|
|
36
|
+
delivered to no one. A routine milestone post still stays record-only even with
|
|
37
|
+
the fallback available, and an operator-declared `feed.broadcast` always wins
|
|
38
|
+
outright. `command:` argv sinks (the tracker/webhook escape hatch) are unchanged.
|
|
39
|
+
Source: `apps/cli/src/lib/feed-broadcast.ts`, `apps/cli/src/commands/feed.ts`.
|
|
40
|
+
|
|
41
|
+
- **`agents run` no longer stalls on a live usage fetch, and the daemon keeps the
|
|
42
|
+
quota cache warm instead (RUSH-2061).** The router's candidate collection
|
|
43
|
+
(`collectRunCandidates`) used to block on a live provider HTTP read whenever an
|
|
44
|
+
account's usage snapshot was older than 5 minutes — one round trip per account
|
|
45
|
+
added to cold-start. It now reads the usage cache **cache-only** (`readOnly`) and
|
|
46
|
+
never touches the network; an unconfirmable snapshot is simply routed around by
|
|
47
|
+
the existing freshness guard (`isUsageVerified`). A new daemon refresher
|
|
48
|
+
(`runUsageRefresh`) keeps that cache fresh in the background: it refreshes only
|
|
49
|
+
accounts signed in on THIS host (sole-writer, no cross-host coordination), on an
|
|
50
|
+
adaptive cadence from each account's session-window burn rate (90s when racing
|
|
51
|
+
toward the 5h cap, up to 15min when idle), capped at ~6 provider calls per
|
|
52
|
+
account per hour and skipped entirely while a provider is under a 429 backoff.
|
|
53
|
+
Source: `apps/cli/src/lib/usage.ts`, `apps/cli/src/lib/usage-refresh.ts`,
|
|
54
|
+
`apps/cli/src/lib/rotate.ts`, `apps/cli/src/lib/daemon.ts`.
|
|
55
|
+
|
|
56
|
+
- **Balanced routing now deprioritizes an account projected to cap soon, not just
|
|
57
|
+
one already maxed (RUSH-2061).** `deriveUsageHeadroom` projects minutes-to-limit
|
|
58
|
+
from the session-window burn rate; balanced weighting scales an account's
|
|
59
|
+
headroom weight down as that projection shortens (`capacityWeight`), so a launch
|
|
60
|
+
avoids an account racing toward its 5-hour cap instead of only skipping a
|
|
61
|
+
100%-maxed one. Source: `apps/cli/src/lib/usage.ts`, `apps/cli/src/lib/rotate.ts`.
|
|
62
|
+
|
|
63
|
+
- **The daemon no longer SSH-probes the whole fleet every 3 minutes — fleet status
|
|
64
|
+
is publish-own / read-union now (RUSH-2061, RUSH-2114).** The daemon's fleet-cache
|
|
65
|
+
warm force-probed every registered device over ssh on every tick; with N daemons
|
|
66
|
+
each probing N devices that was N² remote resource probes across the fleet every
|
|
67
|
+
3 minutes, and the source of the orphaned fleet-doctor probe pile-up. Each daemon
|
|
68
|
+
now probes only **itself** (no ssh) and publishes its own row — resource stats
|
|
69
|
+
**plus live-agent workload** (running-agent count and a per-context / per-agent
|
|
70
|
+
breakdown) — to a shared local mirror (`~/.agents/.cache/.fleet-status.json`).
|
|
71
|
+
Cross-host rows are unioned on demand by the reader: `agents devices status`
|
|
72
|
+
gathers peers cache-first, ssh-reading a stale/missing peer via
|
|
73
|
+
`agents devices status --local --json` through a bounded, kill-on-timeout
|
|
74
|
+
fan-out. `agents devices status` (and `--json`) now shows how many agents are
|
|
75
|
+
running on each box. Source: `apps/cli/src/lib/fleet-status.ts`,
|
|
76
|
+
`apps/cli/src/lib/fleet-cache.ts`, `apps/cli/src/lib/daemon.ts`,
|
|
77
|
+
`apps/cli/src/lib/devices/health-report.ts`, `apps/cli/src/commands/ssh.ts`.
|
|
78
|
+
|
|
79
|
+
- **`agents doctor --json` is no longer a ~136-second stall (RUSH-2136).** The
|
|
80
|
+
overview probed every host-CLI manifest with a blocking `spawnSync` (10s timeout
|
|
81
|
+
each) one after another, so a dozen-plus slow checks summed into minutes. The
|
|
82
|
+
checks now run concurrently (`listCliStatusAsync`), so total time is the slowest
|
|
83
|
+
single check, not their sum; the per-check 10s kill-on-timeout is preserved.
|
|
84
|
+
Source: `apps/cli/src/lib/cli-resources.ts`, `apps/cli/src/commands/doctor.ts`.
|
|
85
|
+
|
|
86
|
+
- **Metrics foundation: hook/command instrumentation + routine metrics.** Every
|
|
87
|
+
hook now instruments through a generated shim — `matcher:`-only hooks like
|
|
88
|
+
git-guard/rm-guard/git-require-clean-tree previously fired with zero perf
|
|
89
|
+
samples; `agents perf hooks` now reports them. `agents perf` gains
|
|
90
|
+
`--project <key>` (scope to one repo), a `P95` column alongside P50/P99, and
|
|
91
|
+
an `ERR/TIMEOUT` rate column. New `agents perf friction` surfaces sessions
|
|
92
|
+
stuck repeatedly hitting the same guard block instead of adapting. New
|
|
93
|
+
`agents routines stats [name]` reports run count/failed/missed/avg/p50/p95
|
|
94
|
+
duration per routine; `agents routines runs --json` now includes `duration`.
|
|
95
|
+
Routine session transcripts are now archived for gemini/antigravity/droid/
|
|
96
|
+
kimi/grok routines, not just claude/codex/cursor. Source:
|
|
97
|
+
`apps/cli/src/lib/hooks.ts`, `apps/cli/src/lib/perf/db.ts`,
|
|
98
|
+
`apps/cli/src/commands/perf.ts`, `apps/cli/src/lib/routines.ts`,
|
|
99
|
+
`apps/cli/src/lib/runner.ts`.
|
|
100
|
+
|
|
101
|
+
- **The Linear line on `agents projects status` is cached, and stops vanishing.** The card
|
|
102
|
+
paged every issue in a project on every invocation — up to 10 requests per project — against
|
|
103
|
+
a 2500/hour request budget that an agent running `status` in a loop exhausts. Answers are now
|
|
104
|
+
cached on disk for 10 minutes (`~/.agents/.cache/linear-projects/`, one file per project written
|
|
105
|
+
by atomic rename so concurrent agent sessions cannot clobber each other), so a repeated
|
|
106
|
+
`status` spends zero Linear requests. More importantly, a failed or rate-limited fetch now
|
|
107
|
+
serves the last good answer marked stale instead of dropping the line: a populated Linear row
|
|
108
|
+
silently disappearing on one 8s timeout was the observed defect, and it is the same rule
|
|
109
|
+
`mergeAuthHealthEntries` already keeps for account health. A 429 records its
|
|
110
|
+
`x-ratelimit-requests-reset` so later runs don't spend a request to be told there are none
|
|
111
|
+
left. Source: `apps/cli/src/lib/linear-cache.ts`.
|
|
112
|
+
|
|
113
|
+
- **The compact `projects status` card shows the milestone it calls `next`.** Milestones are
|
|
114
|
+
listed in date order, and Linear can flag a later-dated one as next — so slicing the front
|
|
115
|
+
of the list showed an earlier milestone while burying the actual next under `+N more`, which
|
|
116
|
+
is the one thing that row exists to say. The next milestone now leads, and identity is
|
|
117
|
+
matched on name plus target date rather than name alone (two milestones can share a name,
|
|
118
|
+
which put the `next` label on the wrong row). Source: `apps/cli/src/commands/projects.ts`.
|
|
119
|
+
|
|
120
|
+
- **`agents projects` stops reading the wrong GitHub repository.** Factory derives a
|
|
121
|
+
project's `owner/repo` from the checkout path's last two segments, so a repo cloned to
|
|
122
|
+
`~/src/github.com/<you>/agents-cli` whose origin is `phnx-labs/agents-cli` imported as
|
|
123
|
+
`<you>/agents-cli`. Both are real repositories, so nothing errored — the card's merged-PR
|
|
124
|
+
and release lines simply reported a stranger's repo (0 merges in 7 days instead of 100).
|
|
125
|
+
`import --from-factory` now reads the checkout's actual `origin` and only falls back to the
|
|
126
|
+
path guess when there is no remote to ask, and `status`/`show` print a warning with the fix
|
|
127
|
+
when a stored slug disagrees with the remote. Source: `apps/cli/src/lib/project-doctor.ts`.
|
|
128
|
+
- **`agents projects set <name>` changes one field without destroying the rest.** Previously
|
|
129
|
+
the only ways to correct a field were `$EDITOR` on raw YAML or `add --force`, which rebuilds
|
|
130
|
+
the definition from flags alone and silently drops `linear`, `contexts`, and `description`.
|
|
131
|
+
`set` loads, patches the named field, and writes back. Flags: `--repo`, `--root`, `--path`,
|
|
132
|
+
`--description`. Source: `apps/cli/src/commands/projects.ts`.
|
|
133
|
+
- **Merged-PR counts say when they are a lower bound.** The `gh` fetch caps at 100, and a busy
|
|
134
|
+
repo where all 100 land inside the window has more — the count now renders `100+` rather than
|
|
135
|
+
presenting the cap as a total, matching the existing Linear `2500+` contract. Source:
|
|
136
|
+
`apps/cli/src/lib/project-status.ts`.
|
|
137
|
+
|
|
138
|
+
- **`agents projects view <name>`** replaces `show` (kept as an alias) and now renders the
|
|
139
|
+
project's full plan: every declared Linear milestone with its date and progress, issue
|
|
140
|
+
counts, and a warning when no issues are assigned to any milestone — a milestone nothing is
|
|
141
|
+
filed against cannot report progress, and a row of silent `0%`s hid that. Sixteen other
|
|
142
|
+
command groups already use `view <name>`; `projects` was the only one that did not. Source:
|
|
143
|
+
`apps/cli/src/commands/projects.ts`.
|
|
144
|
+
- **The status headline counts live agents, not corpses.** It read `39 agents` on a project
|
|
145
|
+
where 19 had crashed. It now reads `19 live`, with a separate `dead` row breaking down what
|
|
146
|
+
finished or was lost — 19 crashed sessions is a thing to go fix, not throughput. `orphaned`
|
|
147
|
+
counts as **live**: `session/active.ts` defines it as "alive, but no client is attached", and
|
|
148
|
+
the repo's own dead rule is `closed` + `crashed` only. Source:
|
|
149
|
+
`apps/cli/src/lib/project-status.ts`.
|
|
150
|
+
- **`planPct` is gone from the card and from `--json`.** It summed each matched session's most
|
|
151
|
+
recent checklist snapshot, so one agent opening a fresh 40-item plan rendered the whole
|
|
152
|
+
project `0% plan`, and a project where nobody had written a checklist showed no figure at
|
|
153
|
+
all. A cross-session sum of ad-hoc checklists does not measure project progress. `live` and
|
|
154
|
+
`dead` counts replace it in `--json`.
|
|
155
|
+
- **The next milestone comes from Linear's own `status: "next"`** when Linear sets it, falling
|
|
156
|
+
back to earliest-dated-unfinished only when nothing is flagged — Linear's answer is the one
|
|
157
|
+
shown in its UI, ours is a guess.
|
|
158
|
+
|
|
159
|
+
- **A regression guard for the distributed `--active --local` / `--host` session-query paths, wired into CI (#1866).** RUSH-2118 fixed a `--local` query dialing remote-host teammates over real ssh, but nothing bench-guarded the fix's latency, and the `--host` cross-fleet fan-out had no bench at all. `bench/sessions-active-perf.ts` times `AgentManager(..., localOnly=true).listAll()` against N synthetic remote-host teammates (asserting zero ssh calls and sub-500ms latency, with a positive-control run proving the ssh-PATH shim actually intercepts) and the `gatherActiveSessions({ hosts })` fan-out against N synthetic peers (asserting it stays parallel, not sequential). Wired into `.github/workflows/bench.yml` as the one gating step in that workflow — every other bench step stays `continue-on-error`. Documented with measured baselines in `apps/cli/docs/05-sessions.md#benchmarks`. Source: `apps/cli/bench/sessions-active-perf.ts`, `.github/workflows/bench.yml`.
|
|
160
|
+
|
|
161
|
+
- **`agents view` columns stay aligned across agents, and usage no longer piles up (view-ui-perf).**
|
|
162
|
+
The multi-agent overview padded every row to the widest usage string — an
|
|
163
|
+
Antigravity account with four model quotas forced ~194-column lines that
|
|
164
|
+
wrapped so `rate-limited` and last-active drifted under the version column.
|
|
165
|
+
Overview now caps compact meters to two windows (`+N` for the rest), always
|
|
166
|
+
emits fixed account/usage/status/lastActive columns (empty cells space-padded),
|
|
167
|
+
and measures padding with `stringWidth` so chalk + block bars don't skew
|
|
168
|
+
gutters. Usage fetches go through one unified core: 5-minute fresh cache
|
|
169
|
+
(was 2), concurrency-capped live reads (`USAGE_FETCH_CONCURRENCY=3`),
|
|
170
|
+
single-flight per identity, and a background SWR queue capped at 2 so delayed
|
|
171
|
+
HTTP responses cannot stack. Spinner stays up through account+usage load.
|
|
172
|
+
Source: `apps/cli/src/commands/view.ts`, `apps/cli/src/lib/usage.ts`,
|
|
173
|
+
`apps/cli/src/lib/agents.ts`.
|
|
174
|
+
|
|
3
175
|
## 1.21.1
|
|
4
176
|
|
|
5
177
|
- **Feed posts require a title + body; phone `{message}` ends with a Sent-from footer.** `agents feed post --title "Short subject" "body text"` — title is the phone first line (~4–5 words), body follows after a blank line, then `Sent from <agent>/<session-chunk> on <host>` (like "Sent from my iPhone"). Em/en dashes in title/body are scrubbed to ASCII ` - `. Source: `apps/cli/src/lib/feed-broadcast.ts`, `feed-post.ts`, `commands/feed.ts`.
|
package/README.md
CHANGED
|
@@ -875,6 +875,7 @@ agents routines add daily-digest \
|
|
|
875
875
|
agents routines list # All jobs + next run times
|
|
876
876
|
agents routines run daily-digest # Test it now, ignore the schedule
|
|
877
877
|
agents routines logs daily-digest # Last execution — status + report (add --full for raw stdout)
|
|
878
|
+
agents routines stats # Run count, failed, missed, avg/p50/p95 duration — per job or all
|
|
878
879
|
|
|
879
880
|
# Routines sync to every device; restrict to an allowlist with --devices
|
|
880
881
|
agents routines add nightly-drain --schedule "0 3 * * *" --agent claude \
|
package/dist/bin/agents
CHANGED
|
Binary file
|
package/dist/commands/doctor.js
CHANGED
|
@@ -25,7 +25,7 @@ import { isVersionIsolated } from '../lib/versions.js';
|
|
|
25
25
|
import { computeDrift, checkSyncStatus, countOrphans, computeSourceBehind } from '../lib/drift.js';
|
|
26
26
|
import { readAuthHealthCache, summarizeHostAuth } from '../lib/auth-health.js';
|
|
27
27
|
import { unifiedDiff, colorizeUnifiedDiff } from '../lib/diff-text.js';
|
|
28
|
-
import { listCliStatus } from '../lib/cli-resources.js';
|
|
28
|
+
import { listCliStatus, listCliStatusAsync } from '../lib/cli-resources.js';
|
|
29
29
|
import { setHelpSections } from '../lib/help.js';
|
|
30
30
|
import { heal, healChangedAnything } from '../lib/heal.js';
|
|
31
31
|
import { getEffectiveExecutionPolicy } from '../lib/platform/winpath.js';
|
|
@@ -1291,7 +1291,10 @@ export function registerDoctorCommand(program) {
|
|
|
1291
1291
|
const clis = checkAllClis();
|
|
1292
1292
|
const syncRows = checkSyncStatus(cwd);
|
|
1293
1293
|
const orphanRows = countOrphans();
|
|
1294
|
-
|
|
1294
|
+
// Parallel host-CLI probe (RUSH-2136): the serial spawnSync version ran a
|
|
1295
|
+
// dozen+ blocking 10s-timeout checks one after another, which measured
|
|
1296
|
+
// ~136s on an idle box and stalled the menu-bar helper's poll.
|
|
1297
|
+
const hostClis = await listCliStatusAsync(cwd);
|
|
1295
1298
|
const repoBehindMarkers = readRepoBehindMarkers();
|
|
1296
1299
|
// The local inventory now carries per-version sign-in (RUSH-2069), so it
|
|
1297
1300
|
// is the single source for both the accounts line and the logged-out
|
package/dist/commands/feed.js
CHANGED
|
@@ -2,7 +2,7 @@ import chalk from 'chalk';
|
|
|
2
2
|
import { ensureFeedPublishHook, listAskStats, listBlocks, recordNotified, buildDeclaredBlock, publishBlock, } from '../lib/feed.js';
|
|
3
3
|
import { ensureActivityLogHook, readRecentActivity, formatActivityLine, formatProgressUpdate, mergeActivityEvents, parseActivityPayload, } from '../lib/activity.js';
|
|
4
4
|
import { postFeedStatus } from '../lib/feed-post.js';
|
|
5
|
-
import { parseFeedPostLevel, planFeedBroadcast, runFeedBroadcast, blockBroadcastContext, blockDeliveryFailure, } from '../lib/feed-broadcast.js';
|
|
5
|
+
import { parseFeedPostLevel, planFeedBroadcast, runFeedBroadcast, effectiveBroadcastConfig, blockBroadcastContext, blockDeliveryFailure, } from '../lib/feed-broadcast.js';
|
|
6
6
|
import { getSessionById } from '../lib/session/db.js';
|
|
7
7
|
import { readMeta } from '../lib/state.js';
|
|
8
8
|
import { enrichBlocksFromSessions, groupBlocksByOutcome, isUnambiguousOutcomeAnswer, openBlocksForOutcome, stampBlockOutcomes, } from '../lib/feed-outcome.js';
|
|
@@ -274,7 +274,7 @@ time. No em-dashes in title/body - they are scrubbed on the way out.
|
|
|
274
274
|
Configure where a post is mirrored under feed.broadcast in agents.yaml - see
|
|
275
275
|
docs/06-observability.md.
|
|
276
276
|
`)
|
|
277
|
-
.action((textParts, opts, cmd) => {
|
|
277
|
+
.action(async (textParts, opts, cmd) => {
|
|
278
278
|
// Parent `feed` also declares `--json` (for the list view). Commander
|
|
279
279
|
// binds the flag on the parent, so a `feed post … --json` lands on
|
|
280
280
|
// parent.opts().json — not the child. Read both.
|
|
@@ -303,6 +303,7 @@ docs/06-observability.md.
|
|
|
303
303
|
throw new Error('Missing --title. Usage: agents feed post --title "Short subject" "body text"');
|
|
304
304
|
}
|
|
305
305
|
const level = flags.blocked ? 'important' : parseFeedPostLevel(flags.level);
|
|
306
|
+
const meta = readMeta();
|
|
306
307
|
const { event } = postFeedStatus({
|
|
307
308
|
title: flags.title,
|
|
308
309
|
text: Array.isArray(textParts) ? textParts.join(' ') : String(textParts ?? ''),
|
|
@@ -325,15 +326,15 @@ docs/06-observability.md.
|
|
|
325
326
|
safeDefault: flags.default,
|
|
326
327
|
});
|
|
327
328
|
publishBlock(block);
|
|
328
|
-
outcomes = broadcastBlock(block, {
|
|
329
|
+
outcomes = await broadcastBlock(block, {
|
|
329
330
|
project: event.project,
|
|
330
331
|
agent: event.agent,
|
|
331
332
|
title: event.title,
|
|
332
333
|
body: event.detail,
|
|
333
|
-
});
|
|
334
|
+
}, meta);
|
|
334
335
|
}
|
|
335
336
|
else {
|
|
336
|
-
outcomes = broadcastPostedEvent(event, level);
|
|
337
|
+
outcomes = await broadcastPostedEvent(event, level, meta);
|
|
337
338
|
}
|
|
338
339
|
// Fail loud when a block reached nobody. This is computed BEFORE the
|
|
339
340
|
// --json early return: a machine caller is exactly the one that reads the
|
|
@@ -562,15 +563,21 @@ docs/06-observability.md.
|
|
|
562
563
|
}
|
|
563
564
|
/**
|
|
564
565
|
* Mirror a written post to the configured sinks (`feed.broadcast` in
|
|
565
|
-
* agents.yaml
|
|
566
|
-
*
|
|
567
|
-
*
|
|
568
|
-
*
|
|
569
|
-
*
|
|
566
|
+
* agents.yaml, or the implicit `notify.owner` fallback for an important post —
|
|
567
|
+
* see {@link effectiveBroadcastConfig}). The ticket is JOINED from the session
|
|
568
|
+
* index rather than asked for as a flag — it is a domain fact about the
|
|
569
|
+
* session, and an agent that has to remember a `--ticket` argument is an agent
|
|
570
|
+
* that will forget it. Returns the per-sink outcomes; an empty array means
|
|
571
|
+
* nothing is configured and no fallback applies, which is not a failure for a
|
|
572
|
+
* routine post (see `blockDeliveryFailure` for the `--blocked` case).
|
|
573
|
+
*
|
|
574
|
+
* `meta` is threaded in rather than read here so the fallback/config decision
|
|
575
|
+
* and the delivery are pinned to one config snapshot, and so this is testable
|
|
576
|
+
* against a real in-memory `Meta` without touching `~/.agents/agents.yaml`.
|
|
570
577
|
*/
|
|
571
|
-
function broadcastPostedEvent(event, level) {
|
|
572
|
-
const config =
|
|
573
|
-
if (!config
|
|
578
|
+
async function broadcastPostedEvent(event, level, meta) {
|
|
579
|
+
const config = effectiveBroadcastConfig(meta.feed?.broadcast, level, meta);
|
|
580
|
+
if (!config)
|
|
574
581
|
return [];
|
|
575
582
|
const ticket = getSessionById(event.sessionId)?.ticketId;
|
|
576
583
|
const planned = planFeedBroadcast(config, {
|
|
@@ -586,22 +593,24 @@ function broadcastPostedEvent(event, level) {
|
|
|
586
593
|
.map((a) => a.href)
|
|
587
594
|
.filter((href) => /^https?:\/\//i.test(href)),
|
|
588
595
|
});
|
|
589
|
-
return runFeedBroadcast(planned);
|
|
596
|
+
return runFeedBroadcast(planned, meta);
|
|
590
597
|
}
|
|
591
598
|
/**
|
|
592
|
-
* Mirror a declared block to the same sinks a post reaches
|
|
599
|
+
* Mirror a declared block to the same sinks a post reaches (plus the implicit
|
|
600
|
+
* `notify.owner` fallback — a block is always `important`, so it always
|
|
601
|
+
* qualifies).
|
|
593
602
|
*
|
|
594
603
|
* Blocks previously never broadcast at all: `broadcastPostedEvent` ran only for
|
|
595
604
|
* `feed post`, while every `publishBlock` call wrote to the ledger and stopped
|
|
596
605
|
* there — so a "needs you" record was durable and invisible at the same time.
|
|
597
606
|
*/
|
|
598
|
-
function broadcastBlock(block, extras) {
|
|
599
|
-
const config =
|
|
600
|
-
if (!config
|
|
607
|
+
async function broadcastBlock(block, extras, meta) {
|
|
608
|
+
const config = effectiveBroadcastConfig(meta.feed?.broadcast, 'important', meta);
|
|
609
|
+
if (!config)
|
|
601
610
|
return [];
|
|
602
611
|
const ticket = getSessionById(block.sessionId)?.ticketId;
|
|
603
612
|
const ctx = blockBroadcastContext({ ...block, ticket: block.ticket ?? ticket }, extras);
|
|
604
|
-
return runFeedBroadcast(planFeedBroadcast(config, ctx));
|
|
613
|
+
return runFeedBroadcast(planFeedBroadcast(config, ctx), meta);
|
|
605
614
|
}
|
|
606
615
|
/** One line per sink that ran. Silent when nothing is configured. */
|
|
607
616
|
function reportBroadcast(outcomes) {
|
package/dist/commands/hooks.js
CHANGED
|
@@ -617,61 +617,25 @@ Examples:
|
|
|
617
617
|
A hook whose p99 exceeds --warn-ms gets flagged in the cache column. Add
|
|
618
618
|
'cache: 5m' or 'cache: 5m-bg' to its hooks.yaml entry to fix it.
|
|
619
619
|
`)
|
|
620
|
+
.option('--project <key>', 'Scope to one project (see agents perf --help)')
|
|
620
621
|
.action(async (options) => {
|
|
621
|
-
const {
|
|
622
|
-
|
|
622
|
+
const { DEFAULT_SLOW_HOOK_WARN_MS } = await import('../lib/hooks/profile.js');
|
|
623
|
+
// Same rollup as `agents perf hooks` — this command predates the `perf`
|
|
624
|
+
// surface and is kept as a documented alias; delegate instead of
|
|
625
|
+
// duplicating the SQLite-vs-legacy-JSONL fallback and table rendering.
|
|
626
|
+
const { loadHookProfile, renderHookTable } = await import('./perf.js');
|
|
623
627
|
const days = Math.max(1, parseInt(options.days, 10) || 7);
|
|
624
628
|
const warnMs = Math.max(0, parseInt(options.warnMs, 10) || DEFAULT_SLOW_HOOK_WARN_MS);
|
|
625
|
-
|
|
626
|
-
const fromDb = aggregateSamples({ days, kinds: ['hook.fire'] }).map((r) => ({
|
|
627
|
-
hook: r.label,
|
|
628
|
-
n: r.n,
|
|
629
|
-
p50Ms: r.p50Ms,
|
|
630
|
-
p99Ms: r.p99Ms,
|
|
631
|
-
meanMs: r.meanMs,
|
|
632
|
-
maxMs: r.maxMs,
|
|
633
|
-
cacheHitPct: r.cacheHitPct ?? 0,
|
|
634
|
-
cacheStalePct: r.cacheStalePct ?? 0,
|
|
635
|
-
cacheMissPct: r.cacheMissPct ?? 0,
|
|
636
|
-
errorCount: r.errorCount ?? 0,
|
|
637
|
-
}));
|
|
638
|
-
const rows = fromDb.length > 0 ? fromDb : aggregateHookProfile(loadHookFireEvents(days));
|
|
629
|
+
const rows = loadHookProfile(days, options.project);
|
|
639
630
|
if (options.json) {
|
|
640
631
|
console.log(JSON.stringify(rows, null, 2));
|
|
641
632
|
return;
|
|
642
633
|
}
|
|
643
634
|
if (rows.length === 0) {
|
|
644
635
|
console.log(chalk.gray(`No hook.fire samples in the last ${days} day${days === 1 ? '' : 's'}.`));
|
|
645
|
-
console.log(chalk.gray('
|
|
636
|
+
console.log(chalk.gray('Every hook now instruments via a generated shim (cache:, matches:, or a bare matcher:) — resync hooks if this is unexpectedly empty.'));
|
|
646
637
|
return;
|
|
647
638
|
}
|
|
648
|
-
|
|
649
|
-
const pad = (s, w) => (s.length >= w ? s.slice(0, w) : s + ' '.repeat(w - s.length));
|
|
650
|
-
const header = [
|
|
651
|
-
pad('HOOK', widths.hook),
|
|
652
|
-
pad('N', widths.n),
|
|
653
|
-
pad('P50', widths.p50),
|
|
654
|
-
pad('P99', widths.p99),
|
|
655
|
-
pad('MEAN', widths.mean),
|
|
656
|
-
pad('MAX', widths.max),
|
|
657
|
-
pad('CACHE', widths.cache),
|
|
658
|
-
].join(' ');
|
|
659
|
-
console.log(chalk.bold(header));
|
|
660
|
-
console.log(chalk.gray('─'.repeat(header.length)));
|
|
661
|
-
for (const r of rows) {
|
|
662
|
-
const slow = r.p99Ms > warnMs;
|
|
663
|
-
const cacheCol = formatCacheColumn(r);
|
|
664
|
-
const warning = slow && r.cacheHitPct + r.cacheStalePct === 0 ? ' ← add cache: 5m' : '';
|
|
665
|
-
const line = [
|
|
666
|
-
pad(r.hook, widths.hook),
|
|
667
|
-
pad(String(r.n), widths.n),
|
|
668
|
-
pad(formatMs(r.p50Ms), widths.p50),
|
|
669
|
-
pad(formatMs(r.p99Ms), widths.p99),
|
|
670
|
-
pad(formatMs(r.meanMs), widths.mean),
|
|
671
|
-
pad(formatMs(r.maxMs), widths.max),
|
|
672
|
-
pad(cacheCol, widths.cache),
|
|
673
|
-
].join(' ') + warning;
|
|
674
|
-
console.log(slow ? chalk.yellow(line) : line);
|
|
675
|
-
}
|
|
639
|
+
renderHookTable(rows, warnMs);
|
|
676
640
|
});
|
|
677
641
|
}
|
package/dist/commands/menubar.js
CHANGED
|
@@ -11,7 +11,7 @@ import { setHelpSections } from '../lib/help.js';
|
|
|
11
11
|
import { enableMenubarService, disableMenubarService, getMenubarStatus, runMenubarSetup, } from '../lib/menubar/install-menubar.js';
|
|
12
12
|
function notMac() {
|
|
13
13
|
if (process.platform !== 'darwin') {
|
|
14
|
-
console.log(chalk.yellow('
|
|
14
|
+
console.log(chalk.yellow('AGI Menu is macOS only.'));
|
|
15
15
|
return true;
|
|
16
16
|
}
|
|
17
17
|
return false;
|
|
@@ -19,7 +19,7 @@ function notMac() {
|
|
|
19
19
|
/** Shared status readout — `status`, bare `menubar`, and `setup --check` all end here. */
|
|
20
20
|
function printStatus(s, opts = {}) {
|
|
21
21
|
const yn = (b) => (b ? chalk.green('yes') : chalk.gray('no'));
|
|
22
|
-
console.log(chalk.bold('Menu
|
|
22
|
+
console.log(chalk.bold('AGI Menu\n'));
|
|
23
23
|
console.log(` running ${yn(s.running)}`);
|
|
24
24
|
console.log(` service installed ${yn(s.serviceInstalled)}`);
|
|
25
25
|
if (opts.brief) {
|
|
@@ -34,7 +34,7 @@ function printStatus(s, opts = {}) {
|
|
|
34
34
|
// Two copies of the INSTALLED bundle is the duplicate the user sees as two
|
|
35
35
|
// agents marks in the menu bar. It used to read as a healthy `running: yes`.
|
|
36
36
|
if (s.instances.length > 1) {
|
|
37
|
-
console.log(chalk.yellow(`\n ${s.instances.length} copies of
|
|
37
|
+
console.log(chalk.yellow(`\n ${s.instances.length} copies of AGI Menu are running — that is the duplicate menu-bar icon:`));
|
|
38
38
|
for (const p of s.instances)
|
|
39
39
|
console.log(chalk.gray(` ${p.pid} ${p.executable}`));
|
|
40
40
|
console.log(chalk.gray(' Fix it with `agents menubar setup`.'));
|
|
@@ -45,20 +45,20 @@ function printStatus(s, opts = {}) {
|
|
|
45
45
|
// was — only that a rival exists — so report the conflict, not a winner.
|
|
46
46
|
// The loser has no other symptom: its chords simply never fire.
|
|
47
47
|
const n = s.foreignInstances.length;
|
|
48
|
-
console.log(chalk.yellow(`\n ${n} other
|
|
48
|
+
console.log(chalk.yellow(`\n ${n} other AGI Menu process${n === 1 ? '' : 'es'} running — ${n === 1 ? 'it' : 'they'} may hold Cmd-Shift-V/O instead of the installed one:`));
|
|
49
49
|
for (const p of s.foreignInstances)
|
|
50
50
|
console.log(chalk.gray(` ${p.pid} ${p.executable}`));
|
|
51
51
|
console.log(chalk.gray(' End them with `agents menubar setup`.'));
|
|
52
52
|
}
|
|
53
53
|
if (s.stale) {
|
|
54
|
-
console.log(chalk.yellow('\n Installed
|
|
54
|
+
console.log(chalk.yellow('\n Installed AGI Menu is stale — runs on next `agents` startup, or `agents menubar setup` now.'));
|
|
55
55
|
}
|
|
56
56
|
else if (!s.serviceInstalled && !s.disabledByUser) {
|
|
57
57
|
console.log(chalk.gray('\n Set it up with `agents menubar setup`.'));
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
60
|
function printSetupResult(r) {
|
|
61
|
-
console.log(chalk.bold('Menu
|
|
61
|
+
console.log(chalk.bold('AGI Menu setup\n'));
|
|
62
62
|
for (const step of r.steps) {
|
|
63
63
|
const mark = step.outcome === 'failed' ? chalk.red('✗')
|
|
64
64
|
: step.outcome === 'changed' ? chalk.green('+') : chalk.green('✓');
|
|
@@ -66,22 +66,22 @@ function printSetupResult(r) {
|
|
|
66
66
|
}
|
|
67
67
|
console.log();
|
|
68
68
|
if (r.configured) {
|
|
69
|
-
console.log(chalk.green('Menu
|
|
69
|
+
console.log(chalk.green('AGI Menu configured.') + chalk.gray(' One agents mark, started at login.'));
|
|
70
70
|
}
|
|
71
71
|
else {
|
|
72
|
-
console.log(chalk.red('Menu
|
|
72
|
+
console.log(chalk.red('AGI Menu not fully configured.') + chalk.gray(' See the failed step above.'));
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
75
|
export function registerMenubarCommands(program) {
|
|
76
76
|
const menubar = program
|
|
77
77
|
.command('menubar')
|
|
78
|
-
.description('Manage
|
|
78
|
+
.description('Manage AGI Menu (running sessions, agents awaiting input, routines)');
|
|
79
79
|
// `setup` is the one command that gets a machine to the intended state:
|
|
80
80
|
// exactly one status item, started at login. `enable` stays the narrow
|
|
81
81
|
// install+start; setup adds duplicate cleanup and verifies the end state.
|
|
82
82
|
const setup = menubar
|
|
83
83
|
.command('setup')
|
|
84
|
-
.description('Configure
|
|
84
|
+
.description('Configure AGI Menu end-to-end: one instance, started at login')
|
|
85
85
|
.option('--check', 'Report the current state, change nothing')
|
|
86
86
|
.option('--json', 'Emit machine-readable JSON')
|
|
87
87
|
.action((options) => {
|
|
@@ -110,7 +110,7 @@ export function registerMenubarCommands(program) {
|
|
|
110
110
|
});
|
|
111
111
|
setHelpSections(setup, {
|
|
112
112
|
examples: `
|
|
113
|
-
# Configure
|
|
113
|
+
# Configure AGI Menu end-to-end (idempotent — safe to re-run)
|
|
114
114
|
agents menubar setup
|
|
115
115
|
|
|
116
116
|
# Two agents marks in the menu bar? This ends the duplicate.
|
|
@@ -120,44 +120,44 @@ export function registerMenubarCommands(program) {
|
|
|
120
120
|
agents menubar setup --check
|
|
121
121
|
`,
|
|
122
122
|
notes: `
|
|
123
|
-
Configures, in order: every running helper ended,
|
|
124
|
-
~/Library/Application Support/agents-cli, its code
|
|
125
|
-
login item (com.phnx-labs.agents-menubar —
|
|
126
|
-
verifies exactly one helper came back up.
|
|
123
|
+
Configures, in order: every running helper ended, AGI Menu at
|
|
124
|
+
~/Library/Application Support/agents-cli/MenubarHelper.app, its code
|
|
125
|
+
signature, the launchd login item (com.phnx-labs.agents-menubar —
|
|
126
|
+
RunAtLoad + KeepAlive), then verifies exactly one helper came back up.
|
|
127
127
|
|
|
128
128
|
Every running helper is ended and launchd restarts one, so the survivor is
|
|
129
129
|
always the login-managed copy. Exits nonzero if it cannot reach that state.
|
|
130
130
|
|
|
131
|
-
Setup clears a previous \`agents menubar disable\`. To turn
|
|
131
|
+
Setup clears a previous \`agents menubar disable\`. To turn AGI Menu off
|
|
132
132
|
again, run \`agents menubar disable\`.
|
|
133
133
|
`,
|
|
134
134
|
});
|
|
135
135
|
menubar
|
|
136
136
|
.command('enable')
|
|
137
|
-
.description('Install and start
|
|
137
|
+
.description('Install and start AGI Menu (launches at login)')
|
|
138
138
|
.action(() => {
|
|
139
139
|
if (notMac())
|
|
140
140
|
return;
|
|
141
141
|
const ok = enableMenubarService({ clearOptOut: true });
|
|
142
142
|
if (!ok) {
|
|
143
|
-
console.log(chalk.red('Could not enable: no
|
|
143
|
+
console.log(chalk.red('Could not enable: no AGI Menu bundle ships with this install.'));
|
|
144
144
|
console.log(chalk.gray(' This build may predate the helper, or be a non-macOS package.'));
|
|
145
145
|
return;
|
|
146
146
|
}
|
|
147
|
-
console.log(chalk.green('Menu
|
|
147
|
+
console.log(chalk.green('AGI Menu enabled.') + chalk.gray(' Look for the agents mark in your menu bar.'));
|
|
148
148
|
});
|
|
149
149
|
menubar
|
|
150
150
|
.command('disable')
|
|
151
|
-
.description('Stop and remove
|
|
151
|
+
.description('Stop and remove AGI Menu (stays off across upgrades)')
|
|
152
152
|
.action(() => {
|
|
153
153
|
if (notMac())
|
|
154
154
|
return;
|
|
155
155
|
disableMenubarService();
|
|
156
|
-
console.log(chalk.green('Menu
|
|
156
|
+
console.log(chalk.green('AGI Menu disabled.') + chalk.gray(' Re-enable any time with `agents menubar setup`.'));
|
|
157
157
|
});
|
|
158
158
|
menubar
|
|
159
159
|
.command('status')
|
|
160
|
-
.description('Show whether
|
|
160
|
+
.description('Show whether AGI Menu is installed and running')
|
|
161
161
|
.option('--json', 'Emit machine-readable JSON')
|
|
162
162
|
.action((options) => {
|
|
163
163
|
const s = getMenubarStatus();
|
|
@@ -166,7 +166,7 @@ export function registerMenubarCommands(program) {
|
|
|
166
166
|
return;
|
|
167
167
|
}
|
|
168
168
|
if (s.platform !== 'darwin') {
|
|
169
|
-
console.log(chalk.yellow('
|
|
169
|
+
console.log(chalk.yellow('AGI Menu is macOS only.'));
|
|
170
170
|
return;
|
|
171
171
|
}
|
|
172
172
|
printStatus(s);
|
|
@@ -175,7 +175,7 @@ export function registerMenubarCommands(program) {
|
|
|
175
175
|
menubar.action(() => {
|
|
176
176
|
const s = getMenubarStatus();
|
|
177
177
|
if (s.platform !== 'darwin') {
|
|
178
|
-
console.log(chalk.yellow('
|
|
178
|
+
console.log(chalk.yellow('AGI Menu is macOS only.'));
|
|
179
179
|
return;
|
|
180
180
|
}
|
|
181
181
|
printStatus(s, { brief: true });
|
package/dist/commands/message.js
CHANGED
|
@@ -12,6 +12,7 @@ import { blockIdForSession, listBlocks, readBlock, recordAnswer, recordMessageRe
|
|
|
12
12
|
import { verifyOperatorIdentity } from '../lib/operator.js';
|
|
13
13
|
import { resolveAnswerRoute, resumeArgv, } from '../lib/answer-router.js';
|
|
14
14
|
import { injectIntoTerminal } from '../lib/terminal/inject.js';
|
|
15
|
+
import { setHelpSections } from '../lib/help.js';
|
|
15
16
|
/** Find the still-open block addressed to `mailboxId`, if any. */
|
|
16
17
|
function findOpenBlockForMailbox(mailboxId) {
|
|
17
18
|
// Fast path: the mailbox id is usually the session id, so the block id is
|
|
@@ -111,15 +112,34 @@ async function deliverViaResume(route, mailboxId) {
|
|
|
111
112
|
console.log(chalk.green(`Resumed ${mailboxId} with answer. `) +
|
|
112
113
|
chalk.dim(route.reason));
|
|
113
114
|
}
|
|
115
|
+
/**
|
|
116
|
+
* `message` is the agent-control plane (RUSH-2123): the answer/keystroke/
|
|
117
|
+
* injected input a running agent consumes, never a notification a human reads.
|
|
118
|
+
* Mirrors SHARED_NOTES in commands/send.ts so an agent reading either --help
|
|
119
|
+
* sees the same three-plane map and doesn't reach for `message` when it means
|
|
120
|
+
* `send`/`notify`.
|
|
121
|
+
*/
|
|
122
|
+
const CONTROL_PLANE_NOTES = `
|
|
123
|
+
Planes (do not mix them up):
|
|
124
|
+
message / sessions inject - CONTROL a running agent (mailbox answer, PTY keystroke, or resume by runtime)
|
|
125
|
+
send / notify - DELIVER a message to a human recipient over a channel provider
|
|
126
|
+
feed post - RECORD progress / milestones (optional broadcast may call send/notify)
|
|
127
|
+
|
|
128
|
+
<text> here is consumed BY THE TARGET AGENT (an answer, a keystroke, or the
|
|
129
|
+
argument to a resume) -- it is not a notification a person reads on their
|
|
130
|
+
phone. To reach the operator instead, use \`agents send\` / \`agents notify\`
|
|
131
|
+
(or a feed.broadcast \`channel:\` sink).
|
|
132
|
+
`;
|
|
114
133
|
export function registerMessageCommand(program) {
|
|
115
|
-
program
|
|
134
|
+
const messageCmd = program
|
|
116
135
|
.command('message <target> <text>')
|
|
117
136
|
.description('Send a message to a running or parked agent (mailbox / PTY-select / resume by runtime).')
|
|
118
137
|
.option('--from <who>', 'Label recorded as the sender of this message')
|
|
119
138
|
.option('--as <operator>', 'Verified operator id answering a high-consequence block')
|
|
120
139
|
.option('--surface <surface>', 'Surface that is sending this answer (feed, terminal, etc.)', 'cli')
|
|
121
|
-
.option('--ttl <dur>', 'Delivery TTL if the message is not consumed (e.g. 30m, 1h, 24h); 0 disables expiry')
|
|
122
|
-
|
|
140
|
+
.option('--ttl <dur>', 'Delivery TTL if the message is not consumed (e.g. 30m, 1h, 24h); 0 disables expiry');
|
|
141
|
+
setHelpSections(messageCmd, { notes: CONTROL_PLANE_NOTES });
|
|
142
|
+
messageCmd.action(async (target, text, opts) => {
|
|
123
143
|
if (!target.trim()) {
|
|
124
144
|
die('Target must be a session/agent id or cloud task id. Run `agents sessions --active` to list running agents.');
|
|
125
145
|
}
|
package/dist/commands/perf.d.ts
CHANGED
|
@@ -6,9 +6,22 @@
|
|
|
6
6
|
* agents perf hooks per-hook p50/p99 + cache hit rates
|
|
7
7
|
* agents perf commands slowest CLI command paths (from command.end)
|
|
8
8
|
* agents perf run agent.run / perf.timing labels
|
|
9
|
+
* agents perf friction sessions stuck repeatedly hitting the same guard
|
|
9
10
|
*
|
|
10
11
|
* Soft-joins sessions.db via shared string keys (session_id, agent, machine) —
|
|
11
12
|
* no foreign keys. Warehouse lives at ~/.agents/.cache/perf/perf.db (safe to wipe).
|
|
12
13
|
*/
|
|
13
14
|
import type { Command } from 'commander';
|
|
15
|
+
import { type PerfAggregateRow } from '../lib/perf/db.js';
|
|
16
|
+
import { type HookProfileRow } from '../lib/hooks/profile.js';
|
|
17
|
+
/** Map warehouse rows shaped like hook.fire into the existing HookProfileRow UI. */
|
|
18
|
+
export declare function asHookRows(rows: PerfAggregateRow[]): HookProfileRow[];
|
|
19
|
+
export declare function renderHookTable(rows: HookProfileRow[], warnMs: number): void;
|
|
20
|
+
/**
|
|
21
|
+
* Prefer SQLite samples; fall back to the legacy daily JSONL so existing
|
|
22
|
+
* instrumentation still surfaces until shims are resynced. `project` only
|
|
23
|
+
* narrows the SQLite path — the legacy JSONL log has no cwd, so a fallback
|
|
24
|
+
* hit ignores it (a caller filtering by project has no legacy rows to miss).
|
|
25
|
+
*/
|
|
26
|
+
export declare function loadHookProfile(days: number, project?: string): HookProfileRow[];
|
|
14
27
|
export declare function registerPerfCommand(program: Command): void;
|