@rikkainc/ccp 0.2.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.
Files changed (39) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +5 -0
  3. package/dist/cli/claude-pty-wrapper.d.ts +2 -0
  4. package/dist/cli/claude-pty-wrapper.js +421 -0
  5. package/dist/cli/claude-pty-wrapper.js.map +1 -0
  6. package/dist/cli/main.d.ts +2 -0
  7. package/dist/cli/main.js +4 -0
  8. package/dist/cli/main.js.map +1 -0
  9. package/dist/core/claude-paths.d.ts +7 -0
  10. package/dist/core/claude-paths.js +64 -0
  11. package/dist/core/claude-paths.js.map +1 -0
  12. package/dist/core/claude-records.d.ts +8 -0
  13. package/dist/core/claude-records.js +78 -0
  14. package/dist/core/claude-records.js.map +1 -0
  15. package/dist/core/claude-session-tail.d.ts +13 -0
  16. package/dist/core/claude-session-tail.js +88 -0
  17. package/dist/core/claude-session-tail.js.map +1 -0
  18. package/dist/core/errors.d.ts +5 -0
  19. package/dist/core/errors.js +15 -0
  20. package/dist/core/errors.js.map +1 -0
  21. package/dist/core/passthrough.d.ts +23 -0
  22. package/dist/core/passthrough.js +347 -0
  23. package/dist/core/passthrough.js.map +1 -0
  24. package/dist/core/pty-runner.d.ts +22 -0
  25. package/dist/core/pty-runner.js +40 -0
  26. package/dist/core/pty-runner.js.map +1 -0
  27. package/dist/core/stream-json.d.ts +16 -0
  28. package/dist/core/stream-json.js +149 -0
  29. package/dist/core/stream-json.js.map +1 -0
  30. package/dist/core/terminal-text.d.ts +1 -0
  31. package/dist/core/terminal-text.js +58 -0
  32. package/dist/core/terminal-text.js.map +1 -0
  33. package/dist/core/wrapper.d.ts +34 -0
  34. package/dist/core/wrapper.js +299 -0
  35. package/dist/core/wrapper.js.map +1 -0
  36. package/docs/stream-json.md +82 -0
  37. package/docs/usage.md +104 -0
  38. package/package.json +50 -0
  39. package/scripts/fix-node-pty-perms.mjs +27 -0
@@ -0,0 +1,78 @@
1
+ export function isRecord(value) {
2
+ return typeof value === "object" && value !== null && !Array.isArray(value);
3
+ }
4
+ export function claudeContentBlocks(content) {
5
+ if (!Array.isArray(content)) {
6
+ return [];
7
+ }
8
+ return content.filter(isRecord);
9
+ }
10
+ export function extractClaudeText(content) {
11
+ if (typeof content === "string") {
12
+ return content;
13
+ }
14
+ let combined = "";
15
+ for (const item of claudeContentBlocks(content)) {
16
+ if (typeof item.text === "string") {
17
+ combined += streamBoundarySeparator(combined, item.text);
18
+ combined += item.text;
19
+ }
20
+ }
21
+ return combined;
22
+ }
23
+ export function isAllToolResultContent(content) {
24
+ const blocks = claudeContentBlocks(content);
25
+ return blocks.length > 0 && blocks.every((block) => block.type === "tool_result");
26
+ }
27
+ export function realClaudeUserText(record) {
28
+ if (record.type !== "user" || record.isSidechain === true || !isRecord(record.message)) {
29
+ return null;
30
+ }
31
+ const content = record.message.content;
32
+ if (isAllToolResultContent(content)) {
33
+ return null;
34
+ }
35
+ const text = extractClaudeText(content);
36
+ const trimmed = text.trim();
37
+ // Claude persists internal task-runner wakeups as user-looking records; they
38
+ // should not start a wrapper output turn.
39
+ if (trimmed.length === 0 || trimmed.startsWith("<task-notification>")) {
40
+ return null;
41
+ }
42
+ return text;
43
+ }
44
+ export function claudeAssistantRecordText(record) {
45
+ if (record.type !== "assistant" || record.isSidechain === true || !isRecord(record.message)) {
46
+ return null;
47
+ }
48
+ const text = extractClaudeText(record.message.content);
49
+ return text.length > 0 ? text : null;
50
+ }
51
+ export function isClaudeTurnTerminalRecord(record) {
52
+ return (record.type === "system" && record.subtype === "turn_duration" && record.isSidechain !== true);
53
+ }
54
+ export function streamBoundarySeparator(prior, delta) {
55
+ if (prior.length === 0) {
56
+ return "";
57
+ }
58
+ let trailing = 0;
59
+ for (let i = prior.length - 1; i >= 0; i--) {
60
+ if (prior[i] === "\n") {
61
+ trailing++;
62
+ }
63
+ else {
64
+ break;
65
+ }
66
+ }
67
+ let leading = 0;
68
+ for (let i = 0; i < delta.length; i++) {
69
+ if (delta[i] === "\n") {
70
+ leading++;
71
+ }
72
+ else {
73
+ break;
74
+ }
75
+ }
76
+ return "\n".repeat(Math.max(0, 2 - trailing - leading));
77
+ }
78
+ //# sourceMappingURL=claude-records.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-records.js","sourceRoot":"","sources":["../../src/core/claude-records.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ export interface TailJsonlOptions {
2
+ path: string;
3
+ startOffset: number;
4
+ signal: AbortSignal;
5
+ pollMs?: number;
6
+ maxLineLength?: number;
7
+ }
8
+ export interface TailJsonlRecord {
9
+ line: string;
10
+ record: Record<string, unknown>;
11
+ offsetEnd: number;
12
+ }
13
+ export declare function tailJsonl(options: TailJsonlOptions): AsyncGenerator<TailJsonlRecord>;
@@ -0,0 +1,88 @@
1
+ import { createReadStream } from "node:fs";
2
+ import { stat } from "node:fs/promises";
3
+ import { basename } from "node:path";
4
+ import { ClaudePtyWrapperError } from "./errors.js";
5
+ export async function* tailJsonl(options) {
6
+ let offset = options.startOffset;
7
+ let buffer = "";
8
+ const pollMs = options.pollMs ?? 50;
9
+ const maxLineLength = options.maxLineLength ?? 16 * 1024 * 1024;
10
+ while (!options.signal.aborted) {
11
+ const size = await currentSize(options.path);
12
+ if (size === null || size <= offset) {
13
+ await delay(pollMs, options.signal);
14
+ continue;
15
+ }
16
+ const chunk = await readRange(options.path, offset, size);
17
+ offset = size;
18
+ buffer += chunk;
19
+ if (buffer.length > maxLineLength) {
20
+ throw new ClaudePtyWrapperError(`failed to parse Claude session history ${basename(options.path)}: line exceeds ${maxLineLength} bytes`);
21
+ }
22
+ let newlineIndex;
23
+ while ((newlineIndex = buffer.indexOf("\n")) >= 0) {
24
+ const line = buffer.slice(0, newlineIndex);
25
+ buffer = buffer.slice(newlineIndex + 1);
26
+ if (line.trim().length === 0) {
27
+ continue;
28
+ }
29
+ let parsed;
30
+ try {
31
+ parsed = JSON.parse(line);
32
+ }
33
+ catch {
34
+ throw new ClaudePtyWrapperError(`failed to parse Claude session history ${basename(options.path)}: invalid JSON`);
35
+ }
36
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
37
+ throw new ClaudePtyWrapperError(`failed to parse Claude session history ${basename(options.path)}: record is not an object`);
38
+ }
39
+ yield { line, record: parsed, offsetEnd: offset - buffer.length };
40
+ }
41
+ }
42
+ }
43
+ async function currentSize(path) {
44
+ try {
45
+ return (await stat(path)).size;
46
+ }
47
+ catch (error) {
48
+ if (isNodeError(error) && error.code === "ENOENT") {
49
+ return null;
50
+ }
51
+ throw error;
52
+ }
53
+ }
54
+ async function readRange(path, start, endExclusive) {
55
+ const chunks = [];
56
+ const stream = createReadStream(path, {
57
+ encoding: "utf8",
58
+ start,
59
+ end: endExclusive - 1,
60
+ });
61
+ for await (const chunk of stream) {
62
+ chunks.push(chunk);
63
+ }
64
+ return chunks.join("");
65
+ }
66
+ async function delay(ms, signal) {
67
+ if (signal.aborted) {
68
+ return;
69
+ }
70
+ let onAbort = null;
71
+ await new Promise((resolve) => {
72
+ const timeout = setTimeout(resolve, ms);
73
+ onAbort = () => {
74
+ clearTimeout(timeout);
75
+ resolve();
76
+ };
77
+ signal.addEventListener("abort", onAbort, { once: true });
78
+ timeout.unref();
79
+ }).finally(() => {
80
+ if (onAbort !== null) {
81
+ signal.removeEventListener("abort", onAbort);
82
+ }
83
+ });
84
+ }
85
+ function isNodeError(error) {
86
+ return typeof error === "object" && error !== null && "code" in error;
87
+ }
88
+ //# sourceMappingURL=claude-session-tail.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-session-tail.js","sourceRoot":"","sources":["../../src/core/claude-session-tail.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export declare class ClaudePtyWrapperError extends Error {
2
+ readonly exitCode: number;
3
+ constructor(message: string, exitCode?: number);
4
+ }
5
+ export declare function errorMessage(error: unknown): string;
@@ -0,0 +1,15 @@
1
+ export class ClaudePtyWrapperError extends Error {
2
+ exitCode;
3
+ constructor(message, exitCode = 1) {
4
+ super(message);
5
+ this.name = "ClaudePtyWrapperError";
6
+ this.exitCode = exitCode;
7
+ }
8
+ }
9
+ export function errorMessage(error) {
10
+ if (error instanceof Error) {
11
+ return error.message;
12
+ }
13
+ return String(error);
14
+ }
15
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,qBAAsB,SAAQ,KAAK;IACrC,QAAQ,CAAS;IAE1B,YAAY,OAAe,EAAE,QAAQ,GAAG,CAAC;QACvC,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,uBAAuB,CAAC;QACpC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;CACF;AAED,MAAM,UAAU,YAAY,CAAC,KAAc;IACzC,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAC3B,OAAO,KAAK,CAAC,OAAO,CAAC;IACvB,CAAC;IACD,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC"}
@@ -0,0 +1,23 @@
1
+ export interface ClaudePassthroughOptions {
2
+ claudeBin: string;
3
+ cwd: string;
4
+ args: string[];
5
+ freshness?: FreshnessOptions;
6
+ env?: NodeJS.ProcessEnv;
7
+ }
8
+ export interface ClaudeLoginOnlyOptions {
9
+ claudeBin: string;
10
+ cwd: string;
11
+ args: string[];
12
+ timeoutMs: number;
13
+ rawPtyLog?: string;
14
+ env?: NodeJS.ProcessEnv;
15
+ }
16
+ export interface FreshnessOptions {
17
+ intervalMs: number;
18
+ message: string;
19
+ maxIterations?: number;
20
+ maxDurationMs?: number;
21
+ }
22
+ export declare function runClaudePassthrough(options: ClaudePassthroughOptions): Promise<number>;
23
+ export declare function runClaudeLoginOnly(options: ClaudeLoginOnlyOptions): Promise<number>;
@@ -0,0 +1,347 @@
1
+ import { resolve } from "node:path";
2
+ import { StringDecoder } from "node:string_decoder";
3
+ import { ClaudePtyWrapperError, errorMessage } from "./errors.js";
4
+ import { openRawPtyLog, spawnPty } from "./pty-runner.js";
5
+ import { normalizeTerminalText } from "./terminal-text.js";
6
+ export async function runClaudePassthrough(options) {
7
+ let ptyHandle;
8
+ const freshness = options.freshness ? createFreshnessController(options.freshness) : null;
9
+ try {
10
+ ptyHandle = spawnPty({
11
+ command: options.claudeBin,
12
+ args: options.args,
13
+ cwd: resolve(options.cwd),
14
+ env: options.env ?? process.env,
15
+ cols: terminalCols(),
16
+ rows: terminalRows(),
17
+ onData: (data) => {
18
+ freshness?.noteActivity();
19
+ process.stdout.write(data);
20
+ },
21
+ });
22
+ }
23
+ catch (error) {
24
+ throw new ClaudePtyWrapperError(`failed to spawn Claude: ${errorMessage(error)}`);
25
+ }
26
+ const stdin = process.stdin;
27
+ const previousRawMode = stdin.isTTY ? stdin.isRaw : undefined;
28
+ const stdinDecoder = new StringDecoder("utf8");
29
+ let ptyExited = false;
30
+ let cleaningUpForSignal = false;
31
+ const onStdinData = (chunk) => {
32
+ freshness?.noteActivity();
33
+ ptyHandle.write(Buffer.isBuffer(chunk) ? stdinDecoder.write(chunk) : chunk);
34
+ };
35
+ const onResize = () => {
36
+ try {
37
+ ptyHandle.resize(terminalCols(), terminalRows());
38
+ }
39
+ catch { }
40
+ };
41
+ const restoreStdin = () => {
42
+ stdin.off("data", onStdinData);
43
+ if (stdin.isTTY &&
44
+ typeof stdin.setRawMode === "function" &&
45
+ typeof previousRawMode === "boolean") {
46
+ stdin.setRawMode(previousRawMode);
47
+ }
48
+ stdin.pause();
49
+ };
50
+ const cleanupListeners = () => {
51
+ process.off("SIGWINCH", onResize);
52
+ for (const signal of relayCleanupSignals) {
53
+ process.off(signal, onProcessSignal);
54
+ }
55
+ };
56
+ const onProcessSignal = (signal) => {
57
+ cleaningUpForSignal = true;
58
+ freshness?.stop();
59
+ cleanupListeners();
60
+ restoreStdin();
61
+ try {
62
+ ptyHandle.kill(signal);
63
+ }
64
+ catch { }
65
+ process.kill(process.pid, signal);
66
+ };
67
+ try {
68
+ if (stdin.isTTY && typeof stdin.setRawMode === "function") {
69
+ stdin.setRawMode(true);
70
+ }
71
+ stdin.resume();
72
+ stdin.on("data", onStdinData);
73
+ process.on("SIGWINCH", onResize);
74
+ for (const signal of relayCleanupSignals) {
75
+ process.once(signal, onProcessSignal);
76
+ }
77
+ freshness?.start((message) => ptyHandle.write(`${message}\r`));
78
+ const exit = await ptyHandle.waitForExit();
79
+ ptyExited = true;
80
+ return ptyExitCode(exit);
81
+ }
82
+ finally {
83
+ freshness?.stop();
84
+ cleanupListeners();
85
+ restoreStdin();
86
+ if (!ptyExited && !cleaningUpForSignal) {
87
+ try {
88
+ ptyHandle.kill("SIGTERM");
89
+ }
90
+ catch { }
91
+ }
92
+ }
93
+ }
94
+ export async function runClaudeLoginOnly(options) {
95
+ let ptyHandle;
96
+ const rawLog = openRawPtyLog(options.rawPtyLog);
97
+ const inputReady = createClaudeInputReadyDetector();
98
+ let readyResolve = null;
99
+ const readyPromise = new Promise((resolveReady) => {
100
+ readyResolve = resolveReady;
101
+ });
102
+ try {
103
+ ptyHandle = spawnPty({
104
+ command: options.claudeBin,
105
+ args: options.args,
106
+ cwd: resolve(options.cwd),
107
+ env: options.env ?? process.env,
108
+ cols: terminalCols(),
109
+ rows: terminalRows(),
110
+ onData: (data) => {
111
+ rawLog?.write(data);
112
+ process.stdout.write(data);
113
+ if (inputReady(data)) {
114
+ readyResolve?.();
115
+ readyResolve = null;
116
+ }
117
+ },
118
+ });
119
+ }
120
+ catch (error) {
121
+ rawLog?.end();
122
+ throw new ClaudePtyWrapperError(`failed to spawn Claude: ${errorMessage(error)}`);
123
+ }
124
+ const stdin = process.stdin;
125
+ const previousRawMode = stdin.isTTY ? stdin.isRaw : undefined;
126
+ const stdinDecoder = new StringDecoder("utf8");
127
+ let ptyExited = false;
128
+ let cleaningUpForSignal = false;
129
+ const onStdinData = (chunk) => {
130
+ ptyHandle.write(Buffer.isBuffer(chunk) ? stdinDecoder.write(chunk) : chunk);
131
+ };
132
+ const onResize = () => {
133
+ try {
134
+ ptyHandle.resize(terminalCols(), terminalRows());
135
+ }
136
+ catch { }
137
+ };
138
+ const restoreStdin = () => {
139
+ stdin.off("data", onStdinData);
140
+ if (stdin.isTTY &&
141
+ typeof stdin.setRawMode === "function" &&
142
+ typeof previousRawMode === "boolean") {
143
+ stdin.setRawMode(previousRawMode);
144
+ }
145
+ stdin.pause();
146
+ };
147
+ const cleanupListeners = () => {
148
+ process.off("SIGWINCH", onResize);
149
+ for (const signal of relayCleanupSignals) {
150
+ process.off(signal, onProcessSignal);
151
+ }
152
+ };
153
+ const onProcessSignal = (signal) => {
154
+ cleaningUpForSignal = true;
155
+ cleanupListeners();
156
+ restoreStdin();
157
+ rawLog?.end();
158
+ try {
159
+ ptyHandle.kill(signal);
160
+ }
161
+ catch { }
162
+ process.kill(process.pid, signal);
163
+ };
164
+ try {
165
+ if (stdin.isTTY && typeof stdin.setRawMode === "function") {
166
+ stdin.setRawMode(true);
167
+ }
168
+ stdin.resume();
169
+ stdin.on("data", onStdinData);
170
+ process.on("SIGWINCH", onResize);
171
+ for (const signal of relayCleanupSignals) {
172
+ process.once(signal, onProcessSignal);
173
+ }
174
+ const first = await Promise.race([
175
+ readyPromise.then(() => "ready"),
176
+ ptyHandle.waitForExit().then((exit) => ({ type: "exit", exit })),
177
+ delay(options.timeoutMs).then(() => "timeout"),
178
+ ]);
179
+ if (first === "ready") {
180
+ await closeInteractivePty(ptyHandle);
181
+ ptyExited = true;
182
+ return 0;
183
+ }
184
+ if (first === "timeout") {
185
+ await terminatePty(ptyHandle);
186
+ ptyExited = true;
187
+ return 2;
188
+ }
189
+ ptyExited = true;
190
+ return ptyExitCode(first.exit);
191
+ }
192
+ finally {
193
+ rawLog?.end();
194
+ cleanupListeners();
195
+ restoreStdin();
196
+ if (!ptyExited && !cleaningUpForSignal) {
197
+ try {
198
+ ptyHandle.kill("SIGTERM");
199
+ }
200
+ catch { }
201
+ }
202
+ }
203
+ }
204
+ function createFreshnessController(options) {
205
+ if (options.intervalMs <= 0) {
206
+ throw new ClaudePtyWrapperError("freshness interval must be a positive number of seconds");
207
+ }
208
+ if (options.maxIterations !== undefined && options.maxIterations <= 0) {
209
+ throw new ClaudePtyWrapperError("freshness max iterations must be a positive integer");
210
+ }
211
+ if (options.maxDurationMs !== undefined && options.maxDurationMs <= 0) {
212
+ throw new ClaudePtyWrapperError("freshness max duration must be a positive number of seconds");
213
+ }
214
+ let timer = null;
215
+ let writeFreshnessMessage = null;
216
+ let lastActivityAt = Date.now();
217
+ let iterations = 0;
218
+ let stopped = false;
219
+ let startedAt = Date.now();
220
+ const clearTimer = () => {
221
+ if (timer !== null) {
222
+ clearTimeout(timer);
223
+ timer = null;
224
+ }
225
+ };
226
+ const maxDurationRemaining = () => {
227
+ if (options.maxDurationMs === undefined) {
228
+ return Number.POSITIVE_INFINITY;
229
+ }
230
+ return options.maxDurationMs - (Date.now() - startedAt);
231
+ };
232
+ const schedule = () => {
233
+ clearTimer();
234
+ if (stopped) {
235
+ return;
236
+ }
237
+ const remainingDuration = maxDurationRemaining();
238
+ if (remainingDuration <= 0) {
239
+ stopped = true;
240
+ return;
241
+ }
242
+ const elapsedIdle = Date.now() - lastActivityAt;
243
+ const untilIdle = Math.max(options.intervalMs - elapsedIdle, 0);
244
+ const delay = Math.min(untilIdle, remainingDuration);
245
+ timer = setTimeout(onTimer, delay);
246
+ timer.unref();
247
+ };
248
+ const onTimer = () => {
249
+ timer = null;
250
+ if (stopped) {
251
+ return;
252
+ }
253
+ if (maxDurationRemaining() <= 0) {
254
+ stopped = true;
255
+ return;
256
+ }
257
+ if (Date.now() - lastActivityAt < options.intervalMs) {
258
+ schedule();
259
+ return;
260
+ }
261
+ writeFreshnessMessage?.(options.message);
262
+ iterations += 1;
263
+ lastActivityAt = Date.now();
264
+ if (options.maxIterations !== undefined && iterations >= options.maxIterations) {
265
+ stopped = true;
266
+ return;
267
+ }
268
+ schedule();
269
+ };
270
+ return {
271
+ start(writeMessage) {
272
+ writeFreshnessMessage = writeMessage;
273
+ startedAt = Date.now();
274
+ lastActivityAt = Date.now();
275
+ schedule();
276
+ },
277
+ noteActivity() {
278
+ if (stopped) {
279
+ return;
280
+ }
281
+ lastActivityAt = Date.now();
282
+ schedule();
283
+ },
284
+ stop() {
285
+ stopped = true;
286
+ clearTimer();
287
+ },
288
+ };
289
+ }
290
+ function createClaudeInputReadyDetector() {
291
+ let observed = "";
292
+ let detected = false;
293
+ return (data) => {
294
+ if (detected) {
295
+ return true;
296
+ }
297
+ observed = normalizeTerminalText(`${observed}${data}`).slice(-8_000);
298
+ detected =
299
+ (observed.includes("Claude Code") || observed.includes("ClaudeCode")) &&
300
+ (observed.includes("for shortcuts") || observed.includes("forshortcuts")) &&
301
+ observed.includes("❯");
302
+ return detected;
303
+ };
304
+ }
305
+ async function closeInteractivePty(handle) {
306
+ try {
307
+ handle.write("\x04");
308
+ await delay(250);
309
+ handle.write("\x04");
310
+ }
311
+ catch {
312
+ return;
313
+ }
314
+ await Promise.race([handle.waitForExit(), delay(1_000)]);
315
+ await terminatePty(handle);
316
+ }
317
+ async function terminatePty(handle) {
318
+ try {
319
+ handle.kill("SIGTERM");
320
+ }
321
+ catch { }
322
+ await Promise.race([handle.waitForExit(), delay(500)]);
323
+ try {
324
+ handle.kill("SIGKILL");
325
+ }
326
+ catch { }
327
+ }
328
+ async function delay(ms) {
329
+ await new Promise((resolveDelay) => {
330
+ const timeout = setTimeout(resolveDelay, ms);
331
+ timeout.unref();
332
+ });
333
+ }
334
+ function ptyExitCode(exit) {
335
+ if (exit.signal > 0) {
336
+ return 128 + exit.signal;
337
+ }
338
+ return exit.exitCode;
339
+ }
340
+ function terminalCols() {
341
+ return process.stdout.columns ?? 120;
342
+ }
343
+ function terminalRows() {
344
+ return process.stdout.rows ?? 40;
345
+ }
346
+ const relayCleanupSignals = ["SIGINT", "SIGTERM", "SIGHUP"];
347
+ //# sourceMappingURL=passthrough.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"passthrough.js","sourceRoot":"","sources":["../../src/core/passthrough.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import { type WriteStream } from "node:fs";
2
+ export interface PtyRunOptions {
3
+ command: string;
4
+ args: string[];
5
+ cwd: string;
6
+ env: NodeJS.ProcessEnv;
7
+ cols?: number;
8
+ rows?: number;
9
+ onData?: (data: string) => void;
10
+ }
11
+ export interface PtyExit {
12
+ exitCode: number;
13
+ signal: number;
14
+ }
15
+ export interface PtyHandle {
16
+ write(data: string): void;
17
+ resize(cols: number, rows: number): void;
18
+ kill(signal?: string): void;
19
+ waitForExit(): Promise<PtyExit>;
20
+ }
21
+ export declare function spawnPty(options: PtyRunOptions): PtyHandle;
22
+ export declare function openRawPtyLog(path: string | undefined): WriteStream | null;
@@ -0,0 +1,40 @@
1
+ import { createWriteStream } from "node:fs";
2
+ import * as pty from "node-pty";
3
+ export function spawnPty(options) {
4
+ const proc = pty.spawn(options.command, options.args, {
5
+ cwd: options.cwd,
6
+ env: {
7
+ ...options.env,
8
+ TERM: options.env.TERM ?? "xterm-256color",
9
+ },
10
+ cols: options.cols ?? process.stdout.columns ?? 120,
11
+ rows: options.rows ?? process.stdout.rows ?? 40,
12
+ });
13
+ proc.onData((data) => options.onData?.(data));
14
+ const exitPromise = new Promise((resolve) => {
15
+ proc.onExit((event) => {
16
+ resolve({ exitCode: event.exitCode, signal: event.signal ?? 0 });
17
+ });
18
+ });
19
+ return {
20
+ write(data) {
21
+ proc.write(data);
22
+ },
23
+ resize(cols, rows) {
24
+ proc.resize(cols, rows);
25
+ },
26
+ kill(signal) {
27
+ proc.kill(signal);
28
+ },
29
+ waitForExit() {
30
+ return exitPromise;
31
+ },
32
+ };
33
+ }
34
+ export function openRawPtyLog(path) {
35
+ if (!path) {
36
+ return null;
37
+ }
38
+ return createWriteStream(path, { flags: "a" });
39
+ }
40
+ //# sourceMappingURL=pty-runner.js.map