@phnx-labs/agents-cli 1.22.47 → 1.22.50
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 +503 -17
- package/README.md +76 -32
- package/dist/bootstrap.js +4 -2
- package/dist/cli/command-registry.d.ts +1 -0
- package/dist/cli/command-registry.js +2 -0
- package/dist/commands/accounts.d.ts +58 -0
- package/dist/commands/accounts.js +201 -39
- package/dist/commands/artifacts.js +7 -6
- package/dist/commands/attach.js +1 -1
- package/dist/commands/browser.js +501 -103
- package/dist/commands/config.d.ts +0 -1
- package/dist/commands/config.js +0 -20
- package/dist/commands/daemon-test-harness.d.ts +42 -0
- package/dist/commands/daemon-test-harness.js +90 -0
- package/dist/commands/daemon.d.ts +21 -0
- package/dist/commands/daemon.js +147 -12
- package/dist/commands/device-config-test-harness.d.ts +11 -0
- package/dist/commands/device-config-test-harness.js +59 -0
- package/dist/commands/exec.js +76 -16
- package/dist/commands/focus.d.ts +14 -0
- package/dist/commands/focus.js +48 -5
- package/dist/commands/go.d.ts +3 -0
- package/dist/commands/go.js +16 -3
- package/dist/commands/inspect.js +2 -2
- package/dist/commands/lease.d.ts +1 -1
- package/dist/commands/lease.js +4 -3
- package/dist/commands/mailboxes.js +4 -3
- package/dist/commands/menubar.js +11 -4
- package/dist/commands/projects.d.ts +16 -1
- package/dist/commands/projects.js +58 -64
- package/dist/commands/resume.js +1 -1
- package/dist/commands/route.js +4 -4
- package/dist/commands/routines.js +3 -2
- package/dist/commands/run-broadcast.d.ts +1 -1
- package/dist/commands/run-broadcast.js +1 -1
- package/dist/commands/sessions-picker.d.ts +22 -0
- package/dist/commands/sessions-picker.js +48 -9
- package/dist/commands/sessions-trace.js +1 -1
- package/dist/commands/sessions.js +1 -0
- package/dist/commands/setup-secrets.js +23 -0
- package/dist/commands/share.d.ts +20 -5
- package/dist/commands/share.js +158 -53
- package/dist/commands/ssh.js +54 -7
- package/dist/commands/teams.d.ts +12 -0
- package/dist/commands/teams.js +44 -67
- package/dist/commands/traces.d.ts +2 -0
- package/dist/commands/traces.js +188 -0
- package/dist/commands/view.d.ts +1 -1
- package/dist/commands/view.js +17 -34
- package/dist/index.d.ts +1 -0
- package/dist/index.js +5 -0
- package/dist/lib/account-provider-registry.d.ts +9 -0
- package/dist/lib/account-provider-registry.js +20 -0
- package/dist/lib/accounting/account-pool-collect.d.ts +34 -0
- package/dist/lib/accounting/account-pool-collect.js +71 -0
- package/dist/lib/accounting/account-pool.d.ts +46 -0
- package/dist/lib/accounting/account-pool.js +33 -0
- package/dist/lib/accounting/capacity.d.ts +24 -0
- package/dist/lib/accounting/capacity.js +30 -0
- package/dist/lib/accounting/rotate.d.ts +11 -18
- package/dist/lib/accounting/rotate.js +6 -24
- package/dist/lib/accounting/usage.d.ts +14 -3
- package/dist/lib/accounting/usage.js +64 -18
- package/dist/lib/agent-spec/agents.js +11 -9
- package/dist/lib/browser/drivers/ssh.d.ts +16 -2
- package/dist/lib/browser/drivers/ssh.js +36 -9
- package/dist/lib/browser/ipc.js +8 -3
- package/dist/lib/browser/profiles.d.ts +35 -101
- package/dist/lib/browser/profiles.js +130 -301
- package/dist/lib/browser/registry.d.ts +39 -0
- package/dist/lib/browser/registry.js +149 -0
- package/dist/lib/browser/remote-control.d.ts +8 -6
- package/dist/lib/browser/remote-control.js +8 -6
- package/dist/lib/browser/resolve-target.d.ts +68 -0
- package/dist/lib/browser/resolve-target.js +250 -0
- package/dist/lib/browser/runtime-state.d.ts +40 -16
- package/dist/lib/browser/runtime-state.js +92 -25
- package/dist/lib/browser/service.d.ts +28 -9
- package/dist/lib/browser/service.js +139 -62
- package/dist/lib/browser/task-index.d.ts +70 -0
- package/dist/lib/browser/task-index.js +180 -0
- package/dist/lib/byok-usage.js +2 -2
- package/dist/lib/claude-statusline.d.ts +29 -0
- package/dist/lib/claude-statusline.js +139 -0
- package/dist/lib/cloud/host.d.ts +1 -1
- package/dist/lib/cloud/host.js +1 -1
- package/dist/lib/cloud/rush.js +1 -1
- package/dist/lib/computer/computer-rpc.js +2 -2
- package/dist/lib/computer/download.d.ts +15 -15
- package/dist/lib/computer/download.js +35 -98
- package/dist/lib/computer/ssh-tunnel.d.ts +0 -3
- package/dist/lib/computer/ssh-tunnel.js +12 -22
- package/dist/lib/config-keys.d.ts +2 -8
- package/dist/lib/config-keys.js +2 -13
- package/dist/lib/crabbox/cli.d.ts +1 -1
- package/dist/lib/crabbox/cli.js +2 -2
- package/dist/lib/crabbox/lease.d.ts +9 -0
- package/dist/lib/crabbox/lease.js +70 -15
- package/dist/lib/crabbox/runtimes.js +1 -1
- package/dist/lib/daemon/account-state-daemon-service.d.ts +16 -0
- package/dist/lib/daemon/account-state-daemon-service.js +26 -0
- package/dist/lib/daemon/browser-ipc-service.d.ts +20 -0
- package/dist/lib/daemon/browser-ipc-service.js +46 -0
- package/dist/lib/daemon/daemon.d.ts +3 -0
- package/dist/lib/daemon/daemon.js +212 -444
- package/dist/lib/daemon/device-probe-service.d.ts +26 -0
- package/dist/lib/daemon/device-probe-service.js +47 -0
- package/dist/lib/daemon/keychain-reap-service.d.ts +17 -0
- package/dist/lib/daemon/keychain-reap-service.js +32 -0
- package/dist/lib/daemon/monitor-engine-service.d.ts +22 -0
- package/dist/lib/daemon/monitor-engine-service.js +29 -0
- package/dist/lib/daemon/secrets-broker-service.d.ts +20 -0
- package/dist/lib/daemon/secrets-broker-service.js +66 -0
- package/dist/lib/daemon/self-heal-service.d.ts +27 -0
- package/dist/lib/daemon/self-heal-service.js +48 -0
- package/dist/lib/daemon/service.d.ts +102 -0
- package/dist/lib/daemon/service.js +98 -0
- package/dist/lib/daemon/session-index-service.d.ts +22 -0
- package/dist/lib/daemon/session-index-service.js +40 -0
- package/dist/lib/daemon/state-dir-check-service.d.ts +43 -0
- package/dist/lib/daemon/state-dir-check-service.js +63 -0
- package/dist/lib/daemon/supervisor.d.ts +87 -0
- package/dist/lib/daemon/supervisor.js +298 -0
- package/dist/lib/daemon/watchdog-service.d.ts +19 -0
- package/dist/lib/daemon/watchdog-service.js +40 -0
- package/dist/lib/daemon-health.d.ts +15 -0
- package/dist/lib/daemon-health.js +29 -5
- package/dist/lib/daemon-services.d.ts +8 -1
- package/dist/lib/daemon-services.js +55 -0
- package/dist/lib/daemon-ticks.d.ts +13 -2
- package/dist/lib/daemon-ticks.js +20 -18
- package/dist/lib/device-config.d.ts +0 -2
- package/dist/lib/device-config.js +1 -23
- package/dist/lib/devices/registry.d.ts +1 -1
- package/dist/lib/devices/registry.js +1 -1
- package/dist/lib/devices/stats-cache.d.ts +20 -0
- package/dist/lib/devices/stats-cache.js +49 -5
- package/dist/lib/devices/worker-pick.d.ts +48 -0
- package/dist/lib/devices/worker-pick.js +113 -0
- package/dist/lib/exec.d.ts +67 -13
- package/dist/lib/exec.js +85 -29
- package/dist/lib/harness/adapters/cursor.js +8 -11
- package/dist/lib/helper-download.d.ts +108 -0
- package/dist/lib/helper-download.js +194 -0
- package/dist/lib/helper-versions.d.ts +52 -0
- package/dist/lib/helper-versions.js +58 -0
- package/dist/lib/hooks/cache.js +11 -0
- package/dist/lib/hooks/install.js +2 -2
- package/dist/lib/hosts/credentials.d.ts +1 -1
- package/dist/lib/hosts/credentials.js +1 -1
- package/dist/lib/hosts/dispatch.d.ts +7 -1
- package/dist/lib/hosts/dispatch.js +24 -5
- package/dist/lib/hosts/passthrough.d.ts +8 -15
- package/dist/lib/hosts/passthrough.js +19 -16
- package/dist/lib/hosts/providers/devices.d.ts +1 -1
- package/dist/lib/hosts/providers/devices.js +1 -1
- package/dist/lib/hosts/reconnect.d.ts +179 -21
- package/dist/lib/hosts/reconnect.js +266 -45
- package/dist/lib/installations/migrate.d.ts +4 -5
- package/dist/lib/installations/migrate.js +6 -7
- package/dist/lib/installations/shims.d.ts +1 -1
- package/dist/lib/installations/shims.js +23 -13
- package/dist/lib/installations/store.js +6 -3
- package/dist/lib/installations/versions.js +73 -48
- package/dist/lib/linear-autoclose.d.ts +1 -1
- package/dist/lib/linear-autoclose.js +1 -1
- package/dist/lib/loop.d.ts +2 -2
- package/dist/lib/loop.js +1 -1
- package/dist/lib/menubar/download-menubar.d.ts +47 -0
- package/dist/lib/menubar/download-menubar.js +60 -0
- package/dist/lib/menubar/install-menubar.d.ts +31 -7
- package/dist/lib/menubar/install-menubar.js +79 -21
- package/dist/lib/menubar/notify-desktop.d.ts +3 -3
- package/dist/lib/menubar/notify-desktop.js +6 -6
- package/dist/lib/model-tiers.d.ts +1 -1
- package/dist/lib/project-probe.d.ts +1 -1
- package/dist/lib/project-probe.js +1 -1
- package/dist/lib/project-pull.d.ts +1 -1
- package/dist/lib/project-pull.js +2 -2
- package/dist/lib/projects.d.ts +1 -1
- package/dist/lib/projects.js +1 -1
- package/dist/lib/sandbox.js +6 -7
- package/dist/lib/secrets/download-keychain.d.ts +47 -0
- package/dist/lib/secrets/download-keychain.js +70 -0
- package/dist/lib/secrets/install-helper.d.ts +20 -1
- package/dist/lib/secrets/install-helper.js +44 -3
- package/dist/lib/session/active.js +17 -1
- package/dist/lib/session/db.d.ts +11 -1
- package/dist/lib/session/db.js +138 -6
- package/dist/lib/session/discover.d.ts +21 -1
- package/dist/lib/session/discover.js +33 -5
- package/dist/lib/session/highlights.d.ts +49 -1
- package/dist/lib/session/highlights.js +95 -0
- package/dist/lib/session/host-link.d.ts +16 -2
- package/dist/lib/session/host-link.js +7 -1
- package/dist/lib/session/parse.js +33 -1
- package/dist/lib/session/remote/remote-list.d.ts +9 -0
- package/dist/lib/session/remote/remote-list.js +19 -2
- package/dist/lib/session/remote/watch.js +11 -2
- package/dist/lib/session/session-cache.d.ts +53 -0
- package/dist/lib/session/session-cache.js +88 -0
- package/dist/lib/session/state.js +1 -1
- package/dist/lib/session/tool-calls.d.ts +2 -0
- package/dist/lib/session/tool-calls.js +1 -1
- package/dist/lib/session/trajectory-html.d.ts +5 -1
- package/dist/lib/session/trajectory-html.js +42 -22
- package/dist/lib/session/trajectory-text.js +9 -2
- package/dist/lib/session/trajectory.js +53 -4
- package/dist/lib/session/types.d.ts +15 -0
- package/dist/lib/sha256-asset.d.ts +26 -0
- package/dist/lib/sha256-asset.js +41 -0
- package/dist/lib/share/backend.d.ts +95 -0
- package/dist/lib/share/backend.js +139 -0
- package/dist/lib/share/delete.d.ts +6 -2
- package/dist/lib/share/delete.js +8 -9
- package/dist/lib/share/html.d.ts +22 -0
- package/dist/lib/share/html.js +88 -0
- package/dist/lib/share/provision.d.ts +18 -4
- package/dist/lib/share/provision.js +38 -4
- package/dist/lib/share/publish.d.ts +44 -15
- package/dist/lib/share/publish.js +58 -26
- package/dist/lib/share/worker-template.js +402 -25
- package/dist/lib/sqlite.js +16 -3
- package/dist/lib/ssh-exec.d.ts +65 -0
- package/dist/lib/ssh-exec.js +120 -4
- package/dist/lib/startup/command-registry.js +1 -1
- package/dist/lib/startup/dev-build.js +3 -3
- package/dist/lib/state.d.ts +1 -1
- package/dist/lib/state.js +7 -3
- package/dist/lib/subagents-registry.js +1 -1
- package/dist/lib/teams/agents.d.ts +14 -12
- package/dist/lib/teams/agents.js +188 -73
- package/dist/lib/teams/api.d.ts +6 -1
- package/dist/lib/teams/api.js +2 -0
- package/dist/lib/teams/scheduler.d.ts +7 -0
- package/dist/lib/teams/scheduler.js +26 -8
- package/dist/lib/terminal/index.d.ts +1 -1
- package/dist/lib/terminal/types.d.ts +1 -1
- package/dist/lib/terminal/types.js +1 -1
- package/dist/lib/tmux/orphan-reap.js +1 -1
- package/dist/lib/tmux/session.js +31 -0
- package/dist/lib/traces/backend.d.ts +29 -0
- package/dist/lib/traces/backend.js +46 -0
- package/dist/lib/traces/classify.d.ts +52 -0
- package/dist/lib/traces/classify.js +72 -0
- package/dist/lib/traces/config.d.ts +10 -0
- package/dist/lib/traces/config.js +2 -0
- package/dist/lib/traces/provision.d.ts +19 -0
- package/dist/lib/traces/provision.js +30 -0
- package/dist/lib/traces/sync.d.ts +150 -0
- package/dist/lib/traces/sync.js +459 -0
- package/dist/lib/traces/worker-template.d.ts +4 -0
- package/dist/lib/traces/worker-template.js +159 -0
- package/dist/lib/types.d.ts +18 -19
- package/dist/lib/types.js +14 -0
- package/dist/lib/usage-refresh.d.ts +1 -1
- package/dist/lib/usage-refresh.js +11 -8
- package/dist/lib/workflows.d.ts +1 -1
- package/package.json +4 -6
- package/dist/lib/menubar/MenubarHelper.app/Contents/CodeResources +0 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/Info.plist +0 -24
- package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/Resources/AppIcon.icns +0 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/_CodeSignature/CodeResources +0 -128
- package/dist/lib/secrets/Agents CLI.app/Contents/CodeResources +0 -0
- package/dist/lib/secrets/Agents CLI.app/Contents/Info.plist +0 -26
- package/dist/lib/secrets/Agents CLI.app/Contents/MacOS/Agents CLI +0 -0
- package/dist/lib/secrets/Agents CLI.app/Contents/Resources/AppIcon.icns +0 -0
- package/dist/lib/secrets/Agents CLI.app/Contents/_CodeSignature/CodeResources +0 -135
- package/dist/lib/secrets/Agents CLI.app/Contents/embedded.provisionprofile +0 -0
- package/dist/lib/usage-fleet.d.ts +0 -32
- package/dist/lib/usage-fleet.js +0 -125
package/dist/lib/ssh-exec.js
CHANGED
|
@@ -18,6 +18,14 @@ import { getCacheDir } from './state.js';
|
|
|
18
18
|
* smuggled in as part of a remote command, and `sshExec` additionally rejects a
|
|
19
19
|
* leading `-` so it can never be parsed as an ssh argv flag.
|
|
20
20
|
*/
|
|
21
|
+
/**
|
|
22
|
+
* ssh's own connection-layer failure code — the transport dropped or never came
|
|
23
|
+
* up, as opposed to the remote command choosing an exit status. Defined here,
|
|
24
|
+
* in the layer that owns the ssh invocation, and re-exported by
|
|
25
|
+
* `lib/hosts/reconnect.ts` as `SSH_CONN_FAILURE` so there is one constant for
|
|
26
|
+
* the concept rather than two that can drift apart.
|
|
27
|
+
*/
|
|
28
|
+
export const SSH_CONN_FAILURE_CODE = 255;
|
|
21
29
|
export const SSH_TARGET_RE = /^[a-zA-Z0-9._-]+(@[a-zA-Z0-9._-]+)?$/;
|
|
22
30
|
export function assertValidSshTarget(host) {
|
|
23
31
|
if (host.startsWith('-') || !SSH_TARGET_RE.test(host)) {
|
|
@@ -314,20 +322,128 @@ export function sshExecRawStream(target, remoteCmd, opts) {
|
|
|
314
322
|
export function sshReachable(target, timeoutMs = 10000) {
|
|
315
323
|
return sshExec(target, 'true', { timeoutMs, multiplex: true }).code === 0;
|
|
316
324
|
}
|
|
325
|
+
/**
|
|
326
|
+
* The DEC private modes a full-screen remote app turns ON and, when it exits
|
|
327
|
+
* cleanly, turns back off itself. A remote agent TUI killed by a dropped link
|
|
328
|
+
* never gets to, so they stay enabled on the LOCAL terminal after ssh is gone:
|
|
329
|
+
* focus reporting (1004) and the mode/colour-scheme reports (996/997) then make
|
|
330
|
+
* the terminal emit answerback sequences at a shell that is not expecting them,
|
|
331
|
+
* which is the `^[[?997;1n ^[[I ^[[O` litter seen after a drop (RUSH-3125). Also
|
|
332
|
+
* resets bracketed paste (2004), the alternate screen (1049), mouse tracking
|
|
333
|
+
* (1000/1002/1003/1006), and re-shows the cursor (25) — every one of which a TUI
|
|
334
|
+
* leaves armed the same way.
|
|
335
|
+
*/
|
|
336
|
+
export const TERMINAL_MODE_RESET = '\x1b[?1004l\x1b[?996l\x1b[?997l\x1b[?2004l\x1b[?1049l'
|
|
337
|
+
+ '\x1b[?1000l\x1b[?1002l\x1b[?1003l\x1b[?1006l\x1b[?25h';
|
|
338
|
+
/**
|
|
339
|
+
* Put the local terminal back the way ssh found it.
|
|
340
|
+
*
|
|
341
|
+
* Two independent kinds of state survive a hard ssh death, and BOTH have to be
|
|
342
|
+
* undone or the next thing the user sees is corrupted:
|
|
343
|
+
*
|
|
344
|
+
* - **termios** (kernel side): `-tt` puts the tty in raw mode, so a killed ssh
|
|
345
|
+
* leaves it with echo and line-editing off. `saved` is the `stty -g` snapshot
|
|
346
|
+
* taken before the spawn; restoring it is exact, unlike guessing at `sane`.
|
|
347
|
+
* - **DEC private modes** (terminal side): see {@link TERMINAL_MODE_RESET}.
|
|
348
|
+
*
|
|
349
|
+
* Then drain whatever the terminal already answered back into the input buffer.
|
|
350
|
+
* Without the drain those bytes are not merely cosmetic — they are still queued
|
|
351
|
+
* on the tty, so the NEXT attach hands them straight to the agent as if the user
|
|
352
|
+
* had typed them.
|
|
353
|
+
*
|
|
354
|
+
* Best-effort by construction: this runs while recovering from a failure, so a
|
|
355
|
+
* missing `stty`, a non-TTY stdin, or a closed stream must never turn a
|
|
356
|
+
* recoverable drop into a thrown error.
|
|
357
|
+
*/
|
|
358
|
+
export function restoreLocalTerminal(saved, opts) {
|
|
359
|
+
try {
|
|
360
|
+
if (saved)
|
|
361
|
+
spawnSync('stty', [saved], { stdio: ['inherit', 'ignore', 'ignore'] });
|
|
362
|
+
}
|
|
363
|
+
catch { /* no stty, or stdin is not a tty — nothing to restore */ }
|
|
364
|
+
try {
|
|
365
|
+
if (process.stdout.isTTY)
|
|
366
|
+
process.stdout.write(TERMINAL_MODE_RESET);
|
|
367
|
+
}
|
|
368
|
+
catch { /* stream closed */ }
|
|
369
|
+
try {
|
|
370
|
+
if (process.stdin.isTTY)
|
|
371
|
+
process.stdin.setRawMode?.(false);
|
|
372
|
+
}
|
|
373
|
+
catch { /* stdin not controllable in this context */ }
|
|
374
|
+
// The DRAIN is the one destructive step here, so it is opt-in per exit. See
|
|
375
|
+
// {@link sshStream} for why it must not run on a clean exit.
|
|
376
|
+
if (!opts.drainStdin)
|
|
377
|
+
return;
|
|
378
|
+
try {
|
|
379
|
+
// read() on a paused non-flowing stdin returns the buffered bytes and
|
|
380
|
+
// discards them; the loop clears a burst rather than one chunk.
|
|
381
|
+
if (process.stdin.isTTY) {
|
|
382
|
+
while (process.stdin.read() !== null) { /* discard */ }
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
catch { /* stdin not readable in this context */ }
|
|
386
|
+
}
|
|
387
|
+
/** `stty -g` snapshot of the local tty, or undefined when there is nothing to snapshot. */
|
|
388
|
+
export function saveLocalTerminal() {
|
|
389
|
+
if (!process.stdin.isTTY)
|
|
390
|
+
return undefined;
|
|
391
|
+
try {
|
|
392
|
+
const r = spawnSync('stty', ['-g'], { stdio: ['inherit', 'pipe', 'ignore'], encoding: 'utf-8' });
|
|
393
|
+
const out = r.status === 0 ? r.stdout?.trim() : '';
|
|
394
|
+
return out || undefined;
|
|
395
|
+
}
|
|
396
|
+
catch {
|
|
397
|
+
return undefined;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
317
400
|
/**
|
|
318
401
|
* Foreground counterpart to `sshExec`: run `remoteCmd` on `target` with the
|
|
319
402
|
* local stdio wired straight through (`stdio: 'inherit'`), so output streams as
|
|
320
403
|
* it is produced and — with `tty` — keystrokes reach a remote picker. Blocks
|
|
321
404
|
* until the remote command exits and returns its exit code (255 is ssh's own
|
|
322
405
|
* connection-layer failure; any other non-zero is the remote command's code).
|
|
406
|
+
*
|
|
407
|
+
* On a `tty` stream the local terminal state is snapshotted before the spawn and
|
|
408
|
+
* restored after it. ssh restores termios itself when it exits cleanly, so this
|
|
409
|
+
* is for the case that matters here: the link dying under a full-screen agent
|
|
410
|
+
* TUI, which leaves the tty raw and the TUI's DEC modes armed. Doing it HERE
|
|
411
|
+
* rather than in the reconnect loop means every caller that opens an interactive
|
|
412
|
+
* remote stream is covered, not just the one that noticed (RUSH-3125).
|
|
413
|
+
*
|
|
414
|
+
* **The stdin drain is gated on an ABNORMAL exit, and the distinction is not
|
|
415
|
+
* cosmetic.** Resetting termios and the DEC modes is idempotent — on a clean
|
|
416
|
+
* exit ssh and the remote TUI have already done it, so re-doing it changes
|
|
417
|
+
* nothing. Draining stdin is destructive: it discards whatever the user has
|
|
418
|
+
* typed ahead. On a clean exit those bytes are legitimate type-ahead the
|
|
419
|
+
* resuming shell should receive, and eating them would be a new bug in every
|
|
420
|
+
* caller of this function (`runInteractiveOnHost`, the remote-tmux attach in
|
|
421
|
+
* commands/go.ts, the remote secrets browse) rather than a fix. Only an
|
|
422
|
+
* abnormal exit — ssh killed by a signal (`status === null`) or its own
|
|
423
|
+
* connection-layer failure (255) — produces the answerback storm the drain
|
|
424
|
+
* exists to clear, because only then did the TUI die without sending its own
|
|
425
|
+
* mode resets.
|
|
323
426
|
*/
|
|
324
427
|
export function sshStream(target, remoteCmd, opts = {}) {
|
|
325
428
|
assertValidSshTarget(target);
|
|
326
429
|
const mux = opts.multiplex === false ? [] : controlOpts();
|
|
327
430
|
const tty = opts.tty ? ['-tt'] : [];
|
|
328
431
|
const args = [...sshConnectOpts(mux, opts.hostKeyOpts), ...(opts.extraSshArgs ?? []), ...tty, target, remoteCmd];
|
|
329
|
-
const
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
432
|
+
const saved = opts.tty ? saveLocalTerminal() : undefined;
|
|
433
|
+
let abnormal = true; // a throw before/inside the spawn is abnormal by definition
|
|
434
|
+
try {
|
|
435
|
+
const res = spawnSync('ssh', args, { stdio: 'inherit' });
|
|
436
|
+
const code = typeof res.status === 'number' ? res.status : 255;
|
|
437
|
+
// Killed by a signal (no numeric status) or ssh's own connection-layer
|
|
438
|
+
// failure — the two shapes in which the remote TUI never got to reset the
|
|
439
|
+
// terminal. Any other code is ssh exiting normally with the remote's status.
|
|
440
|
+
abnormal = res.status === null || code === SSH_CONN_FAILURE_CODE;
|
|
441
|
+
return code;
|
|
442
|
+
}
|
|
443
|
+
finally {
|
|
444
|
+
// `finally`, because the abnormal exits are precisely the ones that leave
|
|
445
|
+
// the terminal wrecked — but the drain within it is gated (see the doc).
|
|
446
|
+
if (opts.tty)
|
|
447
|
+
restoreLocalTerminal(saved, { drainStdin: abnormal });
|
|
448
|
+
}
|
|
333
449
|
}
|
|
@@ -10,7 +10,7 @@ const LOADED_COMMAND_NAMES = [
|
|
|
10
10
|
'ssh', 'devices', 'fleet', 'repos', 'repo', 'setup', 'uninstall', 'upgrade', 'sessions',
|
|
11
11
|
'teams', 'cloud', 'message', 'send', 'notify', 'feed',
|
|
12
12
|
'mailboxes', 'mailbox', 'artifacts', 'webhooks',
|
|
13
|
-
'humans', 'daemon',
|
|
13
|
+
'humans', 'daemon', 'traces',
|
|
14
14
|
];
|
|
15
15
|
const INLINE_COMMAND_NAMES = [
|
|
16
16
|
'perms', 'exec', 'jobs', 'cron', 'check', 'resources', 'hq', '_internal',
|
|
@@ -22,12 +22,12 @@ import * as path from 'path';
|
|
|
22
22
|
* looking for `.git`.
|
|
23
23
|
*
|
|
24
24
|
* That package root does not always hold `.git` itself, though — this repo is a
|
|
25
|
-
* monorepo where the package lives at `
|
|
25
|
+
* monorepo where the package lives at `cli` and `.git` sits one level
|
|
26
26
|
* higher, at the true repo root. `.git` is therefore searched for in a SMALL,
|
|
27
27
|
* bounded set of ancestors above the package root (see
|
|
28
28
|
* `DEV_BUILD_GIT_ANCESTOR_DEPTH`), not just the package root itself — a source
|
|
29
|
-
* checkout run via tsx/ts-node from `
|
|
30
|
-
* `
|
|
29
|
+
* checkout run via tsx/ts-node from `cli/src/` or built to
|
|
30
|
+
* `cli/dist/` must still be recognized. The bound keeps this well short of
|
|
31
31
|
* an unrelated ancestor repo: a real Homebrew npm-global install's package root
|
|
32
32
|
* sits 3 directories below `/opt/homebrew` (`lib/node_modules/@phnx-labs/…`),
|
|
33
33
|
* so a depth of 2 finds this repo's `.git` while staying short of Homebrew's.
|
package/dist/lib/state.d.ts
CHANGED
|
@@ -31,7 +31,7 @@ export declare function getHumansFilePath(): string;
|
|
|
31
31
|
* file against `schema/agents-yaml.schema.json`. Exported so
|
|
32
32
|
* `lib/devices/config-migration.ts` rewrites a device doc with the same header.
|
|
33
33
|
*/
|
|
34
|
-
export declare const META_HEADER = "# agents-cli metadata\n# Auto-generated - do not edit manually\n# https://github.com/phnx-labs/agents-cli\n# yaml-language-server: $schema=https://raw.githubusercontent.com/phnx-labs/agents-cli/main/
|
|
34
|
+
export declare const META_HEADER = "# agents-cli metadata\n# Auto-generated - do not edit manually\n# https://github.com/phnx-labs/agents-cli\n# yaml-language-server: $schema=https://raw.githubusercontent.com/phnx-labs/agents-cli/main/cli/schema/agents-yaml.schema.json\n\n";
|
|
35
35
|
/** Root of the system data directory (~/.agents/.system/). */
|
|
36
36
|
export declare function getAgentsDir(): string;
|
|
37
37
|
/** Root of the system data directory (~/.agents/.system/). */
|
package/dist/lib/state.js
CHANGED
|
@@ -168,7 +168,7 @@ const USER_PROMPTCUTS_FILE = path.join(USER_AGENTS_DIR, 'hooks', 'promptcuts.yam
|
|
|
168
168
|
export const META_HEADER = `# agents-cli metadata
|
|
169
169
|
# Auto-generated - do not edit manually
|
|
170
170
|
# https://github.com/phnx-labs/agents-cli
|
|
171
|
-
# yaml-language-server: $schema=https://raw.githubusercontent.com/phnx-labs/agents-cli/main/
|
|
171
|
+
# yaml-language-server: $schema=https://raw.githubusercontent.com/phnx-labs/agents-cli/main/cli/schema/agents-yaml.schema.json
|
|
172
172
|
|
|
173
173
|
`;
|
|
174
174
|
// ─── Root getters ─────────────────────────────────────────────────────────────
|
|
@@ -895,7 +895,6 @@ const META_KEY_SCOPE = {
|
|
|
895
895
|
actors: 'central',
|
|
896
896
|
seededPresets: 'central',
|
|
897
897
|
hooks: 'central',
|
|
898
|
-
browser: 'central',
|
|
899
898
|
config: 'central',
|
|
900
899
|
hosts: 'central',
|
|
901
900
|
fleet: 'central',
|
|
@@ -910,7 +909,12 @@ const META_KEY_SCOPE = {
|
|
|
910
909
|
* in central is stale and must be migrated out). A key NOT listed here — e.g. one
|
|
911
910
|
* a newer CLI version added — is preserved verbatim, never dropped + synced away.
|
|
912
911
|
*/
|
|
913
|
-
const KNOWN_META_KEYS = new Set(
|
|
912
|
+
const KNOWN_META_KEYS = new Set([
|
|
913
|
+
...Object.keys(META_KEY_SCOPE),
|
|
914
|
+
// Removed browser-profile store. Kept only as a serializer tombstone so the
|
|
915
|
+
// first registry read can migrate it into this device's file and delete it.
|
|
916
|
+
'browser',
|
|
917
|
+
]);
|
|
914
918
|
/**
|
|
915
919
|
* Serialize the central (synced) meta to `agents.yaml` WITHOUT destroying the
|
|
916
920
|
* hand-written comments in the committed file.
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
*
|
|
28
28
|
* The per-agent `transform`/metadata parsers are the escape hatch: they live in
|
|
29
29
|
* `subagents.ts` and are referenced by the table, so the generic engine has zero
|
|
30
|
-
* per-agent branches. See
|
|
30
|
+
* per-agent branches. See `docs/orchestration.md`.
|
|
31
31
|
*/
|
|
32
32
|
import * as fs from 'fs';
|
|
33
33
|
import * as path from 'path';
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { captureProcessStartTime } from '../platform/index.js';
|
|
2
2
|
import { AgentType } from './parsers.js';
|
|
3
|
-
import { NoViableDeviceError } from './scheduler.js';
|
|
4
3
|
/**
|
|
5
4
|
* Compute the Lowest Common Ancestor (LCA) of multiple file paths.
|
|
6
5
|
* Returns the deepest common directory shared by all paths.
|
|
@@ -27,6 +26,16 @@ export declare enum AgentStatus {
|
|
|
27
26
|
export declare const TERMINAL_STATUSES: ReadonlySet<AgentStatus>;
|
|
28
27
|
/** True when a teammate has reached a terminal (completed/failed/stopped) status. */
|
|
29
28
|
export declare function isTerminalStatus(status: AgentStatus): boolean;
|
|
29
|
+
export type TeammateFailureStage = 'placement' | 'spawn' | 'execution' | 'dependency' | 'cloud';
|
|
30
|
+
/** Durable evidence observed at a concrete teammate lifecycle boundary. */
|
|
31
|
+
export interface TeammateFailure {
|
|
32
|
+
stage: TeammateFailureStage;
|
|
33
|
+
code: string;
|
|
34
|
+
message: string;
|
|
35
|
+
exit_code: number | null;
|
|
36
|
+
retryable: boolean;
|
|
37
|
+
observed_at: string;
|
|
38
|
+
}
|
|
30
39
|
/**
|
|
31
40
|
* One remote teammate's liveness, resolved by a single host probe. Three states,
|
|
32
41
|
* kept distinct on purpose (RUSH-2366):
|
|
@@ -201,6 +210,7 @@ export declare class AgentProcess {
|
|
|
201
210
|
remotePid: number | null;
|
|
202
211
|
remoteLog: string | null;
|
|
203
212
|
remoteExit: string | null;
|
|
213
|
+
failure: TeammateFailure | null;
|
|
204
214
|
remoteLogOffset: number;
|
|
205
215
|
remotePollSnapshot: RemoteLivenessSnapshot | null;
|
|
206
216
|
private eventsCache;
|
|
@@ -227,6 +237,7 @@ export declare class AgentProcess {
|
|
|
227
237
|
cloud_session_id: string | null;
|
|
228
238
|
cloud_repo: string | null;
|
|
229
239
|
cloud_branch: string | null;
|
|
240
|
+
failure: TeammateFailure | null;
|
|
230
241
|
agent_dir: string;
|
|
231
242
|
cwd: string | null;
|
|
232
243
|
}>;
|
|
@@ -432,6 +443,8 @@ export declare class AgentManager {
|
|
|
432
443
|
*/
|
|
433
444
|
setCloudDispatcher(fn: CloudDispatchFn | null): void;
|
|
434
445
|
registerAgent(agent: AgentProcess): void;
|
|
446
|
+
private failAgent;
|
|
447
|
+
private deferAgent;
|
|
435
448
|
/**
|
|
436
449
|
* Scan the agents dir for meta.json files not already in the in-memory
|
|
437
450
|
* cache and load them. Needed when another process (e.g. a Planner
|
|
@@ -553,16 +566,6 @@ export declare class AgentManager {
|
|
|
553
566
|
private maybeSchedulePlacement;
|
|
554
567
|
/** Human label of a teammate's agent for the placement fail-loud message. */
|
|
555
568
|
private placementAgentLabel;
|
|
556
|
-
/**
|
|
557
|
-
* Pre-flight the team pool at `teams start` (RUSH-2002): probe the pool and
|
|
558
|
-
* confirm each distinct agent among the pending, unpinned, pooled teammates
|
|
559
|
-
* has at least one viable device. Returns the first {@link NoViableDeviceError}
|
|
560
|
-
* so the command can fail loud BEFORE launching a wave, rather than silently
|
|
561
|
-
* leaving teammates stranded pending. A poolless team (no `--devices`) or a
|
|
562
|
-
* probe that could not gather positive evidence returns null — fail-loud fires
|
|
563
|
-
* only on proof that no device can run the agent, never on a probe miss.
|
|
564
|
-
*/
|
|
565
|
-
preflightPlacement(taskName: string): Promise<NoViableDeviceError | null>;
|
|
566
569
|
/**
|
|
567
570
|
* One-ssh-per-host batched liveness/exit pre-pass for a team's remote teammates.
|
|
568
571
|
* The supervisor calls this each wave BEFORE listByTask() so the per-teammate
|
|
@@ -659,6 +662,5 @@ export declare class AgentManager {
|
|
|
659
662
|
alreadyStopped: string[];
|
|
660
663
|
}>;
|
|
661
664
|
stop(agentId: string): Promise<boolean>;
|
|
662
|
-
private cleanupPartialAgent;
|
|
663
665
|
private cleanupOldAgents;
|
|
664
666
|
}
|