@pentoshi/clai 3.11.7 → 3.11.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -0
- package/dist/agent/confirm-port.d.ts +4 -0
- package/dist/agent/confirm-port.js +9 -1
- package/dist/agent/confirm-port.js.map +1 -1
- package/dist/agent/finalize-gate.d.ts +57 -0
- package/dist/agent/finalize-gate.js +146 -0
- package/dist/agent/finalize-gate.js.map +1 -0
- package/dist/agent/runner.js +71 -179
- package/dist/agent/runner.js.map +1 -1
- package/dist/agent/tool-call-parser.js +3 -0
- package/dist/agent/tool-call-parser.js.map +1 -1
- package/dist/app/adapters/current-interactive-sessions-adapter.d.ts +4 -0
- package/dist/app/adapters/current-interactive-sessions-adapter.js +12 -0
- package/dist/app/adapters/current-interactive-sessions-adapter.js.map +1 -0
- package/dist/app/controllers/cancel-all-result.d.ts +8 -0
- package/dist/app/controllers/cancel-all-result.js +32 -0
- package/dist/app/controllers/cancel-all-result.js.map +1 -0
- package/dist/app/controllers/session-controller.d.ts +3 -0
- package/dist/app/controllers/session-controller.js +22 -6
- package/dist/app/controllers/session-controller.js.map +1 -1
- package/dist/app/ports/interactive-sessions-port.d.ts +22 -0
- package/dist/app/ports/interactive-sessions-port.js +9 -0
- package/dist/app/ports/interactive-sessions-port.js.map +1 -0
- package/dist/index.js +24 -13
- package/dist/index.js.map +1 -1
- package/dist/interactive-session/artifact-writer.d.ts +54 -0
- package/dist/interactive-session/artifact-writer.js +161 -0
- package/dist/interactive-session/artifact-writer.js.map +1 -0
- package/dist/interactive-session/cleanup.d.ts +37 -0
- package/dist/interactive-session/cleanup.js +191 -0
- package/dist/interactive-session/cleanup.js.map +1 -0
- package/dist/interactive-session/config.d.ts +118 -0
- package/dist/interactive-session/config.js +141 -0
- package/dist/interactive-session/config.js.map +1 -0
- package/dist/interactive-session/input-policy.d.ts +26 -0
- package/dist/interactive-session/input-policy.js +70 -0
- package/dist/interactive-session/input-policy.js.map +1 -0
- package/dist/interactive-session/manager.d.ts +118 -0
- package/dist/interactive-session/manager.js +1214 -0
- package/dist/interactive-session/manager.js.map +1 -0
- package/dist/interactive-session/output-store.d.ts +81 -0
- package/dist/interactive-session/output-store.js +239 -0
- package/dist/interactive-session/output-store.js.map +1 -0
- package/dist/interactive-session/output-view.d.ts +20 -0
- package/dist/interactive-session/output-view.js +142 -0
- package/dist/interactive-session/output-view.js.map +1 -0
- package/dist/interactive-session/recovery-journal.d.ts +53 -0
- package/dist/interactive-session/recovery-journal.js +167 -0
- package/dist/interactive-session/recovery-journal.js.map +1 -0
- package/dist/interactive-session/registry.d.ts +59 -0
- package/dist/interactive-session/registry.js +170 -0
- package/dist/interactive-session/registry.js.map +1 -0
- package/dist/interactive-session/runtime.d.ts +107 -0
- package/dist/interactive-session/runtime.js +191 -0
- package/dist/interactive-session/runtime.js.map +1 -0
- package/dist/interactive-session/session-runtime.d.ts +53 -0
- package/dist/interactive-session/session-runtime.js +65 -0
- package/dist/interactive-session/session-runtime.js.map +1 -0
- package/dist/interactive-session/streaming-redactor.d.ts +53 -0
- package/dist/interactive-session/streaming-redactor.js +271 -0
- package/dist/interactive-session/streaming-redactor.js.map +1 -0
- package/dist/interactive-session/telemetry.d.ts +30 -0
- package/dist/interactive-session/telemetry.js +47 -0
- package/dist/interactive-session/telemetry.js.map +1 -0
- package/dist/interactive-session/transport-factory.d.ts +8 -0
- package/dist/interactive-session/transport-factory.js +16 -0
- package/dist/interactive-session/transport-factory.js.map +1 -0
- package/dist/interactive-session/transport-node-pty.d.ts +38 -0
- package/dist/interactive-session/transport-node-pty.js +390 -0
- package/dist/interactive-session/transport-node-pty.js.map +1 -0
- package/dist/interactive-session/transport-pipe.d.ts +9 -0
- package/dist/interactive-session/transport-pipe.js +267 -0
- package/dist/interactive-session/transport-pipe.js.map +1 -0
- package/dist/interactive-session/transport.d.ts +110 -0
- package/dist/interactive-session/transport.js +89 -0
- package/dist/interactive-session/transport.js.map +1 -0
- package/dist/interactive-session/types.d.ts +258 -0
- package/dist/interactive-session/types.js +191 -0
- package/dist/interactive-session/types.js.map +1 -0
- package/dist/os/process-identity.d.ts +46 -0
- package/dist/os/process-identity.js +147 -0
- package/dist/os/process-identity.js.map +1 -0
- package/dist/os/process-tree.d.ts +1 -0
- package/dist/os/process-tree.js +11 -0
- package/dist/os/process-tree.js.map +1 -1
- package/dist/prompts/embedded.js +1 -1
- package/dist/prompts/embedded.js.map +1 -1
- package/dist/prompts/index.d.ts +7 -0
- package/dist/prompts/index.js +23 -0
- package/dist/prompts/index.js.map +1 -1
- package/dist/prompts/system.agent.md +3 -0
- package/dist/repl.js +16 -1
- package/dist/repl.js.map +1 -1
- package/dist/safety/classifier.d.ts +9 -0
- package/dist/safety/classifier.js +119 -18
- package/dist/safety/classifier.js.map +1 -1
- package/dist/safety/engagement-policy.d.ts +13 -0
- package/dist/safety/engagement-policy.js +129 -34
- package/dist/safety/engagement-policy.js.map +1 -1
- package/dist/tools/definitions.js +94 -0
- package/dist/tools/definitions.js.map +1 -1
- package/dist/tools/interactive-session-tools.d.ts +11 -0
- package/dist/tools/interactive-session-tools.js +276 -0
- package/dist/tools/interactive-session-tools.js.map +1 -0
- package/dist/tools/registry.js +3 -0
- package/dist/tools/registry.js.map +1 -1
- package/dist/tui-v2/bootstrap/composition-root.d.ts +3 -0
- package/dist/tui-v2/bootstrap/composition-root.js +3 -0
- package/dist/tui-v2/bootstrap/composition-root.js.map +1 -1
- package/dist/tui-v2/bootstrap/start-tui-v2.js +8 -0
- package/dist/tui-v2/bootstrap/start-tui-v2.js.map +1 -1
- package/dist/types.d.ts +1 -0
- package/dist/version.generated.d.ts +2 -2
- package/dist/version.generated.js +2 -2
- package/package.json +7 -6
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Managed-pipe transport. Used directly for `terminalMode: "pipe"` and as the
|
|
3
|
+
* single fallback for `"preferred"` when PTY capability is unavailable.
|
|
4
|
+
*
|
|
5
|
+
* This module never imports or probes PTY code, and it does not touch the spawn
|
|
6
|
+
* options used by `shell.ts` or `jobs.ts`.
|
|
7
|
+
*/
|
|
8
|
+
import { spawn } from "node:child_process";
|
|
9
|
+
import { augmentedPathEnv } from "../os/command.js";
|
|
10
|
+
import { processIdentityTracker } from "../os/process-identity.js";
|
|
11
|
+
import { supportsProcessGroups, terminateProcessTree, } from "../os/process-tree.js";
|
|
12
|
+
import { resolveShell } from "../tools/shell.js";
|
|
13
|
+
import { LaunchFailure, pipeControlAction, } from "./transport.js";
|
|
14
|
+
class PipeTransport {
|
|
15
|
+
child;
|
|
16
|
+
kind = "pipe";
|
|
17
|
+
pid;
|
|
18
|
+
processGroupId;
|
|
19
|
+
identity;
|
|
20
|
+
outputListeners = new Set();
|
|
21
|
+
exitListeners = new Set();
|
|
22
|
+
pendingOutput = [];
|
|
23
|
+
inputClosed = false;
|
|
24
|
+
exited = false;
|
|
25
|
+
outcome;
|
|
26
|
+
disposed = false;
|
|
27
|
+
outputStarted = false;
|
|
28
|
+
outputDrained = false;
|
|
29
|
+
resolveOutputDrain;
|
|
30
|
+
outputDrain = new Promise((resolve) => {
|
|
31
|
+
this.resolveOutputDrain = resolve;
|
|
32
|
+
});
|
|
33
|
+
constructor(child) {
|
|
34
|
+
this.child = child;
|
|
35
|
+
this.pid = child.pid ?? -1;
|
|
36
|
+
this.processGroupId = supportsProcessGroups() ? child.pid : undefined;
|
|
37
|
+
this.identity = processIdentityTracker.capture(child.pid, { refresh: true });
|
|
38
|
+
child.stdout?.on("data", (chunk) => this.emitOutput("stdout", chunk));
|
|
39
|
+
child.stderr?.on("data", (chunk) => this.emitOutput("stderr", chunk));
|
|
40
|
+
child.stdout?.pause();
|
|
41
|
+
child.stderr?.pause();
|
|
42
|
+
// A broken input pipe after the child exits is an expected race, not a crash.
|
|
43
|
+
child.stdin?.on("error", () => undefined);
|
|
44
|
+
child.on("exit", (code, signal) => {
|
|
45
|
+
this.exited = true;
|
|
46
|
+
const outcome = {
|
|
47
|
+
endedAt: Date.now(),
|
|
48
|
+
...(code !== null ? { exitCode: code } : {}),
|
|
49
|
+
...(signal ? { signal } : {}),
|
|
50
|
+
};
|
|
51
|
+
this.outcome = outcome;
|
|
52
|
+
for (const listener of [...this.exitListeners])
|
|
53
|
+
listener(outcome);
|
|
54
|
+
});
|
|
55
|
+
child.once("close", () => {
|
|
56
|
+
this.outputDrained = true;
|
|
57
|
+
this.resolveOutputDrain();
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
emitOutput(stream, chunk) {
|
|
61
|
+
const event = {
|
|
62
|
+
stream,
|
|
63
|
+
bytes: new Uint8Array(chunk),
|
|
64
|
+
observedAt: Date.now(),
|
|
65
|
+
};
|
|
66
|
+
if (!this.outputStarted) {
|
|
67
|
+
this.pendingOutput.push(event);
|
|
68
|
+
this.pauseOutput();
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
for (const listener of [...this.outputListeners])
|
|
72
|
+
listener(event);
|
|
73
|
+
}
|
|
74
|
+
async write(bytes) {
|
|
75
|
+
const stdin = this.child.stdin;
|
|
76
|
+
if (!stdin || this.inputClosed || stdin.destroyed || this.exited) {
|
|
77
|
+
return { status: "not-delivered", deliveredBytes: 0 };
|
|
78
|
+
}
|
|
79
|
+
return await new Promise((resolve) => {
|
|
80
|
+
let settled = false;
|
|
81
|
+
const settle = (result) => {
|
|
82
|
+
if (settled)
|
|
83
|
+
return;
|
|
84
|
+
settled = true;
|
|
85
|
+
resolve(result);
|
|
86
|
+
};
|
|
87
|
+
try {
|
|
88
|
+
stdin.write(Buffer.from(bytes), (error) => {
|
|
89
|
+
// The callback fires after the bytes leave our buffer. A late error
|
|
90
|
+
// cannot prove whether the child observed them, so it is `unknown`.
|
|
91
|
+
if (error)
|
|
92
|
+
settle({ status: "unknown", deliveredBytes: bytes.length, cause: error });
|
|
93
|
+
else
|
|
94
|
+
settle({ status: "delivered", deliveredBytes: bytes.length });
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
settle({ status: "not-delivered", deliveredBytes: 0, cause: error });
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
async control(action) {
|
|
103
|
+
const mapped = pipeControlAction(action);
|
|
104
|
+
if (mapped.kind === "unsupported") {
|
|
105
|
+
return { status: "not-delivered", deliveredBytes: 0 };
|
|
106
|
+
}
|
|
107
|
+
if (mapped.kind === "bytes")
|
|
108
|
+
return await this.write(mapped.bytes);
|
|
109
|
+
if (mapped.kind === "close-input")
|
|
110
|
+
return await this.closeInput();
|
|
111
|
+
// Interrupt/suspend target the whole tree so a shell wrapper cannot swallow
|
|
112
|
+
// the signal while the real workload keeps running.
|
|
113
|
+
const outcome = terminateProcessTree(this.pid, {
|
|
114
|
+
signal: mapped.signal,
|
|
115
|
+
...(this.processGroupId !== undefined ? { processGroupId: this.processGroupId } : {}),
|
|
116
|
+
});
|
|
117
|
+
return outcome === "failed"
|
|
118
|
+
? { status: "unknown", deliveredBytes: 0 }
|
|
119
|
+
: { status: "delivered", deliveredBytes: 0 };
|
|
120
|
+
}
|
|
121
|
+
async closeInput() {
|
|
122
|
+
if (this.inputClosed)
|
|
123
|
+
return { status: "delivered", deliveredBytes: 0 };
|
|
124
|
+
this.inputClosed = true;
|
|
125
|
+
try {
|
|
126
|
+
this.child.stdin?.end();
|
|
127
|
+
return { status: "delivered", deliveredBytes: 0 };
|
|
128
|
+
}
|
|
129
|
+
catch (error) {
|
|
130
|
+
return { status: "unknown", deliveredBytes: 0, cause: error };
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
pauseOutput() {
|
|
134
|
+
this.child.stdout?.pause();
|
|
135
|
+
this.child.stderr?.pause();
|
|
136
|
+
}
|
|
137
|
+
resumeOutput() {
|
|
138
|
+
this.child.stdout?.resume();
|
|
139
|
+
this.child.stderr?.resume();
|
|
140
|
+
}
|
|
141
|
+
async requestTreeTermination(kind) {
|
|
142
|
+
return terminateProcessTree(this.pid, {
|
|
143
|
+
signal: kind === "graceful" ? "SIGTERM" : "SIGKILL",
|
|
144
|
+
...(this.processGroupId !== undefined ? { processGroupId: this.processGroupId } : {}),
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
onOutput(listener) {
|
|
148
|
+
this.outputListeners.add(listener);
|
|
149
|
+
if (!this.outputStarted) {
|
|
150
|
+
this.outputStarted = true;
|
|
151
|
+
for (const event of this.pendingOutput.splice(0)) {
|
|
152
|
+
for (const outputListener of [...this.outputListeners]) {
|
|
153
|
+
outputListener(event);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
this.child.stdout?.resume();
|
|
157
|
+
this.child.stderr?.resume();
|
|
158
|
+
}
|
|
159
|
+
return () => {
|
|
160
|
+
this.outputListeners.delete(listener);
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
onExit(listener) {
|
|
164
|
+
this.exitListeners.add(listener);
|
|
165
|
+
if (this.outcome)
|
|
166
|
+
queueMicrotask(() => listener(this.outcome));
|
|
167
|
+
return () => {
|
|
168
|
+
this.exitListeners.delete(listener);
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
async waitForOutputDrain() {
|
|
172
|
+
if (this.outputDrained)
|
|
173
|
+
return;
|
|
174
|
+
await this.outputDrain;
|
|
175
|
+
}
|
|
176
|
+
async dispose() {
|
|
177
|
+
if (this.disposed)
|
|
178
|
+
return;
|
|
179
|
+
this.disposed = true;
|
|
180
|
+
this.outputListeners.clear();
|
|
181
|
+
this.exitListeners.clear();
|
|
182
|
+
this.pendingOutput.length = 0;
|
|
183
|
+
try {
|
|
184
|
+
this.child.stdin?.destroy();
|
|
185
|
+
this.child.stdout?.destroy();
|
|
186
|
+
this.child.stderr?.destroy();
|
|
187
|
+
}
|
|
188
|
+
catch {
|
|
189
|
+
// Streams may already be torn down by the exit path.
|
|
190
|
+
}
|
|
191
|
+
this.child.removeAllListeners();
|
|
192
|
+
processIdentityTracker.forget(this.child.pid);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
/** Wait for the OS to confirm (or refuse) the spawn before reporting a launch. */
|
|
196
|
+
function waitForSpawn(child) {
|
|
197
|
+
return new Promise((resolve) => {
|
|
198
|
+
const onSpawn = () => {
|
|
199
|
+
child.off("error", onError);
|
|
200
|
+
resolve(undefined);
|
|
201
|
+
};
|
|
202
|
+
const onError = (error) => {
|
|
203
|
+
child.off("spawn", onSpawn);
|
|
204
|
+
resolve(error);
|
|
205
|
+
};
|
|
206
|
+
child.once("spawn", onSpawn);
|
|
207
|
+
child.once("error", onError);
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
export async function startPipeTransport(request) {
|
|
211
|
+
const shell = resolveShell();
|
|
212
|
+
if (!shell) {
|
|
213
|
+
throw new LaunchFailure("SHELL_NOT_FOUND", "No usable command shell was found for an interactive session.", false, false);
|
|
214
|
+
}
|
|
215
|
+
const child = spawn(request.command, {
|
|
216
|
+
cwd: request.cwd,
|
|
217
|
+
shell,
|
|
218
|
+
detached: supportsProcessGroups(),
|
|
219
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
220
|
+
env: { ...(request.env ?? process.env), PATH: augmentedPathEnv() },
|
|
221
|
+
windowsHide: true,
|
|
222
|
+
});
|
|
223
|
+
let transport;
|
|
224
|
+
let identityNotified = false;
|
|
225
|
+
try {
|
|
226
|
+
if (child.pid) {
|
|
227
|
+
transport = new PipeTransport(child);
|
|
228
|
+
request.onLaunchIdentity?.({
|
|
229
|
+
pid: transport.pid,
|
|
230
|
+
processGroupId: transport.processGroupId,
|
|
231
|
+
identity: transport.identity,
|
|
232
|
+
});
|
|
233
|
+
identityNotified = true;
|
|
234
|
+
}
|
|
235
|
+
const error = await waitForSpawn(child);
|
|
236
|
+
if (error) {
|
|
237
|
+
throw new LaunchFailure(error.code ?? "UNKNOWN", `Interactive session launch failed before spawn: ${error.code ?? "UNKNOWN"}.`, Boolean(child.pid), error.code === "ENOENT" || error.code === "EAGAIN");
|
|
238
|
+
}
|
|
239
|
+
if (!child.pid) {
|
|
240
|
+
throw new LaunchFailure("NO_PID", "The interactive session process reported no process id after spawn.", true, false);
|
|
241
|
+
}
|
|
242
|
+
transport ??= new PipeTransport(child);
|
|
243
|
+
if (!identityNotified) {
|
|
244
|
+
request.onLaunchIdentity?.({
|
|
245
|
+
pid: transport.pid,
|
|
246
|
+
processGroupId: transport.processGroupId,
|
|
247
|
+
identity: transport.identity,
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
return { transport };
|
|
251
|
+
}
|
|
252
|
+
catch (error) {
|
|
253
|
+
try {
|
|
254
|
+
await transport?.requestTreeTermination("forceful");
|
|
255
|
+
}
|
|
256
|
+
catch { }
|
|
257
|
+
try {
|
|
258
|
+
child.kill("SIGKILL");
|
|
259
|
+
}
|
|
260
|
+
catch { }
|
|
261
|
+
await transport?.dispose().catch(() => undefined);
|
|
262
|
+
if (error instanceof LaunchFailure)
|
|
263
|
+
throw error;
|
|
264
|
+
throw new LaunchFailure("LAUNCH_IDENTITY_FAILED", "Interactive session launch identity could not be persisted.", Boolean(child.pid), false);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
//# sourceMappingURL=transport-pipe.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transport-pipe.js","sourceRoot":"","sources":["../../src/interactive-session/transport-pipe.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session transport contracts plus the single centralized table that maps text
|
|
3
|
+
* submission and named controls onto transport/platform byte sequences.
|
|
4
|
+
*
|
|
5
|
+
* A launch is confirmed only after the OS acknowledges spawn. Host stdin is
|
|
6
|
+
* never inherited: agent-controlled sessions must not be able to take the
|
|
7
|
+
* user's controlling terminal.
|
|
8
|
+
*/
|
|
9
|
+
import type { TreeSignalOutcome } from "../os/process-tree.js";
|
|
10
|
+
import type { Unsubscribe } from "./runtime.js";
|
|
11
|
+
import type { ControlInput, OutputStream, ProcessOutcome, SessionTransportKind, SubmitBehavior, TerminalDimensions } from "./types.js";
|
|
12
|
+
export interface TransportOutput {
|
|
13
|
+
readonly stream: OutputStream;
|
|
14
|
+
readonly bytes: Uint8Array;
|
|
15
|
+
readonly observedAt: number;
|
|
16
|
+
}
|
|
17
|
+
export type DeliveryResult = {
|
|
18
|
+
readonly status: "delivered";
|
|
19
|
+
readonly deliveredBytes: number;
|
|
20
|
+
} | {
|
|
21
|
+
readonly status: "not-delivered";
|
|
22
|
+
readonly deliveredBytes: 0;
|
|
23
|
+
readonly cause?: unknown;
|
|
24
|
+
} | {
|
|
25
|
+
readonly status: "unknown";
|
|
26
|
+
readonly deliveredBytes: number;
|
|
27
|
+
readonly cause?: unknown;
|
|
28
|
+
};
|
|
29
|
+
export interface SessionTransport {
|
|
30
|
+
readonly kind: SessionTransportKind;
|
|
31
|
+
readonly pid: number;
|
|
32
|
+
readonly processGroupId?: number | undefined;
|
|
33
|
+
/** Hashed start-time evidence captured at launch confirmation. */
|
|
34
|
+
readonly identity: string | undefined;
|
|
35
|
+
write(bytes: Uint8Array): Promise<DeliveryResult>;
|
|
36
|
+
control(action: ControlInput): Promise<DeliveryResult>;
|
|
37
|
+
closeInput(): Promise<DeliveryResult>;
|
|
38
|
+
resize?(dimensions: TerminalDimensions): Promise<void>;
|
|
39
|
+
pauseOutput(): void;
|
|
40
|
+
resumeOutput(): void;
|
|
41
|
+
requestTreeTermination(kind: "graceful" | "forceful"): Promise<TreeSignalOutcome>;
|
|
42
|
+
onOutput(listener: (event: TransportOutput) => void): Unsubscribe;
|
|
43
|
+
onExit(listener: (outcome: ProcessOutcome) => void): Unsubscribe;
|
|
44
|
+
/** Settles after transport output sources can emit no additional bytes. */
|
|
45
|
+
waitForOutputDrain?(): Promise<void>;
|
|
46
|
+
dispose(): Promise<void>;
|
|
47
|
+
}
|
|
48
|
+
export interface LaunchIdentity {
|
|
49
|
+
readonly pid: number;
|
|
50
|
+
readonly processGroupId?: number | undefined;
|
|
51
|
+
readonly identity: string | undefined;
|
|
52
|
+
}
|
|
53
|
+
export interface LaunchRequest {
|
|
54
|
+
readonly command: string;
|
|
55
|
+
readonly cwd: string;
|
|
56
|
+
readonly env?: NodeJS.ProcessEnv | undefined;
|
|
57
|
+
readonly onLaunchIdentity?: ((identity: LaunchIdentity) => void) | undefined;
|
|
58
|
+
}
|
|
59
|
+
export interface LaunchResult {
|
|
60
|
+
readonly transport: SessionTransport;
|
|
61
|
+
}
|
|
62
|
+
export interface PtyCapability {
|
|
63
|
+
readonly available: boolean;
|
|
64
|
+
readonly platform: NodeJS.Platform;
|
|
65
|
+
/** Non-secret diagnostic for why PTY is unavailable on this target. */
|
|
66
|
+
readonly reason?: string | undefined;
|
|
67
|
+
}
|
|
68
|
+
export interface SessionTransportFactory {
|
|
69
|
+
capability(platform?: NodeJS.Platform): Promise<PtyCapability>;
|
|
70
|
+
startPipe(request: LaunchRequest): Promise<LaunchResult>;
|
|
71
|
+
startPty(request: LaunchRequest & {
|
|
72
|
+
dimensions: TerminalDimensions;
|
|
73
|
+
}): Promise<LaunchResult>;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* A transient pre-spawn failure proves no process side effect occurred, so the
|
|
77
|
+
* manager may retry the launch exactly once.
|
|
78
|
+
*/
|
|
79
|
+
export declare class LaunchFailure extends Error {
|
|
80
|
+
readonly code: string;
|
|
81
|
+
readonly spawnConfirmed: boolean;
|
|
82
|
+
readonly transient: boolean;
|
|
83
|
+
constructor(code: string, message: string, spawnConfirmed: boolean, transient: boolean);
|
|
84
|
+
}
|
|
85
|
+
/** PTY line discipline expects CR; a pipe expects LF. */
|
|
86
|
+
export declare function enterSequence(kind: SessionTransportKind): Uint8Array;
|
|
87
|
+
export declare function encodeTextInput(text: string, submit: SubmitBehavior, kind: SessionTransportKind): Uint8Array;
|
|
88
|
+
/**
|
|
89
|
+
* Byte payload for a named control on a PTY. `undefined` means the control has
|
|
90
|
+
* no byte form on that platform and must be reported as unsupported or handled
|
|
91
|
+
* out of band (signals on a pipe).
|
|
92
|
+
*/
|
|
93
|
+
export declare function ptyControlBytes(action: ControlInput, platform?: NodeJS.Platform): Uint8Array | undefined;
|
|
94
|
+
/**
|
|
95
|
+
* Pipe controls: `interrupt`/`suspend` are process signals because there is no
|
|
96
|
+
* line discipline, `eof` half-closes stdin, and the rest are the same bytes a
|
|
97
|
+
* terminal would have delivered.
|
|
98
|
+
*/
|
|
99
|
+
export type PipeControlAction = {
|
|
100
|
+
readonly kind: "signal";
|
|
101
|
+
readonly signal: NodeJS.Signals;
|
|
102
|
+
} | {
|
|
103
|
+
readonly kind: "bytes";
|
|
104
|
+
readonly bytes: Uint8Array;
|
|
105
|
+
} | {
|
|
106
|
+
readonly kind: "close-input";
|
|
107
|
+
} | {
|
|
108
|
+
readonly kind: "unsupported";
|
|
109
|
+
};
|
|
110
|
+
export declare function pipeControlAction(action: ControlInput, platform?: NodeJS.Platform): PipeControlAction;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session transport contracts plus the single centralized table that maps text
|
|
3
|
+
* submission and named controls onto transport/platform byte sequences.
|
|
4
|
+
*
|
|
5
|
+
* A launch is confirmed only after the OS acknowledges spawn. Host stdin is
|
|
6
|
+
* never inherited: agent-controlled sessions must not be able to take the
|
|
7
|
+
* user's controlling terminal.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* A transient pre-spawn failure proves no process side effect occurred, so the
|
|
11
|
+
* manager may retry the launch exactly once.
|
|
12
|
+
*/
|
|
13
|
+
export class LaunchFailure extends Error {
|
|
14
|
+
code;
|
|
15
|
+
spawnConfirmed;
|
|
16
|
+
transient;
|
|
17
|
+
constructor(code, message, spawnConfirmed, transient) {
|
|
18
|
+
super(message);
|
|
19
|
+
this.code = code;
|
|
20
|
+
this.spawnConfirmed = spawnConfirmed;
|
|
21
|
+
this.transient = transient;
|
|
22
|
+
this.name = "LaunchFailure";
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
// --- Text and control mappings ------------------------------------------
|
|
26
|
+
/** PTY line discipline expects CR; a pipe expects LF. */
|
|
27
|
+
export function enterSequence(kind) {
|
|
28
|
+
return Buffer.from(kind === "pty" ? "\r" : "\n", "utf8");
|
|
29
|
+
}
|
|
30
|
+
export function encodeTextInput(text, submit, kind) {
|
|
31
|
+
const body = Buffer.from(text, "utf8");
|
|
32
|
+
if (submit === "none")
|
|
33
|
+
return body;
|
|
34
|
+
return Buffer.concat([body, Buffer.from(enterSequence(kind))]);
|
|
35
|
+
}
|
|
36
|
+
const ARROWS = {
|
|
37
|
+
up: "\u001b[A",
|
|
38
|
+
down: "\u001b[B",
|
|
39
|
+
right: "\u001b[C",
|
|
40
|
+
left: "\u001b[D",
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Byte payload for a named control on a PTY. `undefined` means the control has
|
|
44
|
+
* no byte form on that platform and must be reported as unsupported or handled
|
|
45
|
+
* out of band (signals on a pipe).
|
|
46
|
+
*/
|
|
47
|
+
export function ptyControlBytes(action, platform = process.platform) {
|
|
48
|
+
switch (action) {
|
|
49
|
+
case "interrupt":
|
|
50
|
+
return Buffer.from([0x03]);
|
|
51
|
+
case "eof":
|
|
52
|
+
// Windows consoles terminate input with Ctrl+Z followed by Enter.
|
|
53
|
+
return platform === "win32"
|
|
54
|
+
? Buffer.from([0x1a, 0x0d])
|
|
55
|
+
: Buffer.from([0x04]);
|
|
56
|
+
case "suspend":
|
|
57
|
+
return platform === "win32" ? undefined : Buffer.from([0x1a]);
|
|
58
|
+
case "escape":
|
|
59
|
+
return Buffer.from([0x1b]);
|
|
60
|
+
case "tab":
|
|
61
|
+
return Buffer.from([0x09]);
|
|
62
|
+
case "backspace":
|
|
63
|
+
return Buffer.from([0x7f]);
|
|
64
|
+
case "up":
|
|
65
|
+
case "down":
|
|
66
|
+
case "left":
|
|
67
|
+
case "right":
|
|
68
|
+
return Buffer.from(ARROWS[action], "utf8");
|
|
69
|
+
default:
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
export function pipeControlAction(action, platform = process.platform) {
|
|
74
|
+
if (action === "interrupt") {
|
|
75
|
+
return platform === "win32"
|
|
76
|
+
? { kind: "signal", signal: "SIGTERM" }
|
|
77
|
+
: { kind: "signal", signal: "SIGINT" };
|
|
78
|
+
}
|
|
79
|
+
if (action === "suspend") {
|
|
80
|
+
return platform === "win32"
|
|
81
|
+
? { kind: "unsupported" }
|
|
82
|
+
: { kind: "signal", signal: "SIGTSTP" };
|
|
83
|
+
}
|
|
84
|
+
if (action === "eof")
|
|
85
|
+
return { kind: "close-input" };
|
|
86
|
+
const bytes = ptyControlBytes(action, platform);
|
|
87
|
+
return bytes ? { kind: "bytes", bytes } : { kind: "unsupported" };
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=transport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transport.js","sourceRoot":"","sources":["../../src/interactive-session/transport.ts"],"names":[],"mappings":"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"}
|