@cotal-ai/cli 0.137.0 → 0.138.1
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/dist/chat/chat-view.d.ts +1 -1
- package/dist/chat/chat-view.d.ts.map +1 -1
- package/dist/chat/controller.d.ts +1 -1
- package/dist/chat/controller.d.ts.map +1 -1
- package/dist/chat/frontend.d.ts +1 -1
- package/dist/chat/frontend.d.ts.map +1 -1
- package/dist/chat/picker.d.ts +1 -1
- package/dist/chat/picker.d.ts.map +1 -1
- package/dist/chat/plain.d.ts +1 -1
- package/dist/chat/plain.d.ts.map +1 -1
- package/dist/chat/stdio-io.d.ts +1 -1
- package/dist/chat/stdio-io.d.ts.map +1 -1
- package/dist/chat/stdio.d.ts +1 -1
- package/dist/chat/stdio.d.ts.map +1 -1
- package/dist/chat/view.d.ts +1 -1
- package/dist/chat/view.d.ts.map +1 -1
- package/dist/commands/agents.d.ts +7 -149
- package/dist/commands/agents.d.ts.map +1 -1
- package/dist/commands/agents.js +15 -723
- package/dist/commands/agents.js.map +1 -1
- package/dist/commands/channels.js +1 -1
- package/dist/commands/channels.js.map +1 -1
- package/dist/commands/chat.d.ts +1 -24
- package/dist/commands/chat.d.ts.map +1 -1
- package/dist/commands/chat.js +3 -15
- package/dist/commands/chat.js.map +1 -1
- package/dist/console/app.js +1 -1
- package/dist/console/app.js.map +1 -1
- package/package.json +5 -6
- package/dist/chat/engine.d.ts +0 -111
- package/dist/chat/engine.d.ts.map +0 -1
- package/dist/chat/engine.js +0 -225
- package/dist/chat/engine.js.map +0 -1
- package/dist/chat/native-session.d.ts +0 -120
- package/dist/chat/native-session.d.ts.map +0 -1
- package/dist/chat/native-session.js +0 -487
- package/dist/chat/native-session.js.map +0 -1
- package/dist/chat/open-session.d.ts +0 -9
- package/dist/chat/open-session.d.ts.map +0 -1
- package/dist/chat/open-session.js +0 -120
- package/dist/chat/open-session.js.map +0 -1
- package/dist/chat/session.d.ts +0 -230
- package/dist/chat/session.d.ts.map +0 -1
- package/dist/chat/session.js +0 -2
- package/dist/chat/session.js.map +0 -1
- package/dist/chat/static-session.d.ts +0 -62
- package/dist/chat/static-session.d.ts.map +0 -1
- package/dist/chat/static-session.js +0 -236
- package/dist/chat/static-session.js.map +0 -1
- package/dist/chat/user-session.d.ts +0 -22
- package/dist/chat/user-session.d.ts.map +0 -1
- package/dist/chat/user-session.js +0 -180
- package/dist/chat/user-session.js.map +0 -1
- package/dist/lib/attach-client.d.ts +0 -112
- package/dist/lib/attach-client.d.ts.map +0 -1
- package/dist/lib/attach-client.js +0 -528
- package/dist/lib/attach-client.js.map +0 -1
|
@@ -1,528 +0,0 @@
|
|
|
1
|
-
import { openSessionRail, encodeTerminalData, terminalFrameBytes, decodeTerminalFrame } from "@cotal-ai/core";
|
|
2
|
-
import { cachedPreferences, describeLayer, parseDetachKey, resolvePreference } from "@cotal-ai/workspace";
|
|
3
|
-
import { c, stderrLine } from "../ui.js";
|
|
4
|
-
/**
|
|
5
|
-
* The detach key — Ctrl-] (0x1d) by default, as in telnet/ssh escape conventions. The `detach-key`
|
|
6
|
-
* preference rebinds it to another control key when Ctrl-] clashes with a keybinding inside the
|
|
7
|
-
* agent's TUI: `COTAL_DETACH_KEY`, then the saved preference (`cotal config set detach-key`). Both
|
|
8
|
-
* accept `ctrl-<char>` or `^<char>` (e.g. `ctrl-b`, `^_`). An unparseable `COTAL_DETACH_KEY` —
|
|
9
|
-
* including a set-but-empty or whitespace-only one — throws (named), never silently falling back;
|
|
10
|
-
* the caller turns that into a loud exit. A saved value was validated when it was written.
|
|
11
|
-
*/
|
|
12
|
-
export function detachKey() {
|
|
13
|
-
const resolved = resolvePreference("detach-key", { preferences: cachedPreferences() });
|
|
14
|
-
const winner = resolved.winner;
|
|
15
|
-
const key = parseDetachKey(winner.value);
|
|
16
|
-
if (!key) {
|
|
17
|
-
throw new Error(`invalid ${describeLayer(winner)} "${winner.value}" - expected ctrl-<char> or ^<char> for a control key ` +
|
|
18
|
-
`(a-z, or one of @ [ \\ ] ^ _), e.g. ctrl-b`);
|
|
19
|
-
}
|
|
20
|
-
return { ...key, overridden: winner.source !== "default", from: describeLayer(winner) };
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Whether a whole chunk `d` is exactly one press of the detach key `byte`, in any of three
|
|
24
|
-
* encodings: the legacy single control byte; the kitty keyboard protocol's `CSI <codepoint> ;
|
|
25
|
-
* <mods> u`; or xterm `modifyOtherKeys`'s `CSI 27 ; <mods> ; <codepoint> ~`. `<codepoint>` is the
|
|
26
|
-
* decimal codepoint kitty/xterm report for the unshifted key: `byte | 0x40` for the control
|
|
27
|
-
* punctuation (`@ [ \ ] ^ _`) and `byte | 0x60` for a letter (kitty reports the lowercase key even
|
|
28
|
-
* though Ctrl was held). `<mods>` is 1 + the modifier bitmask and must carry the Ctrl bit
|
|
29
|
-
* (`(mods - 1) & 4`), so plain Ctrl (5) and Ctrl+Shift (6) match but a modifier field without Ctrl
|
|
30
|
-
* does not, and a field of 0, which neither protocol emits, is not a press either (the test needs
|
|
31
|
-
* that floor: `(0 - 1) & 4` is 4 in ToInt32 arithmetic, so 0 would otherwise read as Ctrl). The match is on the WHOLE chunk:
|
|
32
|
-
* a sequence with company (a paste, a second keystroke, a trailing byte) is not a press, which is
|
|
33
|
-
* the same paste-safety property the one-byte test already had. This assumes one press arrives in
|
|
34
|
-
* one read, as measured on a pty (issue #598); a sequence split across two reads is not buffered
|
|
35
|
-
* and is not recognised. A kitty `CSI u` with an alternate-key `<codepoint>:<shifted>:<base>` triple
|
|
36
|
-
* is accepted by matching only the leading codepoint before an optional `:...` group; no other
|
|
37
|
-
* kitty event type (release, repeat) is recognised.
|
|
38
|
-
*/
|
|
39
|
-
export function isDetachPress(d, byte) {
|
|
40
|
-
if (d.length === 0)
|
|
41
|
-
return false;
|
|
42
|
-
if (d.length === 1 && d[0] === byte)
|
|
43
|
-
return true;
|
|
44
|
-
const s = d.toString("latin1");
|
|
45
|
-
const codepoints = byte >= 0x01 && byte <= 0x1a ? [byte | 0x40, byte | 0x60] : [byte | 0x40];
|
|
46
|
-
const hasCtrl = (mods) => mods >= 1 && ((mods - 1) & 4) !== 0;
|
|
47
|
-
const kitty = /^\x1b\[(\d+)(?::\d+(?::\d+)?)?;(\d+)u$/.exec(s);
|
|
48
|
-
if (kitty) {
|
|
49
|
-
const cp = Number(kitty[1]);
|
|
50
|
-
const mods = Number(kitty[2]);
|
|
51
|
-
if (codepoints.includes(cp) && hasCtrl(mods))
|
|
52
|
-
return true;
|
|
53
|
-
}
|
|
54
|
-
const xterm = /^\x1b\[27;(\d+);(\d+)~$/.exec(s);
|
|
55
|
-
if (xterm) {
|
|
56
|
-
const mods = Number(xterm[1]);
|
|
57
|
-
const cp = Number(xterm[2]);
|
|
58
|
-
if (codepoints.includes(cp) && hasCtrl(mods))
|
|
59
|
-
return true;
|
|
60
|
-
}
|
|
61
|
-
return false;
|
|
62
|
-
}
|
|
63
|
-
/**
|
|
64
|
-
* Terminal modes a full-screen child (a fullscreen TUI: OpenCode, or Claude under `/tui fullscreen`)
|
|
65
|
-
* commonly turns on but that we must undo locally on detach/exit: the agent keeps running after
|
|
66
|
-
* Ctrl-], so it never restores OUR terminal. Without this, detaching from a mouse-tracking TUI leaves
|
|
67
|
-
* the terminal reporting every cursor move as input (a stream of `ESC[<…M` escape codes), or its
|
|
68
|
-
* focus in/out as `ESC[I`/`ESC[O`. Disables all mouse-report modes + focus reporting + bracketed
|
|
69
|
-
* paste, resets the keypad/cursor-key modes, shows the cursor, and resets attributes. Leaving the
|
|
70
|
-
* alternate screen is handled separately (ALT_LEAVE_SEQ), only when we actually entered it — see
|
|
71
|
-
* cleanup().
|
|
72
|
-
*/
|
|
73
|
-
const MOUSE_OFF = "\x1b[?1000l\x1b[?1002l\x1b[?1003l\x1b[?1005l\x1b[?1006l\x1b[?1015l"; // all mouse tracking off
|
|
74
|
-
const RESTORE = MOUSE_OFF +
|
|
75
|
-
"\x1b[?1004l" + // focus reporting off
|
|
76
|
-
"\x1b[?2004l" + // bracketed paste off
|
|
77
|
-
"\x1b[?1l" + // application cursor keys off (DECCKM): a full-screen TUI enables it; left on, arrows emit ESC O A not ESC [ A
|
|
78
|
-
"\x1b>" + // keypad → numeric (DECKPNM)
|
|
79
|
-
"\x1b[?25h" + // show cursor
|
|
80
|
-
"\x1b[0m"; // reset attributes
|
|
81
|
-
// Leave the alternate screen on detach, but ONLY if the child put us there (altScreen). The attach
|
|
82
|
-
// snapshot faithfully re-enters the child's alt-screen (`?1049h`) on our terminal; without a matching
|
|
83
|
-
// leave we strand it in the alt buffer, which has no scrollback and — with xterm alt-scroll — turns
|
|
84
|
-
// the wheel into ↑/↓ that walk shell history. Leaving the alt buffer IS the whole fix: alt-scroll
|
|
85
|
-
// (`?1007`) only acts inside the alt buffer, so `?1049l` alone makes it inert. We deliberately don't
|
|
86
|
-
// send `?1007l` — nothing on this path ever enabled it (unlike console.ts, which sets `?1007h` on
|
|
87
|
-
// entry), so disabling it would clobber the operator's own alternate-scroll preference for later apps.
|
|
88
|
-
const ALT_LEAVE_SEQ = "\x1b[?1049l"; // leave alt-screen — alt-scroll is inert once back in the main buffer
|
|
89
|
-
// Wheel-scroll for full-screen children. A fullscreen TUI (OpenCode, or Claude under `/tui
|
|
90
|
-
// fullscreen`) runs in the alternate screen — where the terminal's native scrollback is dead — and
|
|
91
|
-
// scrolls its content itself off mouse reports. But it enables that mouse capture on ITS pty, and the
|
|
92
|
-
// enable doesn't reliably survive the attach hop (backlog eviction / nested pty), so our terminal
|
|
93
|
-
// never reports the wheel and scrolling dies. So while the child is in the alternate screen we enable
|
|
94
|
-
// SGR mouse reporting on OUR terminal and translate each wheel tick into PageUp/PageDown — the
|
|
95
|
-
// keystrokes a fullscreen TUI treats as "scroll the view" (OpenCode: `messages_page_up`/`_down`;
|
|
96
|
-
// Claude's fullscreen binds PageUp/PageDown too). A child in the normal screen (inline Claude) keeps
|
|
97
|
-
// altScreen=false, so this stays off and its native terminal-scrollback wheel is untouched.
|
|
98
|
-
const MOUSE_ON = "\x1b[?1002h\x1b[?1006h"; // button+drag tracking, SGR encoding
|
|
99
|
-
const PAGE_UP = "\x1b[5~";
|
|
100
|
-
const PAGE_DOWN = "\x1b[6~";
|
|
101
|
-
/** Collapse a wheel burst to at most one page command per display frame. Each raw wheel report used
|
|
102
|
-
* to become a separate session frame and TUI redraw; rapid scrolling could fill the 64-frame rail
|
|
103
|
-
* before the caller returned credit, even though the operator only intended one continuous scroll. */
|
|
104
|
-
const WHEEL_COALESCE_MS = 16;
|
|
105
|
-
// Enter/leave the alternate screen: xterm `?1049`, plus the older `?1047`/`?47`.
|
|
106
|
-
const ALT_ENTER = /\x1b\[\?(?:1049|1047|47)h/g;
|
|
107
|
-
const ALT_LEAVE = /\x1b\[\?(?:1049|1047|47)l/g;
|
|
108
|
-
// A complete SGR mouse report: `ESC [ < btn ; col ; row (M|m)`.
|
|
109
|
-
const SGR_MOUSE = /^\x1b\[<(\d+);\d+;\d+[Mm]/;
|
|
110
|
-
const lastIndexOfRe = (re, s) => {
|
|
111
|
-
re.lastIndex = 0;
|
|
112
|
-
let last = -1;
|
|
113
|
-
for (let m = re.exec(s); m; m = re.exec(s))
|
|
114
|
-
last = m.index;
|
|
115
|
-
return last;
|
|
116
|
-
};
|
|
117
|
-
export function holdTerminal() {
|
|
118
|
-
const stdin = process.stdin;
|
|
119
|
-
const wasRaw = stdin.isRaw ?? false;
|
|
120
|
-
let entered = false;
|
|
121
|
-
let restored = false;
|
|
122
|
-
return {
|
|
123
|
-
altScreen: false,
|
|
124
|
-
enterRaw() {
|
|
125
|
-
if (entered)
|
|
126
|
-
return;
|
|
127
|
-
entered = true;
|
|
128
|
-
if (stdin.isTTY)
|
|
129
|
-
stdin.setRawMode(true);
|
|
130
|
-
},
|
|
131
|
-
restore() {
|
|
132
|
-
if (restored)
|
|
133
|
-
return;
|
|
134
|
-
restored = true;
|
|
135
|
-
if (process.stdout.isTTY)
|
|
136
|
-
process.stdout.write(RESTORE + (this.altScreen ? ALT_LEAVE_SEQ : ""));
|
|
137
|
-
if (stdin.isTTY)
|
|
138
|
-
stdin.setRawMode(wasRaw);
|
|
139
|
-
stdin.pause();
|
|
140
|
-
},
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
/** Register the stdout EPIPE/EIO no-op ONCE for the process. Idempotent by construction: a
|
|
144
|
-
* reconnecting attach calls {@link attachClient} once per attempt and each call would otherwise
|
|
145
|
-
* add another listener that nothing ever removes. */
|
|
146
|
-
let stdoutErrorSwallowed = false;
|
|
147
|
-
function swallowStdoutPipeErrors() {
|
|
148
|
-
if (stdoutErrorSwallowed)
|
|
149
|
-
return;
|
|
150
|
-
stdoutErrorSwallowed = true;
|
|
151
|
-
process.stdout.on("error", () => { });
|
|
152
|
-
}
|
|
153
|
-
/** Resolve when stdout accepted a write. A destroyed pipe is a terminal that no longer consumes, not
|
|
154
|
-
* a reason to wedge the mesh rail forever; `error`/`close` therefore release the wait like `drain`. */
|
|
155
|
-
function writeStdout(bytes) {
|
|
156
|
-
if (process.stdout.write(bytes) || process.stdout.destroyed)
|
|
157
|
-
return;
|
|
158
|
-
return new Promise((resolve) => {
|
|
159
|
-
const done = () => {
|
|
160
|
-
process.stdout.off("drain", done);
|
|
161
|
-
process.stdout.off("error", done);
|
|
162
|
-
process.stdout.off("close", done);
|
|
163
|
-
resolve();
|
|
164
|
-
};
|
|
165
|
-
process.stdout.once("drain", done);
|
|
166
|
-
process.stdout.once("error", done);
|
|
167
|
-
process.stdout.once("close", done);
|
|
168
|
-
});
|
|
169
|
-
}
|
|
170
|
-
/**
|
|
171
|
-
* The TRANSPORT-class end reasons: the link broke, the session did not finish. Every one of these
|
|
172
|
-
* means the seat is still there and a fresh session would reach it.
|
|
173
|
-
*
|
|
174
|
-
* The nine fault names are core's own, not a list invented here: `openSessionRail`'s
|
|
175
|
-
* `onProtocolError` documents its whole vocabulary as "the session is broken — close and
|
|
176
|
-
* re-establish" (SPEC 13.6). Added to them are the three ends that are not rail faults but are
|
|
177
|
-
* still the link dying: the peer closing its rail, and this side's NATS connection going away.
|
|
178
|
-
*
|
|
179
|
-
* Deliberately NOT here, so a reconnect never papers over a finished session: `detached` (the
|
|
180
|
-
* operator pressed the key), and the manager's terminal reasons — `process-exit` (the agent
|
|
181
|
-
* exited), `target-despawn`, `manager-restart`, `expired` (the grant's TTL elapsed). Those end the
|
|
182
|
-
* attach, and the CLI says which.
|
|
183
|
-
*/
|
|
184
|
-
const TRANSPORT_END_REASONS = new Set([
|
|
185
|
-
"garbled-frame", "gap", "credit-overrun", "flood", "subscription", "stall", "handler", "publish", "seq-exhausted",
|
|
186
|
-
"peer-closed", "closed", "connection-closed",
|
|
187
|
-
]);
|
|
188
|
-
/** Did the session end because the LINK broke (so re-establishing is the honest response)? */
|
|
189
|
-
export function isTransportEnd(reason) {
|
|
190
|
-
return TRANSPORT_END_REASONS.has(reason);
|
|
191
|
-
}
|
|
192
|
-
/**
|
|
193
|
-
* Drive a manager's attach session from the terminal: raw-mode stdin streams to the remote PTY,
|
|
194
|
-
* PTY output streams to stdout, and SIGWINCH-style resizes are forwarded. The detach key (Ctrl-]
|
|
195
|
-
* by default, {@link detachKey}) detaches without killing the agent. Transport-agnostic over the
|
|
196
|
-
* mesh §13.6 session.
|
|
197
|
-
*/
|
|
198
|
-
export function attachClient(transport, hold, takeStdin) {
|
|
199
|
-
// Resolve the detach key before connecting so a bad COTAL_DETACH_KEY fails loudly up front
|
|
200
|
-
// (matching the manager's other fail-fast exits) instead of after an attach we'd only tear down.
|
|
201
|
-
let detach;
|
|
202
|
-
try {
|
|
203
|
-
detach = detachKey();
|
|
204
|
-
}
|
|
205
|
-
catch (e) {
|
|
206
|
-
stderrLine("✗ ", `${e.message}`, c.red);
|
|
207
|
-
process.exit(1);
|
|
208
|
-
}
|
|
209
|
-
// A caller that reconnects owns the terminal across attempts and undoes it once at the end;
|
|
210
|
-
// without a hold this session owns it, which is the one-shot behaviour.
|
|
211
|
-
const ownsTerminal = hold === undefined;
|
|
212
|
-
const term = hold ?? holdTerminal();
|
|
213
|
-
return new Promise((resolve) => {
|
|
214
|
-
const stdin = process.stdin;
|
|
215
|
-
// A broken local pipe (terminal closed / SIGHUP) makes stdout writes async-error on a later
|
|
216
|
-
// tick; with no listener that EPIPE/EIO becomes an uncaughtException — crashing on the per-frame
|
|
217
|
-
// PTY write or the on-detach restore write. It must outlive the async error tick, so it is NOT
|
|
218
|
-
// removed in cleanup — which is exactly why it is registered once per PROCESS rather than once
|
|
219
|
-
// per attempt: a reconnect loop calls this function again on every re-establishment, and one
|
|
220
|
-
// listener per attempt walks into MaxListenersExceededWarning during a long outage.
|
|
221
|
-
swallowStdoutPipeErrors();
|
|
222
|
-
// Wheel-scroll state (see MOUSE_ON above): whether the child is in the alternate screen (on the
|
|
223
|
-
// hold, since it outlives one session) and a buffer for an SGR mouse report split across stdin
|
|
224
|
-
// reads (per-session: bytes still in flight when a link dies are gone with it).
|
|
225
|
-
// Did this session ever put bytes on the terminal (see AttachOutcome.carried)?
|
|
226
|
-
let carried = false;
|
|
227
|
-
// Did THIS session ever take the stream? A reconnecting caller holds a reader between sessions,
|
|
228
|
-
// and a session that ends before its `ready` fires never ran the handoff below, so it never
|
|
229
|
-
// took anything: pausing on the way out would pause a stream it does not own, under a reader
|
|
230
|
-
// that is still installed and now reads nothing. Measured before this line existed: a link
|
|
231
|
-
// killed while a session's opening flush was in flight left the loop's watcher listening over a
|
|
232
|
-
// paused stream for the whole backoff, and everything typed at that frozen terminal was flushed
|
|
233
|
-
// into the agent by the NEXT session's resume. Cell O of `smoke:attach-stdin` is that window.
|
|
234
|
-
let tookStdin = false;
|
|
235
|
-
let mouseBuf = "";
|
|
236
|
-
let wheelDelta = 0;
|
|
237
|
-
let wheelTimer;
|
|
238
|
-
const flushWheel = () => {
|
|
239
|
-
if (wheelTimer)
|
|
240
|
-
clearTimeout(wheelTimer);
|
|
241
|
-
wheelTimer = undefined;
|
|
242
|
-
const delta = wheelDelta;
|
|
243
|
-
wheelDelta = 0;
|
|
244
|
-
if (delta === 0)
|
|
245
|
-
return;
|
|
246
|
-
transport.send(Buffer.from(delta > 0 ? PAGE_DOWN : PAGE_UP, "latin1"));
|
|
247
|
-
};
|
|
248
|
-
const clearWheel = () => {
|
|
249
|
-
if (wheelTimer)
|
|
250
|
-
clearTimeout(wheelTimer);
|
|
251
|
-
wheelTimer = undefined;
|
|
252
|
-
wheelDelta = 0;
|
|
253
|
-
};
|
|
254
|
-
const queueWheel = (delta) => {
|
|
255
|
-
wheelDelta = Math.max(-8, Math.min(8, wheelDelta + delta));
|
|
256
|
-
if (wheelTimer)
|
|
257
|
-
return;
|
|
258
|
-
wheelTimer = setTimeout(flushWheel, WHEEL_COALESCE_MS);
|
|
259
|
-
wheelTimer.unref?.();
|
|
260
|
-
};
|
|
261
|
-
// Carry the tail of the previous output frame so an alt-screen escape split across ws frames
|
|
262
|
-
// (e.g. `ESC[?10` then `49h`) is still detected; 16 bytes covers these private-mode sequences.
|
|
263
|
-
// Acting only on state *change* below makes re-scanning the carried bytes idempotent.
|
|
264
|
-
let scanTail = "";
|
|
265
|
-
// Track the child's alt-screen transitions in its output so we can arm/disarm wheel translation.
|
|
266
|
-
const trackAltScreen = (data) => {
|
|
267
|
-
const s = scanTail + data.toString("latin1");
|
|
268
|
-
scanTail = s.slice(-16);
|
|
269
|
-
const enter = lastIndexOfRe(ALT_ENTER, s);
|
|
270
|
-
const leave = lastIndexOfRe(ALT_LEAVE, s);
|
|
271
|
-
if (enter === -1 && leave === -1)
|
|
272
|
-
return;
|
|
273
|
-
const nowAlt = enter > leave;
|
|
274
|
-
if (nowAlt === term.altScreen)
|
|
275
|
-
return;
|
|
276
|
-
term.altScreen = nowAlt;
|
|
277
|
-
if (term.altScreen) {
|
|
278
|
-
if (process.stdout.isTTY)
|
|
279
|
-
process.stdout.write(MOUSE_ON);
|
|
280
|
-
}
|
|
281
|
-
else {
|
|
282
|
-
// Leaving alt-screen mid-session: undo the mouse modes WE enabled so the terminal stops
|
|
283
|
-
// reporting the wheel/clicks and native scrollback works again — don't wait for detach.
|
|
284
|
-
mouseBuf = "";
|
|
285
|
-
clearWheel();
|
|
286
|
-
if (process.stdout.isTTY)
|
|
287
|
-
process.stdout.write(MOUSE_OFF);
|
|
288
|
-
}
|
|
289
|
-
};
|
|
290
|
-
const sendResize = () => transport.resize(process.stdout.columns ?? 80, process.stdout.rows ?? 24);
|
|
291
|
-
const onInput = (data) => {
|
|
292
|
-
// Under the console, Ink has called `stdin.setEncoding("utf8")`, and an encoding persists on
|
|
293
|
-
// the stream after Ink releases raw mode, so data arrives as a STRING there (the standalone
|
|
294
|
-
// command gets Buffers). Normalize first: the one-byte detach compare below would otherwise
|
|
295
|
-
// silently never match (a one-character string is not the number 0x1d), Ctrl-] would just
|
|
296
|
-
// forward to the child, and detaching from a console attach would be impossible.
|
|
297
|
-
const d = Buffer.isBuffer(data) ? data : Buffer.from(data, "utf8");
|
|
298
|
-
if (isDetachPress(d, detach.byte)) {
|
|
299
|
-
clearWheel();
|
|
300
|
-
transport.close();
|
|
301
|
-
return;
|
|
302
|
-
}
|
|
303
|
-
// Inline child: forward keystrokes raw (its wheel scrolls the local terminal, not the app).
|
|
304
|
-
if (!term.altScreen) {
|
|
305
|
-
transport.send(d);
|
|
306
|
-
return;
|
|
307
|
-
}
|
|
308
|
-
// Full-screen child: rewrite wheel reports to PageUp/PageDown, pass everything else through.
|
|
309
|
-
// Wheel reports are coalesced ACROSS stdin reads; raw input flushes the pending wheel first so
|
|
310
|
-
// keyboard/mouse ordering remains exact.
|
|
311
|
-
mouseBuf += d.toString("latin1");
|
|
312
|
-
let out = "";
|
|
313
|
-
const flushOut = () => {
|
|
314
|
-
if (!out)
|
|
315
|
-
return;
|
|
316
|
-
transport.send(Buffer.from(out, "latin1"));
|
|
317
|
-
out = "";
|
|
318
|
-
};
|
|
319
|
-
const appendRaw = (raw) => {
|
|
320
|
-
if (!raw)
|
|
321
|
-
return;
|
|
322
|
-
flushWheel();
|
|
323
|
-
out += raw;
|
|
324
|
-
};
|
|
325
|
-
for (;;) {
|
|
326
|
-
const i = mouseBuf.indexOf("\x1b[<");
|
|
327
|
-
if (i === -1) {
|
|
328
|
-
// A report split right before `<` (`ESC[` now, `<…M` next) would slip through untranslated:
|
|
329
|
-
// hold a trailing `ESC[` for the next read. Never hold a bare trailing `ESC` — that's the
|
|
330
|
-
// Escape key and must forward at once (e.g. OpenCode's interrupt); the rarer `ESC`|`[<…`
|
|
331
|
-
// split stays raw by design.
|
|
332
|
-
const keep = mouseBuf.endsWith("\x1b[") ? 2 : 0;
|
|
333
|
-
appendRaw(mouseBuf.slice(0, mouseBuf.length - keep));
|
|
334
|
-
mouseBuf = mouseBuf.slice(mouseBuf.length - keep);
|
|
335
|
-
break;
|
|
336
|
-
}
|
|
337
|
-
appendRaw(mouseBuf.slice(0, i));
|
|
338
|
-
const rest = mouseBuf.slice(i);
|
|
339
|
-
const m = SGR_MOUSE.exec(rest);
|
|
340
|
-
if (!m) {
|
|
341
|
-
// Hold only a still-valid partial report (`ESC[<` + digits/semicolons) for the next read;
|
|
342
|
-
// anything else can't become an SGR mouse report, so pass it straight through.
|
|
343
|
-
if (/^\x1b\[<[\d;]*$/.test(rest))
|
|
344
|
-
mouseBuf = rest;
|
|
345
|
-
else {
|
|
346
|
-
appendRaw(rest);
|
|
347
|
-
mouseBuf = "";
|
|
348
|
-
}
|
|
349
|
-
break;
|
|
350
|
-
}
|
|
351
|
-
const btn = Number(m[1]);
|
|
352
|
-
if (btn & 0x40) {
|
|
353
|
-
flushOut();
|
|
354
|
-
queueWheel(btn & 1 ? 1 : -1); // wheel: 64=up, 65=down
|
|
355
|
-
}
|
|
356
|
-
else
|
|
357
|
-
appendRaw(m[0]); // other mouse (click/drag): forward raw so the TUI still gets it
|
|
358
|
-
mouseBuf = rest.slice(m[0].length);
|
|
359
|
-
}
|
|
360
|
-
flushOut();
|
|
361
|
-
};
|
|
362
|
-
const cleanup = () => {
|
|
363
|
-
clearWheel();
|
|
364
|
-
stdin.off("data", onInput);
|
|
365
|
-
process.stdout.off("resize", sendResize);
|
|
366
|
-
// Undo terminal modes the (still-running) agent's TUI enabled — it won't restore us on detach.
|
|
367
|
-
// If the child put us in its alternate screen, leave it too so the terminal isn't stranded in
|
|
368
|
-
// the alt buffer; an inline child keeps its scrollback. Only when this session OWNS the
|
|
369
|
-
// terminal: a reconnecting caller undoes it once, after the last attempt, so the screen does
|
|
370
|
-
// not flash back to the shell and get repainted over between sessions.
|
|
371
|
-
if (ownsTerminal)
|
|
372
|
-
term.restore();
|
|
373
|
-
else if (tookStdin)
|
|
374
|
-
stdin.pause();
|
|
375
|
-
};
|
|
376
|
-
transport.onReady(() => {
|
|
377
|
-
// Take stdin from whoever was holding it BETWEEN sessions, synchronously and before anything
|
|
378
|
-
// below touches the stream. A reconnecting caller keeps a reader installed for the whole
|
|
379
|
-
// non-session period so bytes typed at a terminal with no session are read and dropped rather
|
|
380
|
-
// than buffered; without this handoff both readers would be live at once and a detach byte
|
|
381
|
-
// would be seen twice. Synchronous by construction: `data` is emitted on a later tick, so the
|
|
382
|
-
// gap between the caller's `off` and the `on` below cannot lose a byte.
|
|
383
|
-
//
|
|
384
|
-
// It ANSWERS, because the byte it may have just eaten is a detach. The caller's reader owns
|
|
385
|
-
// stdin until this line, and this line runs when the session is READY, which is a round trip
|
|
386
|
-
// after the caller announced the reconnect. A key pressed in between is seen by that reader
|
|
387
|
-
// and by nobody else: without this branch the operator's detach vanishes and the session they
|
|
388
|
-
// meant to leave comes up and keeps their keystrokes. So a press that already landed detaches
|
|
389
|
-
// the session that is opening, before it takes the terminal or reads a byte.
|
|
390
|
-
if (takeStdin?.()) {
|
|
391
|
-
transport.close();
|
|
392
|
-
return;
|
|
393
|
-
}
|
|
394
|
-
// Make an override visible (the CLI's "attached to X — Ctrl-] to detach" hint still prints the
|
|
395
|
-
// default label). Only on override, so the default case stays free of duplicate noise.
|
|
396
|
-
if (detach.overridden)
|
|
397
|
-
console.error(c.dim(`detach key: ${detach.label} (from ${detach.from})`));
|
|
398
|
-
term.enterRaw();
|
|
399
|
-
stdin.resume();
|
|
400
|
-
tookStdin = true;
|
|
401
|
-
sendResize();
|
|
402
|
-
process.stdout.on("resize", sendResize);
|
|
403
|
-
stdin.on("data", onInput);
|
|
404
|
-
});
|
|
405
|
-
transport.onData(async (data) => {
|
|
406
|
-
carried = true;
|
|
407
|
-
trackAltScreen(data);
|
|
408
|
-
await writeStdout(data);
|
|
409
|
-
});
|
|
410
|
-
transport.onEnd((err, reason) => {
|
|
411
|
-
cleanup();
|
|
412
|
-
// The reason is DATA, not an exception: a reconnecting caller reads it to decide whether the
|
|
413
|
-
// link broke or the session finished. A transport with nothing to say about a faulted end
|
|
414
|
-
// reports `error`, which is never in the transport-class set; the loop exits non-zero on it
|
|
415
|
-
// rather than calling it a detach, so an unnamed fault is still loud.
|
|
416
|
-
resolve({ reason: reason ?? (err ? "error" : "detached"), carried, ...(err ? { error: err } : {}) });
|
|
417
|
-
});
|
|
418
|
-
});
|
|
419
|
-
}
|
|
420
|
-
/**
|
|
421
|
-
* The mesh §13.6 SESSION transport: the item-6 replacement for the loopback WebSocket. Given a
|
|
422
|
-
* connection scoped to the session's eps rails and the redeemed grant, it opens the caller rail,
|
|
423
|
-
* asks the serving side to replay the reconstructed backlog (the `ready` handshake — PR #158 over
|
|
424
|
-
* the mesh), and speaks the core terminal-session frame codec. A `drop` frame is surfaced INLINE
|
|
425
|
-
* (never a silent loss); a peer `end`/close or a protocol fault ends the session with the distinct
|
|
426
|
-
* reason. No `127.0.0.1`, no bearer URL — the grant is holder-bound.
|
|
427
|
-
*/
|
|
428
|
-
export function meshSessionTransport(nc, grant) {
|
|
429
|
-
let onDataCb;
|
|
430
|
-
let onEndCb;
|
|
431
|
-
let onReadyCb;
|
|
432
|
-
let ended = false;
|
|
433
|
-
let repaintTimer;
|
|
434
|
-
let rail;
|
|
435
|
-
const fireEnd = (err, reason) => {
|
|
436
|
-
if (ended)
|
|
437
|
-
return;
|
|
438
|
-
ended = true;
|
|
439
|
-
if (repaintTimer)
|
|
440
|
-
clearTimeout(repaintTimer);
|
|
441
|
-
repaintTimer = undefined;
|
|
442
|
-
onEndCb?.(err, reason);
|
|
443
|
-
};
|
|
444
|
-
// Schedule after the rail's async handler returns so the reverse data frame piggybacks the NEW
|
|
445
|
-
// receive watermark, including the drop notice itself. That ack reopens the serving window before
|
|
446
|
-
// the repeat `ready` asks for a fresh canonical screen snapshot.
|
|
447
|
-
const requestRepaint = () => {
|
|
448
|
-
if (ended || repaintTimer)
|
|
449
|
-
return;
|
|
450
|
-
repaintTimer = setTimeout(() => {
|
|
451
|
-
repaintTimer = undefined;
|
|
452
|
-
if (ended)
|
|
453
|
-
return;
|
|
454
|
-
try {
|
|
455
|
-
rail.send({ k: "ready" });
|
|
456
|
-
}
|
|
457
|
-
catch { /* broken/full: the rail fault path ends the session */ }
|
|
458
|
-
}, 0);
|
|
459
|
-
repaintTimer.unref?.();
|
|
460
|
-
};
|
|
461
|
-
rail = openSessionRail({
|
|
462
|
-
nc,
|
|
463
|
-
grant,
|
|
464
|
-
role: "caller",
|
|
465
|
-
onData: async (data) => {
|
|
466
|
-
let frame;
|
|
467
|
-
try {
|
|
468
|
-
frame = decodeTerminalFrame(data);
|
|
469
|
-
}
|
|
470
|
-
catch {
|
|
471
|
-
return;
|
|
472
|
-
} // garbled: the rail already surfaced it
|
|
473
|
-
if (frame.k === "data")
|
|
474
|
-
await onDataCb?.(Buffer.from(terminalFrameBytes(frame)));
|
|
475
|
-
else if (frame.k === "end")
|
|
476
|
-
fireEnd(undefined, frame.reason);
|
|
477
|
-
else if (frame.k === "drop") {
|
|
478
|
-
await onDataCb?.(Buffer.from(`\r\n[cotal: ${frame.bytes} bytes dropped - backpressure]\r\n`));
|
|
479
|
-
requestRepaint();
|
|
480
|
-
}
|
|
481
|
-
},
|
|
482
|
-
onClose: () => fireEnd(undefined, "peer-closed"),
|
|
483
|
-
// The fault NAME rides alongside the error. It used to live only inside the message, where the
|
|
484
|
-
// only way to tell a broken link from a finished session was to parse English.
|
|
485
|
-
onProtocolError: (reason) => fireEnd(new Error(`mesh session transport error: ${reason}`), reason),
|
|
486
|
-
});
|
|
487
|
-
// The connection going away ends the session, and says so. Without this a link that dies past the
|
|
488
|
-
// serving side's stall watchdog leaves the caller subscribed to a session nobody is serving: the
|
|
489
|
-
// manager's `end` and `close` frames were published while this side was disconnected and EPS has
|
|
490
|
-
// no retention, so they are simply gone, and the attach hangs on a dead session with no output,
|
|
491
|
-
// no error and no end. `nc.closed()` is the one signal that still arrives.
|
|
492
|
-
void nc.closed().then((err) => fireEnd(err ?? undefined, "connection-closed"));
|
|
493
|
-
// The caller's `out` subscription must be live before the serving side is asked to replay (EPS is
|
|
494
|
-
// at-most-once, no retention). flush() forces the SUB, then we send `ready` and go.
|
|
495
|
-
void nc.flush().then(() => {
|
|
496
|
-
if (ended)
|
|
497
|
-
return;
|
|
498
|
-
try {
|
|
499
|
-
rail.send({ k: "ready" });
|
|
500
|
-
}
|
|
501
|
-
catch { /* broken/full: the onProtocolError path ends the session */ }
|
|
502
|
-
onReadyCb?.();
|
|
503
|
-
// A flush that FAILS means the connection went away before the session ever opened, which is the
|
|
504
|
-
// link and not the session. Without a reason here the end reads as a plain `error`, which is in
|
|
505
|
-
// no classification, so a reconnect would treat a link that died between connect() and the first
|
|
506
|
-
// flush as a finished session and stop: the exact failure this path exists to remove, in the
|
|
507
|
-
// window where a flapping link is most likely to land.
|
|
508
|
-
}).catch((e) => fireEnd(e, "connection-closed"));
|
|
509
|
-
return {
|
|
510
|
-
onReady: (cb) => { onReadyCb = cb; },
|
|
511
|
-
onData: (cb) => { onDataCb = cb; },
|
|
512
|
-
onEnd: (cb) => { onEndCb = cb; },
|
|
513
|
-
send: (bytes) => { try {
|
|
514
|
-
rail.send(encodeTerminalData(bytes));
|
|
515
|
-
}
|
|
516
|
-
catch { /* interactive keystrokes are low-volume; a stuck window ends via the stall watchdog */ } },
|
|
517
|
-
// Guard degenerate geometry: the §13.6 codec rejects a non-positive dimension (a terminal
|
|
518
|
-
// reporting 0 during a transient) — never emit it (the serving side tolerates it regardless).
|
|
519
|
-
resize: (cols, rows) => { if (cols > 0 && rows > 0) {
|
|
520
|
-
try {
|
|
521
|
-
rail.send({ k: "resize", cols, rows });
|
|
522
|
-
}
|
|
523
|
-
catch { /* advisory */ }
|
|
524
|
-
} },
|
|
525
|
-
close: () => { rail.close(); fireEnd(undefined, "detached"); },
|
|
526
|
-
};
|
|
527
|
-
}
|
|
528
|
-
//# sourceMappingURL=attach-client.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"attach-client.js","sourceRoot":"","sources":["../../src/lib/attach-client.ts"],"names":[],"mappings":"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"}
|