@phnx-labs/agents-cli 1.22.56 → 1.22.58
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 +70 -0
- package/README.md +4 -4
- package/dist/bootstrap.js +11 -2
- package/dist/cli/command-registry.d.ts +0 -1
- package/dist/cli/command-registry.js +0 -3
- package/dist/commands/accounts.js +7 -3
- package/dist/commands/apply.js +10 -2
- package/dist/commands/exec.js +1 -1
- package/dist/commands/fork.d.ts +23 -10
- package/dist/commands/fork.js +115 -58
- package/dist/commands/hooks.js +4 -4
- package/dist/commands/insights.d.ts +7 -5
- package/dist/commands/insights.js +16 -9
- package/dist/commands/monitors.js +11 -0
- package/dist/commands/perf.d.ts +16 -7
- package/dist/commands/perf.js +29 -20
- package/dist/commands/prune.js +5 -3
- package/dist/commands/routines.d.ts +8 -0
- package/dist/commands/routines.js +57 -3
- package/dist/commands/rules.js +1 -1
- package/dist/commands/sessions-picker.d.ts +11 -0
- package/dist/commands/sessions-picker.js +16 -0
- package/dist/commands/sessions.js +1 -0
- package/dist/commands/share.d.ts +14 -0
- package/dist/commands/share.js +43 -2
- package/dist/commands/ssh.js +24 -14
- package/dist/commands/status.js +1 -1
- package/dist/commands/sync.js +83 -7
- package/dist/commands/traces.js +7 -0
- package/dist/commands/trash.d.ts +2 -2
- package/dist/commands/trash.js +2 -6
- package/dist/commands/versions.d.ts +2 -2
- package/dist/commands/versions.js +1 -10
- package/dist/commands/view.d.ts +2 -2
- package/dist/commands/view.js +7 -6
- package/dist/index.d.ts +1 -0
- package/dist/index.js +14 -0
- package/dist/lib/account-registry.d.ts +5 -1
- package/dist/lib/account-registry.js +47 -14
- package/dist/lib/accounting/capacity.d.ts +18 -7
- package/dist/lib/accounting/capacity.js +19 -8
- package/dist/lib/accounting/usage-ingest.d.ts +1 -0
- package/dist/lib/accounting/usage-ingest.js +75 -0
- package/dist/lib/accounting/usage-sync.d.ts +97 -0
- package/dist/lib/accounting/usage-sync.js +203 -0
- package/dist/lib/accounting/usage.d.ts +48 -2
- package/dist/lib/accounting/usage.js +79 -2
- package/dist/lib/agent-spec/agents.js +1 -1
- package/dist/lib/analytics/mix-commands.d.ts +8 -7
- package/dist/lib/analytics/mix-commands.js +50 -73
- package/dist/lib/auth-mint.d.ts +11 -1
- package/dist/lib/auth-mint.js +21 -6
- package/dist/lib/browser/ipc.d.ts +8 -0
- package/dist/lib/browser/ipc.js +87 -0
- package/dist/lib/browser/service.d.ts +19 -0
- package/dist/lib/browser/service.js +96 -11
- package/dist/lib/browser/sessions-list.js +10 -1
- package/dist/lib/daemon/daemon.js +5 -0
- package/dist/lib/daemon/runner.d.ts +3 -0
- package/dist/lib/daemon/runner.js +95 -53
- package/dist/lib/daemon/usage-sync-service.d.ts +21 -0
- package/dist/lib/daemon/usage-sync-service.js +42 -0
- package/dist/lib/daemon-services.d.ts +1 -1
- package/dist/lib/daemon-services.js +5 -0
- package/dist/lib/device-config.d.ts +17 -6
- package/dist/lib/device-config.js +25 -11
- package/dist/lib/devices/connect.d.ts +17 -8
- package/dist/lib/devices/connect.js +31 -14
- package/dist/lib/devices/pool.d.ts +4 -3
- package/dist/lib/devices/pool.js +13 -5
- package/dist/lib/doctor-diff.js +77 -7
- package/dist/lib/exec.d.ts +6 -41
- package/dist/lib/exec.js +6 -41
- package/dist/lib/fleet/manifest.d.ts +17 -0
- package/dist/lib/fleet/manifest.js +26 -0
- package/dist/lib/git.d.ts +13 -1
- package/dist/lib/git.js +36 -7
- package/dist/lib/harness/adapter.d.ts +7 -7
- package/dist/lib/harness/adapters/claude.js +3 -2
- package/dist/lib/hooks/install.d.ts +27 -11
- package/dist/lib/hooks/install.js +42 -17
- package/dist/lib/hosts/reconnect.d.ts +52 -203
- package/dist/lib/hosts/reconnect.js +64 -284
- package/dist/lib/hosts/remote-cmd.d.ts +9 -0
- package/dist/lib/hosts/remote-cmd.js +22 -0
- package/dist/lib/installations/migrate.d.ts +6 -120
- package/dist/lib/installations/migrate.js +27 -259
- package/dist/lib/installations/shims.d.ts +13 -95
- package/dist/lib/installations/shims.js +22 -139
- package/dist/lib/installations/store.js +1 -1
- package/dist/lib/installations/versions.d.ts +26 -133
- package/dist/lib/installations/versions.js +41 -204
- package/dist/lib/perf/db.d.ts +1 -1
- package/dist/lib/perf/db.js +1 -1
- package/dist/lib/plugins/skills.d.ts +8 -1
- package/dist/lib/plugins/skills.js +18 -2
- package/dist/lib/refresh.d.ts +9 -0
- package/dist/lib/refresh.js +3 -1
- package/dist/lib/routine-readiness.d.ts +15 -1
- package/dist/lib/routine-readiness.js +41 -0
- package/dist/lib/sandbox.d.ts +4 -1
- package/dist/lib/sandbox.js +30 -1
- package/dist/lib/secrets/agent.d.ts +80 -225
- package/dist/lib/secrets/agent.js +139 -401
- package/dist/lib/secrets/bundles.d.ts +73 -222
- package/dist/lib/secrets/bundles.js +168 -467
- package/dist/lib/secrets/reaper.d.ts +28 -70
- package/dist/lib/secrets/reaper.js +30 -85
- package/dist/lib/secrets/remote.d.ts +42 -129
- package/dist/lib/secrets/remote.js +55 -173
- package/dist/lib/self-heal/checks/install-staging.d.ts +4 -0
- package/dist/lib/self-heal/checks/install-staging.js +96 -0
- package/dist/lib/self-heal/registry.js +2 -0
- package/dist/lib/self-heal/types.d.ts +1 -1
- package/dist/lib/self-update.d.ts +23 -0
- package/dist/lib/self-update.js +50 -0
- package/dist/lib/session/active.d.ts +16 -32
- package/dist/lib/session/active.js +10 -68
- package/dist/lib/session/db.d.ts +24 -36
- package/dist/lib/session/db.js +143 -44
- package/dist/lib/session/discover.d.ts +6 -58
- package/dist/lib/session/discover.js +5 -43
- package/dist/lib/session/fork.d.ts +45 -26
- package/dist/lib/session/fork.js +32 -95
- package/dist/lib/session/parse.d.ts +1 -19
- package/dist/lib/session/parse.js +2 -15
- package/dist/lib/session/tool-calls.d.ts +43 -1
- package/dist/lib/session/tool-calls.js +74 -44
- package/dist/lib/session/tool-store.d.ts +33 -2
- package/dist/lib/session/tool-store.js +56 -3
- package/dist/lib/staleness/writers/sources.d.ts +5 -0
- package/dist/lib/staleness/writers/sources.js +2 -1
- package/dist/lib/startup/command-registry.d.ts +8 -2
- package/dist/lib/startup/command-registry.js +12 -4
- package/dist/lib/sync-status.d.ts +22 -0
- package/dist/lib/sync-status.js +27 -0
- package/dist/lib/sync-umbrella.d.ts +9 -0
- package/dist/lib/sync-umbrella.js +21 -2
- package/dist/lib/traces/insights.d.ts +47 -14
- package/dist/lib/traces/insights.js +92 -21
- package/dist/lib/traces/phenotype.d.ts +23 -3
- package/dist/lib/traces/phenotype.js +72 -24
- package/dist/lib/traces/sync.d.ts +15 -0
- package/dist/lib/traces/sync.js +104 -19
- package/dist/lib/traces/worker-template.js +154 -1
- package/package.json +1 -1
|
@@ -1,58 +1,37 @@
|
|
|
1
1
|
import { type Host } from './types.js';
|
|
2
|
-
/** ssh's connection-layer failure code —
|
|
3
|
-
* than the remote command exiting on its own. Re-exported from ssh-exec.ts, which
|
|
4
|
-
* owns the ssh invocation, so the two cannot drift apart. */
|
|
2
|
+
/** ssh's connection-layer failure code — re-exported from ssh-exec.ts. */
|
|
5
3
|
export declare const SSH_CONN_FAILURE = 255;
|
|
6
|
-
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
4
|
+
/**
|
|
5
|
+
* ssh returns 255 for BOTH "couldn't connect" and "connected then dropped", so a
|
|
6
|
+
* remote-origin 255 (the focus command's own exit) is remapped to 254 before the
|
|
7
|
+
* reconnect loop sees it — inside the loop, 255 therefore always means a network
|
|
8
|
+
* drop, never a code the remote command chose.
|
|
9
|
+
*/
|
|
9
10
|
export declare const REMOTE_EXIT_255_REMAPPED = 254;
|
|
10
11
|
/**
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* A wall-clock window, not an attempt count, because what it has to outlast is
|
|
14
|
-
* measured in minutes: a laptop lid close, a Wi-Fi handoff, a VPN or Tailscale
|
|
15
|
-
* re-auth, a router reboot. The previous `MAX_ATTEMPTS = 6` over a 2/4/8/16/30/30
|
|
16
|
-
* backoff gave up after about **90 seconds** — shorter than any of them
|
|
17
|
-
* (RUSH-3125). Worse, timers are suspended across sleep, so on wake the whole
|
|
18
|
-
* backoff fired back-to-back before the network was up and the budget was gone in
|
|
19
|
-
* seconds.
|
|
20
|
-
*
|
|
21
|
-
* It bounds the STREAK, not the session: a reattach that reconnects and HOLDS
|
|
22
|
-
* resets it to zero ({@link refillsBudget}), so a session that blinks all day
|
|
23
|
-
* still reconnects every time. That is the property the file header insists on,
|
|
24
|
-
* and a flat total would break it — this changes only how a *streak* is bounded.
|
|
12
|
+
* Wall-clock window bounding unproductive reconnect streaks, not the total
|
|
13
|
+
* session. A reattach that reaches the host and holds resets the budget.
|
|
25
14
|
*/
|
|
26
15
|
export declare const RECONNECT_WINDOW_MS: number;
|
|
27
|
-
/**
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
|
|
33
|
-
* should stop retrying, not one it should keep re-entering. */
|
|
16
|
+
/**
|
|
17
|
+
* A genuine reconnection must hold the remote pane this long before refilling
|
|
18
|
+
* the retry budget. It is the minimum time to clear TTY negotiation and confirm
|
|
19
|
+
* a working session, distinguishing that from an attach that reconnects and
|
|
20
|
+
* immediately re-drops; otherwise a flapping link would retry forever.
|
|
21
|
+
*/
|
|
34
22
|
export declare const MIN_HOLD_MS = 10000;
|
|
35
23
|
export interface ReconnectState {
|
|
36
|
-
/** Consecutive unproductive reattaches since the last genuine reconnection
|
|
37
|
-
* that reached the host and held for {@link MIN_HOLD_MS}. Drives the backoff
|
|
38
|
-
* curve and the human-facing attempt number; no longer the give-up condition. */
|
|
24
|
+
/** Consecutive unproductive reattaches since the last genuine reconnection. */
|
|
39
25
|
attempt: number;
|
|
40
|
-
/**
|
|
41
|
-
* time each failed attach itself took. Compared against
|
|
42
|
-
* {@link RECONNECT_WINDOW_MS}; reset to 0 by a reattach that held. */
|
|
26
|
+
/** Ms burned on the current unproductive streak; compared to the window. */
|
|
43
27
|
unproductiveMs: number;
|
|
44
28
|
}
|
|
45
29
|
export interface ReconnectOutcome {
|
|
46
|
-
/** Exit code of the run
|
|
30
|
+
/** Exit code of the run or last re-attach. */
|
|
47
31
|
code: number;
|
|
48
|
-
/** Whether the ssh handshake
|
|
49
|
-
* and any reattach whose preflight probe succeeded are `connected`; a reattach
|
|
50
|
-
* that couldn't reach the host is not. Half of the budget refill (see file head). */
|
|
32
|
+
/** Whether the ssh handshake completed (preflight probe succeeded). */
|
|
51
33
|
connected: boolean;
|
|
52
|
-
/**
|
|
53
|
-
* probe returned. `0` when the attempt never reached the host. The other half of
|
|
54
|
-
* the refill: it must be at least {@link MIN_HOLD_MS} to count as a genuine
|
|
55
|
-
* reconnection rather than a link that drops the user straight back out. */
|
|
34
|
+
/** How long the interactive attach held after the probe returned. */
|
|
56
35
|
heldMs: number;
|
|
57
36
|
}
|
|
58
37
|
export type ReconnectDecision = {
|
|
@@ -67,93 +46,33 @@ export type ReconnectDecision = {
|
|
|
67
46
|
export declare function initialReconnectState(): ReconnectState;
|
|
68
47
|
/** Exponential backoff capped at {@link MAX_BACKOFF_MS}: 2s, 4s, 8s, 16s, 30s… */
|
|
69
48
|
export declare function backoffMs(attempt: number): number;
|
|
70
|
-
/**
|
|
71
|
-
* Did this attempt genuinely put the user back into the agent? Only such an attempt
|
|
72
|
-
* refills the retry budget — it must have reached the host AND held the pane for at
|
|
73
|
-
* least {@link MIN_HOLD_MS}. An attach that reached the host and died right back is
|
|
74
|
-
* a flapping link, not a reconnection, and counts against the budget like an
|
|
75
|
-
* unreachable host (agents-cli#1884; see the file header).
|
|
76
|
-
*/
|
|
49
|
+
/** True when the attempt both connected and held long enough to refill the budget. */
|
|
77
50
|
export declare function refillsBudget(outcome: ReconnectOutcome): boolean;
|
|
78
51
|
/**
|
|
79
|
-
* Decide
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
* - a non-255 code means the remote command spoke for itself (clean detach = 0,
|
|
83
|
-
* agent exit / no live session = non-zero) → stop and surface that code.
|
|
84
|
-
* - a 255 means the link dropped → retry, unless the budget is spent.
|
|
85
|
-
* - a 255 from an attempt that reconnected AND held ({@link refillsBudget})
|
|
86
|
-
* refills the budget first; every other 255 counts against it, so a host that
|
|
87
|
-
* stays unreachable — and a link that keeps dropping the attach immediately —
|
|
88
|
-
* both give up once the retry window closes.
|
|
52
|
+
* Decide the next action from a run/re-attach outcome. Non-255 exits stop and
|
|
53
|
+
* surface that code; 255 retries until the unproductive window is spent.
|
|
89
54
|
*/
|
|
90
55
|
export declare function reconnectStep(state: ReconnectState, outcome: ReconnectOutcome): ReconnectDecision;
|
|
91
56
|
/** "14m51s", "51s" — a duration a waiting human can read at a glance. */
|
|
92
57
|
export declare function formatDuration(ms: number): string;
|
|
93
|
-
/**
|
|
94
|
-
* Notice shown before each reconnect wait.
|
|
95
|
-
*
|
|
96
|
-
* Says how long is left in the window rather than "attempt 2/6": with a
|
|
97
|
-
* wall-clock budget the attempt number no longer tells the user when this stops,
|
|
98
|
-
* and "how much longer will it keep trying" is the actual question during an
|
|
99
|
-
* outage. Ctrl-C is advertised because a user who wants their shell back should
|
|
100
|
-
* not have to guess whether interrupting is safe — it is (the agent keeps
|
|
101
|
-
* running on the peer, which is the whole point).
|
|
102
|
-
*/
|
|
58
|
+
/** Notice shown before each reconnect wait. */
|
|
103
59
|
export declare function reconnectNotice(target: ReconnectTarget, host: string, attempt: number, waitMs: number, remainingMs: number): string;
|
|
104
|
-
/** Notice shown once the retry budget is spent on
|
|
105
|
-
* Hands back the one verb that re-enters the terminal — attach the live pane if it
|
|
106
|
-
* survived, else resume. */
|
|
60
|
+
/** Notice shown once the retry budget is spent on an unreachable host. */
|
|
107
61
|
export declare function exhaustedNotice(target: ReconnectTarget, host: string): string;
|
|
108
|
-
/** Notice shown when the
|
|
109
|
-
* the host and the connection dropped again within {@link MIN_HOLD_MS}. Saying
|
|
110
|
-
* "couldn't reconnect" there would be false — it did reconnect and could not stay
|
|
111
|
-
* — and the user needs to know the link, not the host, is the problem. It claims
|
|
112
|
-
* no count of successful reconnections: the budget can also be spent by a run of
|
|
113
|
-
* unreachable attempts followed by one that reconnected and dropped straight out. */
|
|
62
|
+
/** Notice shown when the host reconnects but drops again within {@link MIN_HOLD_MS}. */
|
|
114
63
|
export declare function unstableNotice(target: ReconnectTarget, host: string): string;
|
|
115
|
-
/** Notice shown when a reattach
|
|
116
|
-
* ({@link REMOTE_EXIT_255_REMAPPED} — a would-be-255 the remote command decided
|
|
117
|
-
* on for its own reasons, not the ssh transport dropping; see
|
|
118
|
-
* {@link wrapRemoteExitCode}). Distinct from {@link exhaustedNotice}, which is
|
|
119
|
-
* only for a genuinely spent retry budget. */
|
|
64
|
+
/** Notice shown when a reattach ends with a remapped remote-side exit. */
|
|
120
65
|
export declare function remoteExitNotice(target: ReconnectTarget, host: string): string;
|
|
121
|
-
/**
|
|
122
|
-
* detached on the peer — so this says how to get back rather than implying the
|
|
123
|
-
* work was lost. */
|
|
66
|
+
/** Notice shown when the user stops the wait with Ctrl-C. */
|
|
124
67
|
export declare function interruptedNotice(target: ReconnectTarget, host: string): string;
|
|
125
68
|
/**
|
|
126
|
-
* Wrap `cmd` in `bash -lc`
|
|
127
|
-
*
|
|
128
|
-
* a login shell at all; the sibling interactive dispatch in dispatch.ts sends a
|
|
129
|
-
* bare `agents …` with no shell wrapper, so this is a NEW login-shell hop on the
|
|
130
|
-
* reattach path specifically, not something already universal here) with a
|
|
131
|
-
* trailing exit-code remap: whatever `cmd` itself exits with, a 255 becomes
|
|
132
|
-
* {@link REMOTE_EXIT_255_REMAPPED} before the wrapper exits — see the file
|
|
133
|
-
* header for why. Every other code (0, 1, …) passes through unchanged. This
|
|
134
|
-
* carries no PATH bootstrap of its own — `ensureHostReady`/`readyProbe` already
|
|
135
|
-
* gates every `--device` dispatch on `bash -lc 'agents --version'` succeeding
|
|
136
|
-
* before a run is attempted at all, so the peer's login shell resolving `agents`
|
|
137
|
-
* is an established precondition here too. Pure string-building, so it is
|
|
138
|
-
* unit-tested without SSH (and, since the constructed script is ordinary POSIX,
|
|
139
|
-
* also exercised by actually running it through a real shell in the test — no
|
|
140
|
-
* mock needed).
|
|
69
|
+
* Wrap `cmd` in `bash -lc` with an exit-code remap: 255 becomes
|
|
70
|
+
* {@link REMOTE_EXIT_255_REMAPPED} so a remote-origin 255 cannot pass as ssh drop.
|
|
141
71
|
*/
|
|
142
72
|
export declare function wrapRemoteExitCode(cmd: string): string;
|
|
143
73
|
/**
|
|
144
74
|
* How a dropped run is named when we go back for it.
|
|
145
|
-
*
|
|
146
|
-
* `session` is the direct case: the id was known before the link died — Claude
|
|
147
|
-
* is handed one up front, and a resumed run already has one.
|
|
148
|
-
*
|
|
149
|
-
* `launch` is what makes reconnect work for every OTHER harness (RUSH-3125).
|
|
150
|
-
* Their real session id is coined on the peer, and the launcher used to read it
|
|
151
|
-
* back over SSH *after* the stream returned — i.e. over the link that had just
|
|
152
|
-
* dropped. That read fails exactly when it matters, leaving `reconnectId`
|
|
153
|
-
* undefined and the process exiting straight to a shell, which is why a Grok tab
|
|
154
|
-
* got no reconnect at all while a Claude tab beside it got a countdown. The
|
|
155
|
-
* launch id is minted locally before the connection exists, so it survives the
|
|
156
|
-
* drop; the peer maps it to the real session with a purely local lookup.
|
|
75
|
+
* `launch` ids are minted locally before the connection exists, so they survive a drop.
|
|
157
76
|
*/
|
|
158
77
|
export type ReconnectTarget = {
|
|
159
78
|
kind: 'session';
|
|
@@ -165,43 +84,25 @@ export type ReconnectTarget = {
|
|
|
165
84
|
/** The short form shown to a human. Both kinds are uuid-shaped, so 8 chars reads the same. */
|
|
166
85
|
export declare function targetLabel(target: ReconnectTarget): string;
|
|
167
86
|
/**
|
|
168
|
-
* The command to
|
|
169
|
-
*
|
|
170
|
-
* A `session` target has a real id, so `agents sessions resume <id>` does the
|
|
171
|
-
* same attach-else-recover the loop was attempting. The full id is labeled on
|
|
172
|
-
* its own `Session` line, not only inside the command (RUSH-3227). (It used to
|
|
173
|
-
* say `agents reconnect`, which is deprecated and hidden — `commands/reconnect.ts`
|
|
174
|
-
* — so the advice printed at the worst possible moment was itself stale; RUSH-3125.)
|
|
175
|
-
*
|
|
176
|
-
* A `launch` target has no id a user-facing verb accepts: the mapping lives in
|
|
177
|
-
* the peer's hook records, which is exactly why reconnect uses it. So point at
|
|
178
|
-
* the peer's own resolver rather than inventing a launch-id selector on every
|
|
179
|
-
* local command for a string no human ever types.
|
|
87
|
+
* The command a user can run to re-enter a session after reconnect gives up.
|
|
88
|
+
* The full id is printed on its own line so it remains copyable after a drop.
|
|
180
89
|
*/
|
|
181
90
|
export declare function recoveryHint(target: ReconnectTarget, host: string): string;
|
|
182
91
|
/**
|
|
183
|
-
* Notice shown when an interactive remote connection
|
|
184
|
-
*
|
|
185
|
-
* about to auto-reconnect. The OpenSSH close line (`Shared connection to …
|
|
186
|
-
* closed.`) names the host and nothing else; this is the handle they need to
|
|
187
|
-
* get back in (RUSH-3227).
|
|
92
|
+
* Notice shown when an interactive remote connection ends and no auto-reconnect
|
|
93
|
+
* follows. Prints the session id/handle so the user can get back in.
|
|
188
94
|
*/
|
|
189
95
|
export declare function connectionEndedNotice(target: ReconnectTarget, host: string, opts?: {
|
|
190
96
|
dropped?: boolean;
|
|
191
97
|
}): string;
|
|
192
98
|
/**
|
|
193
|
-
* Banner printed
|
|
194
|
-
*
|
|
195
|
-
* will cover this; it survives in scrollback so the id exists *while* the
|
|
196
|
-
* connection exists, not only after it dies (RUSH-3227 plan B). Launch-id
|
|
197
|
-
* targets are not a resume handle — do not print them here.
|
|
99
|
+
* Banner printed as an interactive `--device` run takes the TTY, so the id is
|
|
100
|
+
* visible in scrollback while the connection exists.
|
|
198
101
|
*/
|
|
199
102
|
export declare function connectionStartedNotice(target: ReconnectTarget, host: string): string | undefined;
|
|
200
103
|
/**
|
|
201
|
-
* The id to print as an interactive `--device` stream starts.
|
|
202
|
-
*
|
|
203
|
-
* Claude's forced id is the other. `run auto` is excluded: its forwarded
|
|
204
|
-
* `--session-id` is only real if the remote pick is Claude.
|
|
104
|
+
* The id to print as an interactive `--device` stream starts. `run auto` is
|
|
105
|
+
* excluded because its forwarded id is only real when the remote picks Claude.
|
|
205
106
|
*/
|
|
206
107
|
export declare function startConnectionTarget(opts: {
|
|
207
108
|
agent: string;
|
|
@@ -209,15 +110,8 @@ export declare function startConnectionTarget(opts: {
|
|
|
209
110
|
resumeId?: string;
|
|
210
111
|
}): ReconnectTarget | undefined;
|
|
211
112
|
/**
|
|
212
|
-
* Decide what happens after an interactive `--device` stream returns.
|
|
213
|
-
*
|
|
214
|
-
* Auto-reconnect fires whenever the link dropped (255) and the run did not opt
|
|
215
|
-
* out with `--raw` (`willReconnect`) — wrap or no wrap. A wrapped run's pane
|
|
216
|
-
* survived, so the reattach rejoins it; a bare run's agent died with the link,
|
|
217
|
-
* so the same verb resumes the session in place from disk (PHNX-3316). `--raw`
|
|
218
|
-
* never reconnects — but it still prints the session id: the user is at a
|
|
219
|
-
* shell, and EXEC-55 does not exempt raw (RUSH-3227). Bundling the notice
|
|
220
|
-
* behind `!isRaw` was the miss.
|
|
113
|
+
* Decide what happens after an interactive `--device` stream returns. Auto-
|
|
114
|
+
* reconnect fires on 255 unless `--raw` opted out; otherwise print recovery info.
|
|
221
115
|
*/
|
|
222
116
|
export declare function afterInteractiveRemoteExit(opts: {
|
|
223
117
|
target?: ReconnectTarget;
|
|
@@ -229,84 +123,39 @@ export declare function afterInteractiveRemoteExit(opts: {
|
|
|
229
123
|
reconnect: boolean;
|
|
230
124
|
notice: string | undefined;
|
|
231
125
|
};
|
|
232
|
-
/**
|
|
126
|
+
/** Inputs the launcher has once its interactive stream has returned. */
|
|
233
127
|
export interface ReconnectTargetInputs {
|
|
234
|
-
/** The harness (or {@link RUN_AUTO_KEYWORD}) that was dispatched. */
|
|
235
128
|
agent: string;
|
|
236
|
-
/** An id forced by the launcher up front — Claude's `--session-id`. */
|
|
237
129
|
sessionId?: string;
|
|
238
|
-
/** An id read back off the peer AFTER the stream returned. Absent on a drop. */
|
|
239
130
|
resolvedId?: string;
|
|
240
|
-
/** The id of a run that was resuming an existing session. */
|
|
241
131
|
resumeId?: string;
|
|
242
|
-
/** The launcher-minted AGENT_LAUNCH_ID, known before the connection existed. */
|
|
243
132
|
launchId?: string;
|
|
244
133
|
}
|
|
245
134
|
/**
|
|
246
|
-
* Choose how to name the dropped run
|
|
247
|
-
*
|
|
248
|
-
* Order matters, and the last clause is the fix (RUSH-3125):
|
|
249
|
-
*
|
|
250
|
-
* 1. `run auto` prefers `resolvedId` — the harness the remote ACTUALLY picked,
|
|
251
|
-
* which the launcher's own `--session-id` (adopted only by Claude) may not
|
|
252
|
-
* name. Every other agent prefers the id the launcher forced.
|
|
253
|
-
* 2. `resumeId` covers a run that was continuing a known session.
|
|
254
|
-
* 3. **`launchId` last, and it is what makes this work at all off-Claude.**
|
|
255
|
-
* Every id above either came from the launcher or was read back over SSH —
|
|
256
|
-
* and that read happens after the stream returned, i.e. over the link that
|
|
257
|
-
* just died, so on a real drop it yields nothing. Falling through to the
|
|
258
|
-
* launch id means the reconnect no longer depends on reaching the host to
|
|
259
|
-
* learn what to reconnect to; the peer resolves it locally instead.
|
|
260
|
-
*
|
|
261
|
-
* Returns undefined only when the launcher has no handle at all (a hookless
|
|
262
|
-
* harness with no forced id), which is the one case reconnect genuinely cannot
|
|
263
|
-
* serve. Pure, so the precedence is unit-tested without SSH.
|
|
135
|
+
* Choose how to name the dropped run. `launchId` is last because it is minted
|
|
136
|
+
* locally before the connection exists, so it survives the drop.
|
|
264
137
|
*/
|
|
265
138
|
export declare function pickReconnectTarget(inputs: ReconnectTargetInputs): ReconnectTarget | undefined;
|
|
266
139
|
/**
|
|
267
|
-
* The
|
|
268
|
-
*
|
|
269
|
-
* so a stray remote-origin 255 (from this command, whatever produces it — see the
|
|
270
|
-
* file header) can never masquerade as a network drop. No `--attach-only`: focus
|
|
271
|
-
* joins the live pane when it survived, else RESUMES the session in place, so a
|
|
272
|
-
* reattach landing after the pane died recovers the agent instead of dead-ending
|
|
273
|
-
* (RUSH-2085). Split out from {@link reattachRemoteSession} so it is unit-tested
|
|
274
|
-
* without SSH — mirrors `remoteAgentsJsonCommand` in lib/remote-agents-json.ts.
|
|
275
|
-
*
|
|
276
|
-
* A `launch` target passes `--launch-id`, which focus resolves against the hook
|
|
277
|
-
* records on the peer itself — no network read from this side, which is the
|
|
278
|
-
* whole point (see {@link ReconnectTarget}).
|
|
140
|
+
* The peer's recovery verb wrapped so a remote-origin 255 cannot masquerade as
|
|
141
|
+
* a network drop. No `--attach-only`: focus resumes in place when no pane survived.
|
|
279
142
|
*/
|
|
280
143
|
export declare function reattachRemoteCommand(target: ReconnectTarget): string;
|
|
281
144
|
/**
|
|
282
|
-
* Re-attach the live remote
|
|
283
|
-
*
|
|
284
|
-
*
|
|
285
|
-
* `connected` bit, not the call duration, is what the retry policy keys on. Only on
|
|
286
|
-
* a reachable host do we run the interactive attach-or-resume (which carries no
|
|
287
|
-
* credentials — the agent already runs on the peer — so it rides the normal
|
|
288
|
-
* transport). Returns the ssh exit code (255 = dropped again / unreachable; 0 =
|
|
289
|
-
* clean detach; other = session ended), whether this attempt connected, and how
|
|
290
|
-
* long the attach held — the two inputs {@link refillsBudget} decides on.
|
|
145
|
+
* Re-attach the live remote pane by driving the peer's `agents sessions focus`.
|
|
146
|
+
* A fast preflight probe decides reachability; only then do we run the
|
|
147
|
+
* interactive attach/resume. Returns the exit code, connected bit, and hold time.
|
|
291
148
|
*/
|
|
292
149
|
export declare function reattachRemoteSession(host: Host, target: ReconnectTarget): ReconnectOutcome;
|
|
293
150
|
export interface ReconnectLoopOpts {
|
|
294
151
|
host: Host;
|
|
295
152
|
target: ReconnectTarget;
|
|
296
|
-
/**
|
|
297
|
-
* is treated as a connected attempt). */
|
|
153
|
+
/** Exit code from the initial interactive run (treated as connected). */
|
|
298
154
|
initialExit: number;
|
|
299
|
-
/**
|
|
300
|
-
* fakes so the loop's control flow is exercised without SSH. Production uses the
|
|
301
|
-
* real {@link reattachRemoteSession} + {@link waitOrInterrupt}. */
|
|
155
|
+
/** Test seams for the re-attach and wait. */
|
|
302
156
|
reattach?: (host: Host, target: ReconnectTarget) => ReconnectOutcome;
|
|
303
|
-
/** Resolves 'interrupted' when the user Ctrl-Cs out of the backoff. */
|
|
304
157
|
wait?: (ms: number) => Promise<'elapsed' | 'interrupted'>;
|
|
305
158
|
write?: (s: string) => void;
|
|
306
159
|
}
|
|
307
|
-
/**
|
|
308
|
-
* Drive the reconnect loop from the initial run's outcome to a terminal code.
|
|
309
|
-
* Only the real SSH re-attach and the wait are side effects; the decision is
|
|
310
|
-
* {@link reconnectStep}. Returns the exit code the process should ultimately use.
|
|
311
|
-
*/
|
|
160
|
+
/** Drive the reconnect loop from the initial run's outcome to a terminal code. */
|
|
312
161
|
export declare function reconnectInteractiveSession(opts: ReconnectLoopOpts): Promise<number>;
|