@phnx-labs/agents-cli 1.22.8 → 1.22.9
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 +53 -0
- package/README.md +5 -0
- package/dist/bin/agents +0 -0
- package/dist/commands/exec.js +41 -9
- package/dist/commands/feed.js +38 -1
- package/dist/commands/harness.d.ts +40 -1
- package/dist/commands/harness.js +316 -76
- package/dist/commands/profiles.d.ts +42 -0
- package/dist/commands/profiles.js +91 -3
- package/dist/commands/sessions-picker.js +3 -3
- package/dist/commands/sessions-render.d.ts +12 -0
- package/dist/commands/sessions-render.js +124 -0
- package/dist/commands/sessions.js +28 -1
- package/dist/commands/ssh.js +26 -3
- package/dist/commands/teams.js +12 -1
- package/dist/index.js +9 -2
- package/dist/lib/crabbox/cli.d.ts +35 -0
- package/dist/lib/crabbox/cli.js +46 -0
- package/dist/lib/crabbox/config.d.ts +21 -0
- package/dist/lib/crabbox/config.js +43 -0
- package/dist/lib/crabbox/lease.d.ts +15 -5
- package/dist/lib/crabbox/lease.js +57 -17
- package/dist/lib/daemon.js +12 -11
- package/dist/lib/devices/resolve-target.d.ts +4 -3
- package/dist/lib/devices/resolve-target.js +4 -3
- package/dist/lib/hosts/passthrough.js +18 -1
- package/dist/lib/hosts/registry.d.ts +4 -0
- package/dist/lib/hosts/registry.js +16 -0
- package/dist/lib/hosts/remote-cmd.js +1 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/CodeResources +0 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
- package/dist/lib/observe-aliases.d.ts +30 -0
- package/dist/lib/observe-aliases.js +56 -0
- package/dist/lib/redact.js +4 -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/session/parse.d.ts +5 -1
- package/dist/lib/session/parse.js +23 -13
- package/dist/lib/session/prompt.js +5 -0
- package/dist/lib/session/render.d.ts +3 -0
- package/dist/lib/session/render.js +33 -10
- package/dist/lib/startup/command-registry.js +15 -1
- package/dist/lib/usage-refresh.d.ts +19 -11
- package/dist/lib/usage-refresh.js +75 -43
- package/dist/lib/usage.d.ts +12 -0
- package/dist/lib/usage.js +37 -6
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,56 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.22.9
|
|
4
|
+
|
|
5
|
+
- **`agents ssh auto` and `agents teams add --device auto` no longer reject with "Unknown device 'auto'" (RUSH-2185).** The `auto` affinity sentinel was a `run`-only preprocessing step (`applyDeviceAutoToOptions` in `smart-launch.ts`, wired only from `agents run`'s exec path) — every other `--host`/`--device` caller went straight to the shared resolver, which had no idea what `auto` meant and reported it as an unregistered device. `matchHost` (the one core every `--host`/`--device` caller shares) now resolves `auto` directly via the same `resolveDeviceAffinity` engine `run` uses, so `agents ssh`, `agents teams add`, and anything else routed through `matchHost`/`resolveHost` (including the generic `--host`/`--device` passthrough) pick a device the same way. `agents teams add --device auto` landing on the local machine now just runs the teammate locally, matching `run`'s "null pick = local" outcome; `agents ssh auto` refuses a local pick with a clear message instead of self-SSHing, since `agents ssh` exists to dial OUT to a remote box. Source: `apps/cli/src/lib/hosts/registry.ts`, `apps/cli/src/lib/devices/resolve-target.ts`, `apps/cli/src/commands/ssh.ts`, `apps/cli/src/commands/teams.ts`, `apps/cli/docs/00-concepts.md`, `apps/cli/docs/hosts.md`, `apps/cli/docs/teams.md`.
|
|
6
|
+
|
|
7
|
+
- **`agents harness edit` gains `--auth-provider`, `--fallback-model`, and `--from-secrets`; `add`/`fork` gain an interactive wizard and `--from-secrets`.** `edit` (already shipped with `--model`/`--base-url`/`--version`/`--description`) now also repoints auth at a different keychain-backed provider, sets or clears (`--fallback-model ""`) the same-host fallback model retried on a rate limit, and — like `add`/`fork` — accepts `--from-secrets <bundle>[:<key>]` to copy a value out of an existing `agents secrets` bundle into the harness's own keychain item once, instead of retyping a key already stored elsewhere (the item it writes to, `agents-cli.<provider>.token`, is never gated behind the biometry-required prefixes, so later reads stay silent). `agents harness add`/`fork` now accept `[name]`/`[source] [name]` as optional positionals — run either with insufficient flags in an interactive terminal and a picker (fork from a native host or existing harness → a built-in preset or "build custom" → the harness's name, pre-filled with the preset's own name → how to get the key) replaces the old hard error; flags remain fully supported for scripts, and a non-interactive shell still gets the original error. Source: `apps/cli/src/commands/harness.ts`, `apps/cli/src/commands/profiles.ts`, `apps/cli/docs/profiles.md`.
|
|
8
|
+
|
|
9
|
+
- **`agents run --lease` is reuse-first against the crabbox profile pool, with a
|
|
10
|
+
`--fresh` opt-out.** A bare `--lease` used to always lease a brand-new box, so
|
|
11
|
+
bursts of runs (e.g. resumed sessions) stacked up idle `keep=true` boxes at
|
|
12
|
+
full monthly cost. Now, before warming a new box, the run looks for a warm box
|
|
13
|
+
carrying the same `profile` label the warmup would use (read from the repo's
|
|
14
|
+
`.crabbox.yaml`, matching `scripts/sandbox.sh`'s `pick_ready_box`) and the same
|
|
15
|
+
network mode — a tailnet box is never handed to a public run or vice versa —
|
|
16
|
+
and reuses the first one `crabbox status` reports SSH-ready, keeping it after
|
|
17
|
+
the run. A not-ready pool box is skipped, never stopped. `--fresh` forces the
|
|
18
|
+
old behavior (brand-new box, torn down after the run); `--box <slug>` is
|
|
19
|
+
unchanged. Source: `apps/cli/src/lib/crabbox/lease.ts`,
|
|
20
|
+
`apps/cli/src/lib/crabbox/cli.ts`, `apps/cli/src/lib/crabbox/config.ts`,
|
|
21
|
+
`apps/cli/src/commands/exec.ts`.
|
|
22
|
+
|
|
23
|
+
- **The menu bar now notices and reports when the scheduler dies — instead of
|
|
24
|
+
staying silent forever.** The only proactive "routines overdue / scheduler
|
|
25
|
+
down" signal was `notifyOverdue` (`src/lib/overdue.ts`), fired from inside
|
|
26
|
+
`runDaemon()` — so it could never fire while the daemon itself was down, the
|
|
27
|
+
exact outage it exists to report. `MenubarHelper` is a separate launchd
|
|
28
|
+
KeepAlive service that stays alive when the daemon dies, so its 10s tick now
|
|
29
|
+
polls daemon liveness independently of the dropdown ever being opened; once
|
|
30
|
+
it has been continuously unreachable for ~30s (debounced past a routine
|
|
31
|
+
restart blip), it fires one native notification ("Scheduler stopped —
|
|
32
|
+
routines won't run") through its own `NSUserNotificationCenter` delivery —
|
|
33
|
+
no daemon, no CLI spawn required — and lights the always-visible menu-bar
|
|
34
|
+
badge (`⏻`) until the scheduler comes back. Source:
|
|
35
|
+
`apps/cli/menubar/Sources/MenubarHelper/StatusItemController.swift`.
|
|
36
|
+
|
|
37
|
+
- **Observe umbrella aliases: `inbox`, `timeline`, `roster` (Phase 3 surface consolidation).**
|
|
38
|
+
Thin doors onto existing readers (no store merge): `agents inbox` ≡ `feed`,
|
|
39
|
+
`agents timeline` ≡ `feed --filter updates`, `agents roster` ≡ `sessions --active`.
|
|
40
|
+
Root help gains an Observe section; `agents audit` stays the tamper-evident run
|
|
41
|
+
log (not an events alias). Source: `apps/cli/src/lib/observe-aliases.ts`,
|
|
42
|
+
`apps/cli/src/commands/feed.ts`, `apps/cli/src/commands/sessions.ts`.
|
|
43
|
+
|
|
44
|
+
- **Daemon usage refresh is a fixed 5-minute per-host schedule, concurrency-safe, and Touch-ID-free.**
|
|
45
|
+
Each machine's daemon still owns its own usage cache (no fleet-wide store). Account live
|
|
46
|
+
fetches are now scheduled every **5 minutes** (was adaptive 90s–15m), with a 60s wake to
|
|
47
|
+
notice due accounts after backoff ends. Cache writes use a file lock + atomic rename so a
|
|
48
|
+
concurrent `agents view` background refresh cannot tear or drop rows. The daemon path
|
|
49
|
+
loads Claude credentials with **`fileOnly`** (setup-token / no-ACL cache / `.credentials.json`
|
|
50
|
+
only) and never opens the ACL-bound macOS keychain item, so a background tick cannot pop
|
|
51
|
+
Touch ID. Refresh still skips a provider under 429 backoff and still never rotates
|
|
52
|
+
single-use Claude refresh tokens.
|
|
53
|
+
|
|
3
54
|
## 1.22.8
|
|
4
55
|
|
|
5
56
|
- **`agents browser` now gates cross-machine drives behind per-device consent.** `agents browser <cmd> --host <device>` already routes a browser command to another fleet machine over SSH and drives its browser — but nothing asked that machine's permission, so any box you could SSH to, you could drive. A new device-local `browser.remote-control` setting (off by default, never synced) fixes that: a fleet-remote `browser --host <this-machine> start` is refused with an actionable message until the owner runs `agents browser remote-control on` here. Local starts (no `--host`) are never gated. The fleet passthrough marks every `--host` dispatch with `AGENTS_FLEET_REMOTE` so the far side can tell a cross-machine drive from a local one. New command: `agents browser remote-control [on|off]` (no arg prints status; `--json` supported). Source: `apps/cli/src/lib/browser/remote-control.ts`, `apps/cli/src/commands/browser.ts`, `apps/cli/src/lib/hosts/passthrough.ts`, `apps/cli/src/lib/device-config.ts`, `apps/cli/docs/browser.md`.
|
|
@@ -983,6 +1034,8 @@
|
|
|
983
1034
|
|
|
984
1035
|
## 1.20.92
|
|
985
1036
|
|
|
1037
|
+
- **`agents sessions render <id...>` produces shareable, redacted Markdown instead of raw harness JSONL.** Claude, Codex, Kimi, Grok, Cursor, and Droid transcripts flow through the existing normalized `SessionEvent[]` parsers, then render with the same session-browser preview at the top, ordered user/assistant turns, fenced shell commands, JSON tool arguments, and explicitly truncated tool results. Redaction remains on by default through the canonical redactor, now also masking Unix/macOS/Windows home-directory identities and live secret values; `--no-redact` is local-only. Reasoning defaults to omitted and can be folded or included explicitly. One or several selected sessions can be written to a mode-`0600` Markdown file, and `--json` exposes the rendered documents for machine callers. The repo session skill and transcript-sharing guidance now require rendering `.md` before creating a confidential gist. Source: `apps/cli/src/commands/sessions-render.ts`, `apps/cli/src/lib/session/render.ts`, `apps/cli/src/lib/redact.ts`, `.agents/skills/sessions/SKILL.md`.
|
|
1038
|
+
|
|
986
1039
|
- **`agents sessions` rows show creation time as well as last activity (RUSH-2107).**
|
|
987
1040
|
The trailing time cell used to carry one unlabeled "X ago" — last activity — so a
|
|
988
1041
|
row could not say when the session began or how long it had been alive. It now
|
package/README.md
CHANGED
|
@@ -255,6 +255,9 @@ agents sessions --project my-app
|
|
|
255
255
|
# Read a full conversation
|
|
256
256
|
agents sessions a1b2c3d4 --markdown
|
|
257
257
|
|
|
258
|
+
# Render a shareable, redacted Markdown transcript with the session preview on top
|
|
259
|
+
agents sessions render a1b2c3d4 -o session.md
|
|
260
|
+
|
|
258
261
|
# Just the last 3 turns, user messages only
|
|
259
262
|
agents sessions a1b2c3d4 --last 3 --include user
|
|
260
263
|
|
|
@@ -323,6 +326,8 @@ Each live session resolves to `working`, `waiting_input` (with why -- a question
|
|
|
323
326
|
|
|
324
327
|
Landing on a session cold? `agents sessions <id>` prints a catch-up digest: an inferred title, files changed grouped by directory (created / modified / deleted), a histogram of which tools did the work (including parsed Bash commands -- `git`, `npm`, `ffmpeg`, `ssh`, and so on), and the last test verdict -- the signals to reload a task in seconds.
|
|
325
328
|
|
|
329
|
+
Sharing a session uses `agents sessions render <id> -o session.md`, not the raw harness JSONL. The document starts with that same preview, then presents user and assistant turns, fenced commands, structured tool arguments, and bounded tool output. Credential-shaped values and local home paths are redacted by default; `--no-redact` is for local-only inspection.
|
|
330
|
+
|
|
326
331
|
### Resume anywhere — and stay resumed
|
|
327
332
|
|
|
328
333
|
Pick up any past conversation and drop it back into a terminal:
|
package/dist/bin/agents
CHANGED
|
Binary file
|
package/dist/commands/exec.js
CHANGED
|
@@ -560,9 +560,10 @@ export function registerRunCommand(program) {
|
|
|
560
560
|
.option('--no-follow', 'With --host, dispatch detached and return immediately (track via `agents hosts ps/logs`).')
|
|
561
561
|
.option('--any', 'With --host <cap> (a capability tag), pick any matching host instead of erroring when several match.')
|
|
562
562
|
.option('--copy-creds', 'With --host, copy the picked runtime credentials (and Claude OAuth token) to the host, then shred them after the run. Opt-in per run.')
|
|
563
|
-
.option('--lease [backend]',
|
|
563
|
+
.option('--lease [backend]', "Run on a cloud box (via crabbox) and tear it down after — reuses a warm box from the repo's profile pool when one is ready (--fresh forces a new box). Optional backend selects the cloud (hetzner/aws/do). Same as --where lease[:backend]. Unlike --host, no machine is registered.")
|
|
564
564
|
.option('--box <slug>', 'Reuse an existing warm crabbox box for this run instead of provisioning a disposable --lease box.')
|
|
565
565
|
.option('--keep-box', 'With --lease, keep the box after the run instead of stopping it.')
|
|
566
|
+
.option('--fresh', "With --lease, always provision a brand-new box (skip the warm profile-pool reuse) and tear it down after the run.")
|
|
566
567
|
.option('--reuse', 'With --lease, reuse the most-recently-used warm box if one exists (else provision fresh). The scriptable form of the interactive reuse picker.')
|
|
567
568
|
.option('--bare', 'With --lease, skip copying your local ~/.agents setup (skills/hooks/commands/MCP) onto the box.')
|
|
568
569
|
.option('--tailscale', 'Lease the box onto your tailnet (reachable only over Tailscale) rather than a public IP.')
|
|
@@ -621,6 +622,14 @@ export function registerRunCommand(program) {
|
|
|
621
622
|
# Inject a keychain-backed secrets bundle
|
|
622
623
|
agents run claude "deploy the worker" --secrets prod --mode edit
|
|
623
624
|
|
|
625
|
+
# Run on a cloud box — reuses a warm box from the repo's profile pool when
|
|
626
|
+
# one is ready (kept after the run), else leases a fresh box, torn down after
|
|
627
|
+
agents run claude "fix the failing tests" --lease
|
|
628
|
+
|
|
629
|
+
# Force a brand-new box (destroyed after), or target a warm box by slug
|
|
630
|
+
agents run claude "fix the failing tests" --lease --fresh
|
|
631
|
+
agents run claude "fix the failing tests" --box warm-one
|
|
632
|
+
|
|
624
633
|
# Pass arbitrary native flags to the underlying CLI via -- separator
|
|
625
634
|
agents run kimi -- --plan --some-kimi-option value
|
|
626
635
|
agents run claude "fix the bug" -- --custom-flag
|
|
@@ -824,6 +833,14 @@ export function registerRunCommand(program) {
|
|
|
824
833
|
console.error(chalk.red('Pass either --lease to provision a disposable box, or --box <slug> to reuse a warm box — not both.'));
|
|
825
834
|
process.exit(1);
|
|
826
835
|
}
|
|
836
|
+
if (options.fresh && options.box) {
|
|
837
|
+
console.error(chalk.red('--fresh forces a brand-new box; it cannot be combined with --box <slug> (which reuses one).'));
|
|
838
|
+
process.exit(1);
|
|
839
|
+
}
|
|
840
|
+
if (options.fresh && options.reuse) {
|
|
841
|
+
console.error(chalk.red('--fresh forces a brand-new box; it cannot be combined with --reuse.'));
|
|
842
|
+
process.exit(1);
|
|
843
|
+
}
|
|
827
844
|
const backend = typeof options.lease === 'string' ? options.lease : undefined;
|
|
828
845
|
// crabbox syncs this directory to the box via `git ls-files`; outside a
|
|
829
846
|
// git repo that fails with "build sync file list: exit status 128" — but
|
|
@@ -848,12 +865,21 @@ export function registerRunCommand(program) {
|
|
|
848
865
|
// ── F3 reuse (RUSH-1922) + F5 net-mode (RUSH-1924) ───────────────────
|
|
849
866
|
// Resolve which box this run targets and how it is networked BEFORE any
|
|
850
867
|
// provisioning. `--box` is an explicit reuse; otherwise, on an
|
|
851
|
-
// interactive tty, offer the warm boxes as a reuse picker
|
|
852
|
-
//
|
|
868
|
+
// interactive tty, offer the warm boxes as a reuse picker. Headless runs
|
|
869
|
+
// never block: leaseAndRun itself is reuse-first against the profile
|
|
870
|
+
// pool (a ready pool box is reused; none ready → warm a fresh one).
|
|
871
|
+
// `--fresh` opts out of every reuse path.
|
|
853
872
|
const leaseSecretsBundle = process.env.AGENTS_LEASE_SECRETS_BUNDLE;
|
|
854
873
|
const nowSecs = Math.floor(Date.now() / 1000);
|
|
855
874
|
let reuseSlug = options.box;
|
|
856
|
-
|
|
875
|
+
// The profile this run's pool/box carries: the repo's .crabbox.yaml
|
|
876
|
+
// `profile:` when declared (what crabbox warmup would label a fresh box
|
|
877
|
+
// with), else crabbox's default. Passing it to leaseAndRun makes the
|
|
878
|
+
// pool-reuse match interchangeable with a fresh warmup.
|
|
879
|
+
const repoRoot = gitToplevel(leaseCwd);
|
|
880
|
+
const { readCrabboxRepoProfile } = await import('../lib/crabbox/config.js');
|
|
881
|
+
const poolProfile = repoRoot ? readCrabboxRepoProfile(repoRoot) : undefined;
|
|
882
|
+
if (options.lease && !reuseSlug && !options.fresh) {
|
|
857
883
|
const { crabboxList } = await import('../lib/crabbox/cli.js');
|
|
858
884
|
const { reusableBoxes, formatBoxRow } = await import('./lease.js');
|
|
859
885
|
let warm = [];
|
|
@@ -861,9 +887,8 @@ export function registerRunCommand(program) {
|
|
|
861
887
|
warm = reusableBoxes(crabboxList({ secretsBundle: leaseSecretsBundle }), nowSecs);
|
|
862
888
|
}
|
|
863
889
|
catch {
|
|
864
|
-
warm = []; // crabbox unavailable / no creds →
|
|
890
|
+
warm = []; // crabbox unavailable / no creds → the pool check in leaseAndRun decides
|
|
865
891
|
}
|
|
866
|
-
const repoRoot = gitToplevel(leaseCwd);
|
|
867
892
|
const alwaysFresh = repoRoot ? isAlwaysFreshRepo(readAlwaysFreshRepos(), repoRoot) : false;
|
|
868
893
|
if (warm.length > 0 && !alwaysFresh) {
|
|
869
894
|
if (options.reuse) {
|
|
@@ -896,7 +921,8 @@ export function registerRunCommand(program) {
|
|
|
896
921
|
console.error(chalk.yellow('Selection cancelled — provisioning a fresh box.'));
|
|
897
922
|
}
|
|
898
923
|
}
|
|
899
|
-
// Headless with no --reuse falls through here →
|
|
924
|
+
// Headless with no --reuse falls through here → leaseAndRun's
|
|
925
|
+
// profile-pool check decides (reuse a ready pool box, else warm fresh).
|
|
900
926
|
}
|
|
901
927
|
else if (options.reuse && warm.length > 0) {
|
|
902
928
|
// --reuse still honors a warm box even when the picker is suppressed.
|
|
@@ -1015,12 +1041,16 @@ export function registerRunCommand(program) {
|
|
|
1015
1041
|
: `${runtime} credentials`;
|
|
1016
1042
|
const boxLifecycle = reuseSlug
|
|
1017
1043
|
? `Reusing crabbox box ${reuseSlug}`
|
|
1018
|
-
:
|
|
1044
|
+
: options.fresh
|
|
1045
|
+
? `Leasing a fresh ${backend ?? 'hetzner'} box${netMode === 'tailscale' ? ' on your tailnet' : ''}`
|
|
1046
|
+
: `Leasing a ${backend ?? 'hetzner'} box${netMode === 'tailscale' ? ' on your tailnet' : ''} (a ready box from the '${poolProfile ?? 'default'}' pool is reused when one exists)`;
|
|
1019
1047
|
const boxAfterRun = reuseSlug
|
|
1020
1048
|
? 'the box is kept after the run'
|
|
1021
1049
|
: options.keepBox
|
|
1022
1050
|
? 'the box is kept after the run'
|
|
1023
|
-
:
|
|
1051
|
+
: options.fresh
|
|
1052
|
+
? 'the box is destroyed after the run'
|
|
1053
|
+
: 'a fresh box is destroyed after the run; a reused pool box is kept';
|
|
1024
1054
|
console.error(chalk.gray(`${boxLifecycle} · shipping ${whatShips}${credentialRuntimes.length > 0 && leaseEmail ? ` (${leaseEmail})` : ''}; ${boxAfterRun}.`));
|
|
1025
1055
|
// Read the Claude OAuth token from the local Keychain (silent) so it can be
|
|
1026
1056
|
// written to ~/.claude/.credentials.json on the box — otherwise Claude boots
|
|
@@ -1100,6 +1130,8 @@ export function registerRunCommand(program) {
|
|
|
1100
1130
|
secretsBundle: leaseSecretsBundle,
|
|
1101
1131
|
keep: options.keepBox,
|
|
1102
1132
|
reuseBox: reuseSlug,
|
|
1133
|
+
fresh: options.fresh,
|
|
1134
|
+
profile: poolProfile,
|
|
1103
1135
|
copySetup,
|
|
1104
1136
|
netMode,
|
|
1105
1137
|
onData: (chunk) => router.push(chunk),
|
package/dist/commands/feed.js
CHANGED
|
@@ -222,7 +222,7 @@ export function sessionHintsFromActive(sessions) {
|
|
|
222
222
|
export function registerFeedCommand(program) {
|
|
223
223
|
const feed = program
|
|
224
224
|
.command('feed')
|
|
225
|
-
.description('
|
|
225
|
+
.description('Operator inbox + agent status posts (aliases: inbox = needs-you; timeline = --filter updates)')
|
|
226
226
|
.option('--json', 'Output as JSON (each block stamped with its outcome + ask class)')
|
|
227
227
|
.option('--filter <view>', 'What to show: needs (default) · updates · all', 'needs')
|
|
228
228
|
.option('--flat', 'List one block per agent instead of grouping by outcome')
|
|
@@ -572,6 +572,43 @@ docs/06-observability.md.
|
|
|
572
572
|
renderOutcomeGroup(g, self);
|
|
573
573
|
await renderTrailingActivity();
|
|
574
574
|
});
|
|
575
|
+
// Observe-umbrella aliases (Phase 3): intentional second names, not deprecations.
|
|
576
|
+
// Re-parse into `feed` so flags/help stay single-sourced. See lib/observe-aliases.ts.
|
|
577
|
+
registerFeedObserveAliases(program);
|
|
578
|
+
}
|
|
579
|
+
/**
|
|
580
|
+
* `inbox` / `timeline` → feed. Loaded with the feed module so lazy COMMAND_LOADERS
|
|
581
|
+
* for those names also get the real `feed` command registered for re-parse.
|
|
582
|
+
*/
|
|
583
|
+
function registerFeedObserveAliases(program) {
|
|
584
|
+
const reparse = async (alias) => {
|
|
585
|
+
const { expandObserveAlias } = await import('../lib/observe-aliases.js');
|
|
586
|
+
const rest = process.argv.slice(3);
|
|
587
|
+
const expanded = expandObserveAlias(alias, rest);
|
|
588
|
+
if (!expanded) {
|
|
589
|
+
console.error(chalk.red(`Unknown observe alias: ${alias}`));
|
|
590
|
+
process.exit(1);
|
|
591
|
+
}
|
|
592
|
+
if (process.stderr.isTTY)
|
|
593
|
+
process.stderr.write(chalk.gray(`${expanded.note}\n`));
|
|
594
|
+
await program.parseAsync(['node', 'agents', ...expanded.argv]);
|
|
595
|
+
};
|
|
596
|
+
program
|
|
597
|
+
.command('inbox')
|
|
598
|
+
.description('Needs-you inbox (alias of `agents feed`). Open blocks waiting on you.')
|
|
599
|
+
.allowUnknownOption()
|
|
600
|
+
.allowExcessArguments()
|
|
601
|
+
.action(async () => {
|
|
602
|
+
await reparse('inbox');
|
|
603
|
+
});
|
|
604
|
+
program
|
|
605
|
+
.command('timeline')
|
|
606
|
+
.description('Agent progress stream (alias of `agents feed --filter updates`). What agents posted recently.')
|
|
607
|
+
.allowUnknownOption()
|
|
608
|
+
.allowExcessArguments()
|
|
609
|
+
.action(async () => {
|
|
610
|
+
await reparse('timeline');
|
|
611
|
+
});
|
|
575
612
|
}
|
|
576
613
|
/**
|
|
577
614
|
* Mirror a written post to the configured sinks (`feed.broadcast` in
|
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
* native harness registry. The `agents profiles` tree stays unchanged.
|
|
12
12
|
*/
|
|
13
13
|
import type { Command } from 'commander';
|
|
14
|
-
import { type
|
|
14
|
+
import { type AddProfileOptions } from './profiles.js';
|
|
15
|
+
import { type Profile, type ForkProfileOptions } from '../lib/profiles.js';
|
|
15
16
|
/**
|
|
16
17
|
* Print one custom harness. Shared by `agents harness view <name>` and by
|
|
17
18
|
* `agents view <name>` — a custom harness resolves as an agent type there, so
|
|
@@ -25,9 +26,25 @@ export interface ForkOptions {
|
|
|
25
26
|
authProvider?: string;
|
|
26
27
|
version?: string;
|
|
27
28
|
description?: string;
|
|
29
|
+
/** `<bundle>` or `<bundle>:<key>` — see {@link applyFromSecrets} in ./profiles.js. */
|
|
30
|
+
fromSecrets?: string;
|
|
28
31
|
keyStdin?: boolean;
|
|
29
32
|
force?: boolean;
|
|
30
33
|
}
|
|
34
|
+
/** Options accepted by `agents harness edit`. */
|
|
35
|
+
export interface EditOptions {
|
|
36
|
+
model?: string;
|
|
37
|
+
baseUrl?: string;
|
|
38
|
+
authProvider?: string;
|
|
39
|
+
/** Empty string ('') unpins the host CLI version. */
|
|
40
|
+
version?: string;
|
|
41
|
+
description?: string;
|
|
42
|
+
/** Empty string ('') clears the fallback model. */
|
|
43
|
+
fallbackModel?: string;
|
|
44
|
+
/** `<bundle>` or `<bundle>:<key>` — see {@link applyFromSecrets} in ./profiles.js. */
|
|
45
|
+
fromSecrets?: string;
|
|
46
|
+
keyStdin?: boolean;
|
|
47
|
+
}
|
|
31
48
|
/**
|
|
32
49
|
* Build the new harness for `agents harness fork <source> <name>`.
|
|
33
50
|
*
|
|
@@ -37,4 +54,26 @@ export interface ForkOptions {
|
|
|
37
54
|
* copy a model from.
|
|
38
55
|
*/
|
|
39
56
|
export declare function buildFork(source: string, name: string, opts: ForkOptions): Profile;
|
|
57
|
+
/** Map `agents harness edit` flags onto {@link ForkProfileOptions} — the same
|
|
58
|
+
* override shape `editProfile`/`forkProfile` apply. `--version ''` (unpin) is
|
|
59
|
+
* handled by the caller ({@link buildEdit}), not here: `forkProfile`'s own
|
|
60
|
+
* ternary treats an empty string as "no override" and would otherwise inherit
|
|
61
|
+
* the source's version instead of clearing it. */
|
|
62
|
+
export declare function buildEditOverrides(opts: EditOptions): ForkProfileOptions;
|
|
63
|
+
/** True when at least one recognized edit flag was given. */
|
|
64
|
+
export declare function hasEditFlags(opts: EditOptions): boolean;
|
|
65
|
+
/**
|
|
66
|
+
* Build the edited harness for `agents harness edit <name>` — the profile-shape
|
|
67
|
+
* transform only; the caller applies `--from-secrets`/`--auth-provider` (async
|
|
68
|
+
* keychain side effects) and persists with `writeProfile`. Mirrors
|
|
69
|
+
* {@link buildFork}'s split between a pure builder and the action's IO.
|
|
70
|
+
*/
|
|
71
|
+
export declare function buildEdit(name: string, opts: EditOptions): Profile;
|
|
72
|
+
/** True when `agents harness fork` was given too little to proceed without the wizard. */
|
|
73
|
+
export declare function forkNeedsWizard(source: string | undefined, name: string | undefined, opts: ForkOptions): boolean;
|
|
74
|
+
/** True when `agents harness add` was given too little to proceed without the wizard.
|
|
75
|
+
* Mirrors {@link addProfile}'s own error condition in ./profiles.js so a bare
|
|
76
|
+
* `agents harness add <preset-name>` (no flags) still resolves via the preset
|
|
77
|
+
* fallback instead of being routed into the wizard. */
|
|
78
|
+
export declare function addNeedsWizard(name: string | undefined, opts: AddProfileOptions): boolean;
|
|
40
79
|
export declare function registerHarnessCommands(program: Command): void;
|