terminal-pilot 0.0.5 → 0.0.7

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 (86) hide show
  1. package/README.md +40 -0
  2. package/dist/ansi.js +68 -63
  3. package/dist/ansi.js.map +7 -0
  4. package/dist/cli.d.ts +2 -0
  5. package/dist/cli.js +6254 -0
  6. package/dist/cli.js.map +7 -0
  7. package/dist/commands/close-session.d.ts +12 -0
  8. package/dist/commands/close-session.js +1509 -0
  9. package/dist/commands/close-session.js.map +7 -0
  10. package/dist/commands/create-session.d.ts +26 -0
  11. package/dist/commands/create-session.js +1516 -0
  12. package/dist/commands/create-session.js.map +7 -0
  13. package/dist/commands/fill.d.ts +10 -0
  14. package/dist/commands/fill.js +1512 -0
  15. package/dist/commands/fill.js.map +7 -0
  16. package/dist/commands/get-session.d.ts +18 -0
  17. package/dist/commands/get-session.js +1514 -0
  18. package/dist/commands/get-session.js.map +7 -0
  19. package/dist/commands/index.d.ts +242 -0
  20. package/dist/commands/index.js +3973 -0
  21. package/dist/commands/index.js.map +7 -0
  22. package/dist/commands/install.d.ts +20 -0
  23. package/dist/commands/install.js +1480 -0
  24. package/dist/commands/install.js.map +7 -0
  25. package/dist/commands/installer.d.ts +43 -0
  26. package/dist/commands/installer.js +289 -0
  27. package/dist/commands/installer.js.map +7 -0
  28. package/dist/commands/list-sessions.d.ts +16 -0
  29. package/dist/commands/list-sessions.js +1513 -0
  30. package/dist/commands/list-sessions.js.map +7 -0
  31. package/dist/commands/press-key.d.ts +10 -0
  32. package/dist/commands/press-key.js +1512 -0
  33. package/dist/commands/press-key.js.map +7 -0
  34. package/dist/commands/read-history.d.ts +16 -0
  35. package/dist/commands/read-history.js +1511 -0
  36. package/dist/commands/read-history.js.map +7 -0
  37. package/dist/commands/read-screen.d.ts +21 -0
  38. package/dist/commands/read-screen.js +1515 -0
  39. package/dist/commands/read-screen.js.map +7 -0
  40. package/dist/commands/resize.d.ts +12 -0
  41. package/dist/commands/resize.js +1512 -0
  42. package/dist/commands/resize.js.map +7 -0
  43. package/dist/commands/runtime.d.ts +36 -0
  44. package/dist/commands/runtime.js +1262 -0
  45. package/dist/commands/runtime.js.map +7 -0
  46. package/dist/commands/screenshot.d.ts +14 -0
  47. package/dist/commands/screenshot.js +2280 -0
  48. package/dist/commands/screenshot.js.map +7 -0
  49. package/dist/commands/send-signal.d.ts +10 -0
  50. package/dist/commands/send-signal.js +1512 -0
  51. package/dist/commands/send-signal.js.map +7 -0
  52. package/dist/commands/type.d.ts +10 -0
  53. package/dist/commands/type.js +1512 -0
  54. package/dist/commands/type.js.map +7 -0
  55. package/dist/commands/uninstall.d.ts +14 -0
  56. package/dist/commands/uninstall.js +529 -0
  57. package/dist/commands/uninstall.js.map +7 -0
  58. package/dist/commands/wait-for-exit.d.ts +14 -0
  59. package/dist/commands/wait-for-exit.js +1513 -0
  60. package/dist/commands/wait-for-exit.js.map +7 -0
  61. package/dist/commands/wait-for.d.ts +20 -0
  62. package/dist/commands/wait-for.js +1520 -0
  63. package/dist/commands/wait-for.js.map +7 -0
  64. package/dist/exports.compile-check.js +1 -1
  65. package/dist/exports.compile-check.js.map +7 -0
  66. package/dist/index.js +1118 -5
  67. package/dist/index.js.map +7 -0
  68. package/dist/keys.js +58 -49
  69. package/dist/keys.js.map +7 -0
  70. package/dist/templates/terminal-pilot.md +45 -0
  71. package/dist/terminal-buffer.d.ts +9 -1
  72. package/dist/terminal-buffer.js +525 -425
  73. package/dist/terminal-buffer.js.map +7 -0
  74. package/dist/terminal-pilot.js +1105 -35
  75. package/dist/terminal-pilot.js.map +7 -0
  76. package/dist/terminal-screen.js +108 -26
  77. package/dist/terminal-screen.js.map +7 -0
  78. package/dist/terminal-session.js +1020 -292
  79. package/dist/terminal-session.js.map +7 -0
  80. package/dist/testing/cli-repl.d.ts +15 -0
  81. package/dist/testing/cli-repl.js +6359 -0
  82. package/dist/testing/cli-repl.js.map +7 -0
  83. package/dist/testing/qa-cli.d.ts +1 -0
  84. package/dist/testing/qa-cli.js +7276 -0
  85. package/dist/testing/qa-cli.js.map +7 -0
  86. package/package.json +37 -7
@@ -1,340 +1,1068 @@
1
+ // src/terminal-session.ts
1
2
  import { spawn as spawnChildProcess } from "node:child_process";
2
3
  import { EventEmitter } from "node:events";
3
4
  import * as nodePty from "node-pty";
4
- import { stripAnsi } from "./ansi.js";
5
- import { TerminalBuffer } from "./terminal-buffer.js";
6
- import { keyToSequence } from "./keys.js";
7
- import { TerminalScreen } from "./terminal-screen.js";
8
- const DEFAULT_COLS = 120;
9
- const DEFAULT_ROWS = 40;
10
- const DEFAULT_TIMEOUT_MS = 10_000;
11
- const WAIT_FOR_POLL_MS = 100;
12
- const TYPE_DELAY_MS = 15;
13
- const CLOSE_AFTER_SIGNAL_GRACE_MS = 250;
14
- export class TerminalSession {
15
- id;
16
- command;
17
- pid;
18
- exitCode = null;
19
- pty;
20
- terminal;
21
- emitter = new EventEmitter();
22
- exitPromise;
23
- rawBuffer = "";
24
- lastDataAt = Date.now();
25
- currentCols;
26
- currentRows;
27
- closeRequested = false;
28
- signalRequested = false;
29
- constructor({ id, command, args = [], cwd = process.cwd(), env = process.env, cols = DEFAULT_COLS, rows = DEFAULT_ROWS, observe = false }) {
30
- this.id = id;
31
- this.command = command;
32
- this.currentCols = cols;
33
- this.currentRows = rows;
34
- this.terminal = new TerminalBuffer(cols, rows);
35
- this.pty = createPtyProcess({ command, args, cwd, env, cols, rows });
36
- this.pid = this.pty.pid;
37
- const dataSubscription = this.pty.onData((chunk) => {
38
- this.rawBuffer += chunk;
39
- this.lastDataAt = Date.now();
40
- this.terminal.write(chunk);
41
- if (observe) {
42
- process.stderr.write(chunk);
43
- }
44
- });
45
- let exitSubscription;
46
- this.exitPromise = new Promise((resolve) => {
47
- exitSubscription = this.pty.onExit(({ exitCode }) => {
48
- if (this.exitCode !== null) {
49
- resolve(this.exitCode);
50
- return;
51
- }
52
- this.exitCode = exitCode;
53
- dataSubscription.dispose();
54
- exitSubscription?.dispose();
55
- this.emitter.emit("exit", exitCode);
56
- resolve(exitCode);
57
- });
5
+
6
+ // src/ansi.ts
7
+ var ESC = 27;
8
+ var BEL = 7;
9
+ var ST = 156;
10
+ var CSI = 155;
11
+ var OSC = 157;
12
+ var DCS = 144;
13
+ var SOS = 152;
14
+ var PM = 158;
15
+ var APC = 159;
16
+ function stripAnsi(input) {
17
+ let output = "";
18
+ for (let index = 0; index < input.length; index += 1) {
19
+ const code = input.charCodeAt(index);
20
+ if (code === ESC) {
21
+ const nextCode = input.charCodeAt(index + 1);
22
+ if (nextCode === 91) {
23
+ index = consumeCsi(input, index + 2);
24
+ continue;
25
+ }
26
+ if (nextCode === 93) {
27
+ index = consumeTerminatedString(input, index + 2, true);
28
+ continue;
29
+ }
30
+ if (nextCode === 80 || nextCode === 88 || nextCode === 94 || nextCode === 95) {
31
+ index = consumeTerminatedString(input, index + 2, false);
32
+ continue;
33
+ }
34
+ if (!Number.isNaN(nextCode)) {
35
+ index += 1;
36
+ }
37
+ continue;
38
+ }
39
+ if (code === CSI) {
40
+ index = consumeCsi(input, index + 1);
41
+ continue;
42
+ }
43
+ if (code === OSC) {
44
+ index = consumeTerminatedString(input, index + 1, true);
45
+ continue;
46
+ }
47
+ if (code === DCS || code === SOS || code === PM || code === APC) {
48
+ index = consumeTerminatedString(input, index + 1, false);
49
+ continue;
50
+ }
51
+ output += input[index];
52
+ }
53
+ return output;
54
+ }
55
+ function consumeCsi(input, index) {
56
+ while (index < input.length) {
57
+ const code = input.charCodeAt(index);
58
+ if (code >= 64 && code <= 126) {
59
+ return index;
60
+ }
61
+ index += 1;
62
+ }
63
+ return input.length;
64
+ }
65
+ function consumeTerminatedString(input, index, allowBellTerminator) {
66
+ while (index < input.length) {
67
+ const code = input.charCodeAt(index);
68
+ if (code === ST || allowBellTerminator && code === BEL) {
69
+ return index;
70
+ }
71
+ if (code === ESC && input.charCodeAt(index + 1) === 92) {
72
+ return index + 1;
73
+ }
74
+ index += 1;
75
+ }
76
+ return input.length;
77
+ }
78
+
79
+ // src/terminal-buffer.ts
80
+ var RESET_SGR = "\x1B[0m";
81
+ var TerminalBuffer = class {
82
+ _cols;
83
+ _rows;
84
+ _screen;
85
+ _cursorX = 0;
86
+ _cursorY = 0;
87
+ _savedCursor = { x: 0, y: 0 };
88
+ _scrollTop = 0;
89
+ _scrollBottom;
90
+ _state = 0 /* Normal */;
91
+ _csiParams = "";
92
+ _csiPrivate = "";
93
+ _style = createDefaultStyleState();
94
+ _styleSequence = "";
95
+ displayBuffer;
96
+ constructor(cols, rows) {
97
+ this._cols = cols;
98
+ this._rows = rows;
99
+ this._scrollBottom = rows - 1;
100
+ this._screen = this._makeScreen(cols, rows);
101
+ this.displayBuffer = Object.defineProperties(
102
+ {},
103
+ {
104
+ cursorX: { get: () => this._cursorX, enumerable: true },
105
+ cursorY: { get: () => this._cursorY, enumerable: true },
106
+ data: { get: () => this._screen, enumerable: true }
107
+ }
108
+ );
109
+ }
110
+ write(data) {
111
+ for (const ch of data) {
112
+ this._feed(ch);
113
+ }
114
+ }
115
+ renderLine(row) {
116
+ const cells = this._screen[row] ?? [];
117
+ let lastVisibleCell = -1;
118
+ for (let index = cells.length - 1; index >= 0; index -= 1) {
119
+ if (cells[index] !== null) {
120
+ lastVisibleCell = index;
121
+ break;
122
+ }
123
+ }
124
+ if (lastVisibleCell === -1) {
125
+ return "";
126
+ }
127
+ let line = "";
128
+ let activeStyle = "";
129
+ for (let index = 0; index <= lastVisibleCell; index += 1) {
130
+ const cell = cells[index];
131
+ const cellStyle = cell?.style ?? "";
132
+ if (cellStyle !== activeStyle) {
133
+ line += cellStyle.length > 0 ? cellStyle : RESET_SGR;
134
+ activeStyle = cellStyle;
135
+ }
136
+ line += cell?.[1] ?? " ";
137
+ }
138
+ if (activeStyle.length > 0) {
139
+ line += RESET_SGR;
140
+ }
141
+ return line;
142
+ }
143
+ resize(cols, rows) {
144
+ while (this._screen.length < rows) {
145
+ this._screen.push(this._makeRow(cols));
146
+ }
147
+ this._screen.length = rows;
148
+ for (let y = 0; y < rows; y++) {
149
+ const row = this._screen[y] ?? this._makeRow(cols);
150
+ while (row.length < cols) row.push(null);
151
+ row.length = cols;
152
+ this._screen[y] = row;
153
+ }
154
+ this._cols = cols;
155
+ this._rows = rows;
156
+ this._scrollTop = 0;
157
+ this._scrollBottom = rows - 1;
158
+ this._cursorX = this._clamp(this._cursorX, 0, cols - 1);
159
+ this._cursorY = this._clamp(this._cursorY, 0, rows - 1);
160
+ }
161
+ _makeScreen(cols, rows) {
162
+ return Array.from({ length: rows }, () => this._makeRow(cols));
163
+ }
164
+ _makeRow(cols) {
165
+ return Array(cols).fill(null);
166
+ }
167
+ _clamp(value, min, max) {
168
+ return Math.max(min, Math.min(max, value));
169
+ }
170
+ _setChar(y, x, ch) {
171
+ const row = this._screen[y];
172
+ if (row && x >= 0 && x < this._cols) {
173
+ const cell = [ch.charCodeAt(0), ch];
174
+ if (this._styleSequence.length > 0) {
175
+ Object.defineProperty(cell, "style", {
176
+ value: this._styleSequence,
177
+ writable: true,
178
+ configurable: true
58
179
  });
180
+ }
181
+ row[x] = cell;
59
182
  }
60
- async type(text) {
61
- for (const character of text) {
62
- await this.send(character);
63
- await sleep(TYPE_DELAY_MS);
64
- }
183
+ }
184
+ _eraseLine(y, fromX, toX) {
185
+ const row = this._screen[y];
186
+ if (!row) return;
187
+ for (let x = fromX; x <= toX && x < this._cols; x++) {
188
+ row[x] = null;
65
189
  }
66
- async fill(text) {
67
- await this.send(text.replace(/\r?\n/g, "\r"));
190
+ }
191
+ _scrollUp(count) {
192
+ for (let i = 0; i < count; i++) {
193
+ this._screen.splice(this._scrollTop, 1);
194
+ this._screen.splice(this._scrollBottom, 0, this._makeRow(this._cols));
68
195
  }
69
- async press(key) {
70
- await this.send(keyToSequence(key));
196
+ }
197
+ _scrollDown(count) {
198
+ for (let i = 0; i < count; i++) {
199
+ this._screen.splice(this._scrollBottom, 1);
200
+ this._screen.splice(this._scrollTop, 0, this._makeRow(this._cols));
71
201
  }
72
- async send(raw) {
73
- if (this.exitCode !== null) {
74
- return;
202
+ }
203
+ _newline() {
204
+ if (this._cursorY === this._scrollBottom) {
205
+ this._scrollUp(1);
206
+ } else {
207
+ this._cursorY = Math.min(this._cursorY + 1, this._rows - 1);
208
+ }
209
+ }
210
+ _parseCsiParams() {
211
+ if (!this._csiParams) return [];
212
+ return this._csiParams.split(";").map((s) => s === "" ? 0 : parseInt(s, 10));
213
+ }
214
+ _execCsi(final) {
215
+ const params = this._parseCsiParams();
216
+ const p0 = params[0] ?? 0;
217
+ const p1 = params[1] ?? 0;
218
+ if (this._csiPrivate === "?") {
219
+ if (final === "h" || final === "l") {
220
+ if (params.includes(1049)) {
221
+ if (final === "h") {
222
+ this._screen = this._makeScreen(this._cols, this._rows);
223
+ this._cursorX = 0;
224
+ this._cursorY = 0;
225
+ } else {
226
+ this._screen = this._makeScreen(this._cols, this._rows);
227
+ this._cursorX = 0;
228
+ this._cursorY = 0;
229
+ }
230
+ this._resetStyle();
75
231
  }
76
- this.pty.write(raw);
232
+ }
233
+ return;
77
234
  }
78
- async signal(sig) {
79
- if (this.exitCode !== null) {
80
- return;
235
+ switch (final) {
236
+ case "A":
237
+ this._cursorY = this._clamp(this._cursorY - Math.max(1, p0), 0, this._rows - 1);
238
+ break;
239
+ case "B":
240
+ this._cursorY = this._clamp(this._cursorY + Math.max(1, p0), 0, this._rows - 1);
241
+ break;
242
+ case "C":
243
+ // cursor forward
244
+ case "a":
245
+ this._cursorX = this._clamp(this._cursorX + Math.max(1, p0), 0, this._cols - 1);
246
+ break;
247
+ case "D":
248
+ this._cursorX = this._clamp(this._cursorX - Math.max(1, p0), 0, this._cols - 1);
249
+ break;
250
+ case "E":
251
+ this._cursorY = this._clamp(this._cursorY + Math.max(1, p0), 0, this._rows - 1);
252
+ this._cursorX = 0;
253
+ break;
254
+ case "F":
255
+ this._cursorY = this._clamp(this._cursorY - Math.max(1, p0), 0, this._rows - 1);
256
+ this._cursorX = 0;
257
+ break;
258
+ case "G":
259
+ // cursor horizontal absolute
260
+ case "`":
261
+ this._cursorX = this._clamp(Math.max(1, p0) - 1, 0, this._cols - 1);
262
+ break;
263
+ case "H":
264
+ // cursor position
265
+ case "f":
266
+ this._cursorY = this._clamp(Math.max(1, p0) - 1, 0, this._rows - 1);
267
+ this._cursorX = this._clamp(Math.max(1, p1) - 1, 0, this._cols - 1);
268
+ break;
269
+ case "I":
270
+ for (let i = 0; i < Math.max(1, p0); i++) {
271
+ this._cursorX = Math.min(this._cols - 1, (Math.floor(this._cursorX / 8) + 1) * 8);
81
272
  }
82
- this.signalRequested = true;
83
- this.pty.kill(sig);
84
- }
85
- async waitFor(pattern, opts) {
86
- const timeout = opts?.timeout ?? DEFAULT_TIMEOUT_MS;
87
- const startedAt = Date.now();
88
- while (Date.now() - startedAt <= timeout) {
89
- const matched = matchPattern(this.rawBuffer, pattern);
90
- if (matched !== null) {
91
- return matched;
92
- }
93
- await sleep(WAIT_FOR_POLL_MS);
273
+ break;
274
+ case "J":
275
+ if (p0 === 0) {
276
+ this._eraseLine(this._cursorY, this._cursorX, this._cols - 1);
277
+ for (let y = this._cursorY + 1; y < this._rows; y++) this._eraseLine(y, 0, this._cols - 1);
278
+ } else if (p0 === 1) {
279
+ for (let y = 0; y < this._cursorY; y++) this._eraseLine(y, 0, this._cols - 1);
280
+ this._eraseLine(this._cursorY, 0, this._cursorX);
281
+ } else if (p0 === 2 || p0 === 3) {
282
+ for (let y = 0; y < this._rows; y++) this._eraseLine(y, 0, this._cols - 1);
94
283
  }
95
- throw new Error(`Timed out waiting for pattern after ${timeout}ms: ${String(pattern)}`);
96
- }
97
- async waitForQuiet(ms) {
98
- while (true) {
99
- const remaining = ms - (Date.now() - this.lastDataAt);
100
- if (remaining <= 0) {
101
- return;
102
- }
103
- await sleep(remaining);
284
+ break;
285
+ case "K":
286
+ if (p0 === 0) this._eraseLine(this._cursorY, this._cursorX, this._cols - 1);
287
+ else if (p0 === 1) this._eraseLine(this._cursorY, 0, this._cursorX);
288
+ else if (p0 === 2) this._eraseLine(this._cursorY, 0, this._cols - 1);
289
+ break;
290
+ case "X":
291
+ this._eraseLine(this._cursorY, this._cursorX, this._cursorX + Math.max(1, p0) - 1);
292
+ break;
293
+ case "L": {
294
+ const n = Math.max(1, p0);
295
+ for (let i = 0; i < n; i++) {
296
+ this._screen.splice(this._scrollBottom, 1);
297
+ this._screen.splice(this._cursorY, 0, this._makeRow(this._cols));
104
298
  }
105
- }
106
- async screen() {
107
- const rawLines = [];
108
- for (let row = 0; row < this.currentRows; row += 1) {
109
- const cells = this.terminal.displayBuffer.data[row] ?? [];
110
- let rawLine = "";
111
- for (const cell of cells) {
112
- rawLine += cell?.[1] ?? " ";
113
- }
114
- rawLines.push(trimTrailingSpaces(rawLine));
299
+ break;
300
+ }
301
+ case "M": {
302
+ const n = Math.max(1, p0);
303
+ for (let i = 0; i < n; i++) {
304
+ this._screen.splice(this._cursorY, 1);
305
+ this._screen.splice(this._scrollBottom, 0, this._makeRow(this._cols));
115
306
  }
116
- return new TerminalScreen({
117
- lines: rawLines,
118
- rawLines,
119
- cursor: {
120
- row: this.terminal.displayBuffer.cursorY,
121
- col: this.terminal.displayBuffer.cursorX
122
- },
123
- size: {
124
- rows: this.currentRows,
125
- cols: this.currentCols
126
- }
127
- });
128
- }
129
- async history(opts) {
130
- const normalized = normalizeHistoryBuffer(stripAnsi(this.rawBuffer));
131
- const lines = splitHistoryLines(normalized);
132
- if (opts?.last === undefined) {
133
- return lines;
307
+ break;
308
+ }
309
+ case "P": {
310
+ const row = this._screen[this._cursorY];
311
+ if (row) {
312
+ const n = Math.max(1, p0);
313
+ row.splice(this._cursorX, n);
314
+ while (row.length < this._cols) row.push(null);
134
315
  }
135
- const start = Math.max(0, lines.length - opts.last);
136
- return lines.slice(start);
137
- }
138
- async resize(cols, rows) {
139
- this.currentCols = cols;
140
- this.currentRows = rows;
141
- if (this.exitCode === null) {
142
- this.pty.resize(cols, rows);
316
+ break;
317
+ }
318
+ case "@": {
319
+ const row = this._screen[this._cursorY];
320
+ if (row) {
321
+ const n = Math.max(1, p0);
322
+ for (let i = 0; i < n; i++) row.splice(this._cursorX, 0, null);
323
+ row.splice(this._cols);
143
324
  }
144
- this.terminal.resize(cols, rows);
145
- }
146
- async waitForExit(opts) {
147
- if (this.exitCode !== null) {
148
- return this.exitCode;
325
+ break;
326
+ }
327
+ case "S":
328
+ this._scrollUp(Math.max(1, p0));
329
+ break;
330
+ case "T":
331
+ if (params.length <= 1) this._scrollDown(Math.max(1, p0));
332
+ break;
333
+ case "Z": {
334
+ const n = Math.max(1, p0);
335
+ for (let i = 0; i < n; i++) {
336
+ this._cursorX = Math.max(0, (Math.ceil(this._cursorX / 8) - 1) * 8);
149
337
  }
150
- if (opts?.timeout !== undefined) {
151
- const result = await waitForExit(this.exitPromise, opts.timeout);
152
- if (result === null) {
153
- throw new Error(`Timed out waiting for process to exit after ${opts.timeout}ms`);
154
- }
155
- return result;
338
+ break;
339
+ }
340
+ case "d":
341
+ this._cursorY = this._clamp(Math.max(1, p0) - 1, 0, this._rows - 1);
342
+ break;
343
+ case "e":
344
+ this._cursorY = this._clamp(this._cursorY + Math.max(1, p0), 0, this._rows - 1);
345
+ break;
346
+ case "r": {
347
+ const top = this._clamp(Math.max(1, p0) - 1, 0, this._rows - 1);
348
+ const bottom = this._clamp((p1 === 0 ? this._rows : p1) - 1, 0, this._rows - 1);
349
+ if (top < bottom) {
350
+ this._scrollTop = top;
351
+ this._scrollBottom = bottom;
156
352
  }
157
- return this.exitPromise;
353
+ this._cursorX = 0;
354
+ this._cursorY = 0;
355
+ break;
356
+ }
357
+ case "s":
358
+ this._savedCursor = { x: this._cursorX, y: this._cursorY };
359
+ break;
360
+ case "u":
361
+ this._cursorX = this._clamp(this._savedCursor.x, 0, this._cols - 1);
362
+ this._cursorY = this._clamp(this._savedCursor.y, 0, this._rows - 1);
363
+ break;
364
+ case "m":
365
+ this._applySgr(params);
366
+ break;
367
+ default:
368
+ break;
158
369
  }
159
- async close() {
160
- if (this.exitCode !== null) {
161
- return this.exitCode;
370
+ }
371
+ _feed(ch) {
372
+ const code = ch.charCodeAt(0);
373
+ switch (this._state) {
374
+ case 0 /* Normal */:
375
+ this._feedNormal(ch, code);
376
+ break;
377
+ case 1 /* Escape */:
378
+ this._feedEscape(ch, code);
379
+ break;
380
+ case 2 /* Csi */:
381
+ this._feedCsi(ch, code);
382
+ break;
383
+ case 3 /* Osc */:
384
+ if (code === 7 || code === 156) {
385
+ this._state = 0 /* Normal */;
386
+ } else if (code === 27) {
387
+ this._state = 0 /* Normal */;
162
388
  }
163
- if (!this.closeRequested) {
164
- this.closeRequested = true;
165
- const gracefulExitCode = await waitForExit(this.exitPromise, CLOSE_AFTER_SIGNAL_GRACE_MS);
166
- if (gracefulExitCode !== null) {
167
- return gracefulExitCode;
168
- }
169
- if (this.signalRequested) {
170
- return this.exitPromise;
171
- }
172
- if (this.exitCode === null) {
173
- this.pty.kill("SIGTERM");
174
- }
389
+ break;
390
+ case 4 /* Str */:
391
+ if (code === 156 || code === 7) {
392
+ this._state = 0 /* Normal */;
393
+ } else if (code === 27) {
394
+ this._state = 0 /* Normal */;
175
395
  }
176
- return this.exitPromise;
396
+ break;
397
+ case 5 /* EscCharset */:
398
+ this._state = 0 /* Normal */;
399
+ break;
400
+ case 6 /* EscHash */:
401
+ this._state = 0 /* Normal */;
402
+ break;
177
403
  }
178
- on(event, cb) {
179
- this.emitter.on(event, cb);
404
+ }
405
+ _feedNormal(ch, code) {
406
+ if (code === 27) {
407
+ this._state = 1 /* Escape */;
408
+ } else if (code === 155) {
409
+ this._csiParams = "";
410
+ this._csiPrivate = "";
411
+ this._state = 2 /* Csi */;
412
+ } else if (code === 157) {
413
+ this._state = 3 /* Osc */;
414
+ } else if (code === 144 || code === 152 || code === 158 || code === 159) {
415
+ this._state = 4 /* Str */;
416
+ } else if (code === 7 || code === 5 || code === 6) {
417
+ } else if (code === 8) {
418
+ if (this._cursorX > 0) this._cursorX--;
419
+ } else if (code === 127) {
420
+ if (this._cursorX > 0) {
421
+ this._cursorX--;
422
+ this._setChar(this._cursorY, this._cursorX, " ");
423
+ }
424
+ } else if (code === 9) {
425
+ this._cursorX = Math.min(this._cols - 1, (Math.floor(this._cursorX / 8) + 1) * 8);
426
+ } else if (code === 10 || code === 11 || code === 12) {
427
+ this._newline();
428
+ } else if (code === 13) {
429
+ this._cursorX = 0;
430
+ } else if (code === 14 || code === 15) {
431
+ } else if (code >= 32 && code !== 127) {
432
+ this._setChar(this._cursorY, this._cursorX, ch);
433
+ this._cursorX++;
434
+ if (this._cursorX >= this._cols) {
435
+ this._cursorX = 0;
436
+ this._newline();
437
+ }
180
438
  }
439
+ }
440
+ _feedEscape(ch, code) {
441
+ this._state = 0 /* Normal */;
442
+ if (code === 91) {
443
+ this._csiParams = "";
444
+ this._csiPrivate = "";
445
+ this._state = 2 /* Csi */;
446
+ } else if (code === 93) {
447
+ this._state = 3 /* Osc */;
448
+ } else if (code === 80 || code === 88 || code === 94 || code === 95) {
449
+ this._state = 4 /* Str */;
450
+ } else if (code === 40 || code === 41 || code === 42 || code === 43 || code === 45 || code === 46) {
451
+ this._state = 5 /* EscCharset */;
452
+ } else if (code === 35) {
453
+ this._state = 6 /* EscHash */;
454
+ } else if (code === 55) {
455
+ this._savedCursor = { x: this._cursorX, y: this._cursorY };
456
+ } else if (code === 56) {
457
+ this._cursorX = this._clamp(this._savedCursor.x, 0, this._cols - 1);
458
+ this._cursorY = this._clamp(this._savedCursor.y, 0, this._rows - 1);
459
+ } else if (code === 68) {
460
+ this._newline();
461
+ } else if (code === 69) {
462
+ this._cursorX = 0;
463
+ this._newline();
464
+ } else if (code === 77) {
465
+ if (this._cursorY === this._scrollTop) {
466
+ this._scrollDown(1);
467
+ } else {
468
+ this._cursorY = Math.max(0, this._cursorY - 1);
469
+ }
470
+ } else if (code === 72) {
471
+ } else if (code === 99) {
472
+ this._screen = this._makeScreen(this._cols, this._rows);
473
+ this._cursorX = 0;
474
+ this._cursorY = 0;
475
+ this._savedCursor = { x: 0, y: 0 };
476
+ this._scrollTop = 0;
477
+ this._scrollBottom = this._rows - 1;
478
+ this._resetStyle();
479
+ }
480
+ }
481
+ _feedCsi(ch, code) {
482
+ if (code >= 64 && code <= 126) {
483
+ this._execCsi(ch);
484
+ this._state = 0 /* Normal */;
485
+ } else if (code === 63 || code === 33 || code === 62 || code === 32) {
486
+ this._csiPrivate = ch;
487
+ } else if (code >= 48 && code <= 57 || code === 59) {
488
+ this._csiParams += ch;
489
+ }
490
+ }
491
+ _resetStyle() {
492
+ this._style = createDefaultStyleState();
493
+ this._styleSequence = "";
494
+ }
495
+ _applySgr(params) {
496
+ const normalizedParams = params.length === 0 ? [0] : params;
497
+ for (let index = 0; index < normalizedParams.length; index += 1) {
498
+ const value = normalizedParams[index] ?? 0;
499
+ switch (value) {
500
+ case 0:
501
+ this._resetStyle();
502
+ break;
503
+ case 1:
504
+ this._style.bold = true;
505
+ break;
506
+ case 2:
507
+ this._style.dim = true;
508
+ break;
509
+ case 3:
510
+ this._style.italic = true;
511
+ break;
512
+ case 4:
513
+ this._style.underline = true;
514
+ break;
515
+ case 7:
516
+ this._style.inverse = true;
517
+ break;
518
+ case 9:
519
+ this._style.strikethrough = true;
520
+ break;
521
+ case 21:
522
+ case 22:
523
+ this._style.bold = false;
524
+ this._style.dim = false;
525
+ break;
526
+ case 23:
527
+ this._style.italic = false;
528
+ break;
529
+ case 24:
530
+ this._style.underline = false;
531
+ break;
532
+ case 27:
533
+ this._style.inverse = false;
534
+ break;
535
+ case 29:
536
+ this._style.strikethrough = false;
537
+ break;
538
+ case 39:
539
+ this._style.fg = void 0;
540
+ break;
541
+ case 49:
542
+ this._style.bg = void 0;
543
+ break;
544
+ case 38:
545
+ case 48:
546
+ index = this._applyExtendedColor(value, normalizedParams, index);
547
+ break;
548
+ default:
549
+ if (value >= 30 && value <= 37 || value >= 90 && value <= 97) {
550
+ this._style.fg = [value];
551
+ } else if (value >= 40 && value <= 47 || value >= 100 && value <= 107) {
552
+ this._style.bg = [value];
553
+ }
554
+ break;
555
+ }
556
+ }
557
+ this._styleSequence = serializeStyleState(this._style);
558
+ }
559
+ _applyExtendedColor(control, params, index) {
560
+ const mode = params[index + 1];
561
+ const target = control === 38 ? "fg" : "bg";
562
+ if (mode === 5) {
563
+ const paletteIndex = params[index + 2];
564
+ if (paletteIndex !== void 0) {
565
+ this._style[target] = [control, 5, paletteIndex];
566
+ return index + 2;
567
+ }
568
+ return index;
569
+ }
570
+ if (mode === 2) {
571
+ const red = params[index + 2];
572
+ const green = params[index + 3];
573
+ const blue = params[index + 4];
574
+ if (red !== void 0 && green !== void 0 && blue !== void 0) {
575
+ this._style[target] = [control, 2, red, green, blue];
576
+ return index + 4;
577
+ }
578
+ }
579
+ return index;
580
+ }
581
+ };
582
+ function createDefaultStyleState() {
583
+ return {
584
+ bold: false,
585
+ dim: false,
586
+ italic: false,
587
+ underline: false,
588
+ inverse: false,
589
+ strikethrough: false
590
+ };
181
591
  }
182
- function createPtyProcess({ command, args, cwd, env, cols, rows }) {
183
- try {
184
- return nodePty.spawn(command, args, {
185
- cwd,
186
- env,
187
- cols,
188
- rows,
189
- encoding: "utf8"
190
- });
592
+ function serializeStyleState(state) {
593
+ const codes = [];
594
+ if (state.bold) {
595
+ codes.push(1);
596
+ }
597
+ if (state.dim) {
598
+ codes.push(2);
599
+ }
600
+ if (state.italic) {
601
+ codes.push(3);
602
+ }
603
+ if (state.underline) {
604
+ codes.push(4);
605
+ }
606
+ if (state.inverse) {
607
+ codes.push(7);
608
+ }
609
+ if (state.strikethrough) {
610
+ codes.push(9);
611
+ }
612
+ if (state.fg !== void 0) {
613
+ codes.push(...state.fg);
614
+ }
615
+ if (state.bg !== void 0) {
616
+ codes.push(...state.bg);
617
+ }
618
+ return codes.length === 0 ? "" : `\x1B[${codes.join(";")}m`;
619
+ }
620
+
621
+ // src/keys.ts
622
+ var NAMED_KEY_SEQUENCES = {
623
+ Enter: "\r",
624
+ Tab: " ",
625
+ Escape: "\x1B",
626
+ Backspace: "\x7F",
627
+ Delete: "\x1B[3~",
628
+ ArrowUp: "\x1B[A",
629
+ ArrowDown: "\x1B[B",
630
+ ArrowRight: "\x1B[C",
631
+ ArrowLeft: "\x1B[D",
632
+ Home: "\x1B[H",
633
+ End: "\x1B[F",
634
+ PageUp: "\x1B[5~",
635
+ PageDown: "\x1B[6~",
636
+ Space: " "
637
+ };
638
+ var NAMED_KEY_LOWER = new Map(
639
+ Object.entries(NAMED_KEY_SEQUENCES).map(([k, v]) => [k.toLowerCase(), v])
640
+ );
641
+ var VALID_KEYS_HINT = `Valid keys: ${Object.keys(NAMED_KEY_SEQUENCES).join(", ")}, Control+<letter>, Alt+<key>`;
642
+ function unknownKeyError(key) {
643
+ return new Error(`Unknown terminal key: ${key}. ${VALID_KEYS_HINT}`);
644
+ }
645
+ function keyToSequence(key) {
646
+ const lowerKey = key.toLowerCase();
647
+ const namedSequence = NAMED_KEY_LOWER.get(lowerKey);
648
+ if (namedSequence !== void 0) {
649
+ return namedSequence;
650
+ }
651
+ if (lowerKey.startsWith("control+")) {
652
+ return controlKeyToSequence(key.slice("control+".length));
653
+ }
654
+ if (lowerKey.startsWith("alt+")) {
655
+ const nestedKey = key.slice("alt+".length);
656
+ if (nestedKey.length === 0) {
657
+ throw unknownKeyError(key);
191
658
  }
192
- catch {
193
- return createChildProcessFallback({ command, args, cwd, env });
659
+ if (nestedKey.length === 1) {
660
+ return "\x1B" + nestedKey;
194
661
  }
662
+ try {
663
+ return "\x1B" + keyToSequence(nestedKey);
664
+ } catch {
665
+ throw unknownKeyError(key);
666
+ }
667
+ }
668
+ if (key.length === 1) {
669
+ return key;
670
+ }
671
+ throw unknownKeyError(key);
195
672
  }
196
- function createChildProcessFallback({ command, args, cwd, env }) {
197
- const child = spawnChildProcess(command, args, {
198
- cwd,
199
- env,
200
- stdio: ["pipe", "pipe", "pipe"]
201
- });
202
- return new ChildProcessFallback(child);
673
+ function controlKeyToSequence(controlKey) {
674
+ if (controlKey.length !== 1) {
675
+ throw unknownKeyError(`Control+${controlKey}`);
676
+ }
677
+ const uppercaseLetter = controlKey.toUpperCase();
678
+ const charCode = uppercaseLetter.charCodeAt(0);
679
+ if (charCode < 65 || charCode > 90) {
680
+ throw unknownKeyError(`Control+${controlKey}`);
681
+ }
682
+ return String.fromCharCode(charCode - 64);
203
683
  }
204
- class ChildProcessFallback {
205
- pid;
206
- child;
207
- dataEmitter = new EventEmitter();
208
- exitEmitter = new EventEmitter();
209
- constructor(child) {
210
- this.child = child;
211
- this.pid = child.pid ?? -1;
212
- child.stdout.setEncoding("utf8");
213
- child.stderr.setEncoding("utf8");
214
- child.stdout.on("data", this.handleData);
215
- child.stderr.on("data", this.handleData);
216
- child.on("exit", (exitCode, signal) => {
217
- this.exitEmitter.emit("exit", {
218
- exitCode: exitCode ?? signalToExitCode(signal),
219
- signal: undefined
220
- });
221
- });
684
+
685
+ // src/terminal-screen.ts
686
+ var TerminalScreen = class {
687
+ lines;
688
+ rawLines;
689
+ cursor;
690
+ size;
691
+ constructor({
692
+ lines,
693
+ rawLines,
694
+ cursor,
695
+ size
696
+ }) {
697
+ this.lines = Object.freeze(lines.map((line) => stripAnsi(line)));
698
+ this.rawLines = Object.freeze([...rawLines]);
699
+ this.cursor = Object.freeze({ ...cursor });
700
+ this.size = Object.freeze({ ...size });
701
+ Object.freeze(this);
702
+ }
703
+ get text() {
704
+ return this.lines.join("\n");
705
+ }
706
+ contains(substring) {
707
+ return this.text.includes(substring);
708
+ }
709
+ line(index) {
710
+ const normalizedIndex = index < 0 ? this.lines.length + index : index;
711
+ const line = this.lines[normalizedIndex];
712
+ if (line === void 0) {
713
+ throw new RangeError(`Line index out of bounds: ${index}`);
222
714
  }
223
- write(data) {
224
- this.child.stdin.write(data);
225
- }
226
- resize() {
227
- // No-op in fallback mode.
228
- }
229
- kill(signal) {
230
- this.child.kill(signal);
231
- }
232
- onData(listener) {
233
- this.dataEmitter.on("data", listener);
234
- return {
235
- dispose: () => {
236
- this.dataEmitter.off("data", listener);
237
- }
238
- };
239
- }
240
- onExit(listener) {
241
- this.exitEmitter.on("exit", listener);
242
- return {
243
- dispose: () => {
244
- this.exitEmitter.off("exit", listener);
245
- }
246
- };
247
- }
248
- handleData = (chunk) => {
249
- this.dataEmitter.emit("data", String(chunk));
250
- };
715
+ return line;
716
+ }
717
+ };
718
+
719
+ // src/terminal-session.ts
720
+ var DEFAULT_COLS = 120;
721
+ var DEFAULT_ROWS = 40;
722
+ var DEFAULT_TIMEOUT_MS = 1e4;
723
+ var WAIT_FOR_POLL_MS = 10;
724
+ var TYPE_DELAY_MS = 15;
725
+ var CLOSE_AFTER_SIGNAL_GRACE_MS = 250;
726
+ var CLOSE_AFTER_SIGTERM_MS = 1e3;
727
+ var TerminalSession = class {
728
+ id;
729
+ command;
730
+ pid;
731
+ exitCode = null;
732
+ pty;
733
+ terminal;
734
+ emitter = new EventEmitter();
735
+ exitPromise;
736
+ rawBuffer = "";
737
+ lastDataAt = Date.now();
738
+ currentCols;
739
+ currentRows;
740
+ closeRequested = false;
741
+ signalRequested = false;
742
+ constructor({
743
+ id,
744
+ command,
745
+ args = [],
746
+ cwd = process.cwd(),
747
+ env = process.env,
748
+ cols = DEFAULT_COLS,
749
+ rows = DEFAULT_ROWS,
750
+ observe = false
751
+ }) {
752
+ this.id = id;
753
+ this.command = command;
754
+ this.currentCols = cols;
755
+ this.currentRows = rows;
756
+ this.terminal = new TerminalBuffer(cols, rows);
757
+ this.pty = createPtyProcess({ command, args, cwd, env, cols, rows });
758
+ this.pid = this.pty.pid;
759
+ const dataSubscription = this.pty.onData((chunk) => {
760
+ this.rawBuffer += chunk;
761
+ this.lastDataAt = Date.now();
762
+ this.terminal.write(chunk);
763
+ if (observe) {
764
+ process.stderr.write(chunk);
765
+ }
766
+ });
767
+ let exitSubscription;
768
+ this.exitPromise = new Promise((resolve) => {
769
+ exitSubscription = this.pty.onExit(({ exitCode }) => {
770
+ if (this.exitCode !== null) {
771
+ resolve(this.exitCode);
772
+ return;
773
+ }
774
+ this.exitCode = exitCode;
775
+ dataSubscription.dispose();
776
+ exitSubscription?.dispose();
777
+ this.emitter.emit("exit", exitCode);
778
+ resolve(exitCode);
779
+ });
780
+ });
781
+ }
782
+ async type(text) {
783
+ for (const character of text) {
784
+ await this.send(character);
785
+ await sleep(TYPE_DELAY_MS);
786
+ }
787
+ }
788
+ async fill(text) {
789
+ await this.send(text.replace(/\r?\n/g, "\r"));
790
+ }
791
+ async press(key) {
792
+ await this.send(keyToSequence(key));
793
+ }
794
+ async send(raw) {
795
+ if (this.exitCode !== null) {
796
+ return;
797
+ }
798
+ this.pty.write(raw);
799
+ }
800
+ async signal(sig) {
801
+ if (this.exitCode !== null) {
802
+ return;
803
+ }
804
+ this.signalRequested = true;
805
+ this.pty.kill(sig);
806
+ }
807
+ async waitFor(pattern, opts) {
808
+ const timeout = opts?.timeout ?? DEFAULT_TIMEOUT_MS;
809
+ const startedAt = Date.now();
810
+ while (Date.now() - startedAt <= timeout) {
811
+ const matched = matchPattern(this.rawBuffer, pattern);
812
+ if (matched !== null) {
813
+ return matched;
814
+ }
815
+ await sleep(WAIT_FOR_POLL_MS);
816
+ }
817
+ throw new Error(`Timed out waiting for pattern after ${timeout}ms: ${String(pattern)}`);
818
+ }
819
+ async waitForQuiet(ms) {
820
+ while (true) {
821
+ const remaining = ms - (Date.now() - this.lastDataAt);
822
+ if (remaining <= 0) {
823
+ return;
824
+ }
825
+ await sleep(remaining);
826
+ }
827
+ }
828
+ async screen() {
829
+ const rawLines = [];
830
+ for (let row = 0; row < this.currentRows; row += 1) {
831
+ rawLines.push(this.terminal.renderLine(row));
832
+ }
833
+ return new TerminalScreen({
834
+ lines: rawLines,
835
+ rawLines,
836
+ cursor: {
837
+ row: this.terminal.displayBuffer.cursorY,
838
+ col: this.terminal.displayBuffer.cursorX
839
+ },
840
+ size: {
841
+ rows: this.currentRows,
842
+ cols: this.currentCols
843
+ }
844
+ });
845
+ }
846
+ async history(opts) {
847
+ const normalized = normalizeHistoryBuffer(stripAnsi(this.rawBuffer));
848
+ const lines = splitHistoryLines(normalized);
849
+ if (opts?.last === void 0) {
850
+ return lines;
851
+ }
852
+ const start = Math.max(0, lines.length - opts.last);
853
+ return lines.slice(start);
854
+ }
855
+ async resize(cols, rows) {
856
+ this.currentCols = cols;
857
+ this.currentRows = rows;
858
+ if (this.exitCode === null) {
859
+ this.pty.resize(cols, rows);
860
+ }
861
+ this.terminal.resize(cols, rows);
862
+ }
863
+ async waitForExit(opts) {
864
+ if (this.exitCode !== null) {
865
+ return this.exitCode;
866
+ }
867
+ if (opts?.timeout !== void 0) {
868
+ const result = await waitForExit(this.exitPromise, opts.timeout);
869
+ if (result === null) {
870
+ throw new Error(`Timed out waiting for process to exit after ${opts.timeout}ms`);
871
+ }
872
+ return result;
873
+ }
874
+ return this.exitPromise;
875
+ }
876
+ async close() {
877
+ if (this.exitCode !== null) {
878
+ return this.exitCode;
879
+ }
880
+ if (!this.closeRequested) {
881
+ this.closeRequested = true;
882
+ const gracefulExitCode = await waitForExit(this.exitPromise, CLOSE_AFTER_SIGNAL_GRACE_MS);
883
+ if (gracefulExitCode !== null) {
884
+ return gracefulExitCode;
885
+ }
886
+ if (this.signalRequested) {
887
+ return this.exitPromise;
888
+ }
889
+ if (this.exitCode === null) {
890
+ this.pty.kill("SIGTERM");
891
+ const afterSigterm = await waitForExit(this.exitPromise, CLOSE_AFTER_SIGTERM_MS);
892
+ if (afterSigterm !== null) {
893
+ return afterSigterm;
894
+ }
895
+ }
896
+ if (this.exitCode === null) {
897
+ this.pty.kill("SIGKILL");
898
+ }
899
+ }
900
+ return this.exitPromise;
901
+ }
902
+ on(event, cb) {
903
+ this.emitter.on(event, cb);
904
+ }
905
+ };
906
+ function createPtyProcess({
907
+ command,
908
+ args,
909
+ cwd,
910
+ env,
911
+ cols,
912
+ rows
913
+ }) {
914
+ try {
915
+ return nodePty.spawn(command, args, {
916
+ cwd,
917
+ env,
918
+ cols,
919
+ rows,
920
+ encoding: "utf8"
921
+ });
922
+ } catch {
923
+ return createChildProcessFallback({ command, args, cwd, env });
924
+ }
251
925
  }
252
- function signalToExitCode(signal) {
253
- if (signal === null) {
254
- return 0;
255
- }
256
- const signalNumbers = {
257
- SIGTERM: 15,
258
- SIGINT: 2,
259
- SIGHUP: 1,
260
- SIGKILL: 9
926
+ function createChildProcessFallback({
927
+ command,
928
+ args,
929
+ cwd,
930
+ env
931
+ }) {
932
+ const child = spawnChildProcess(command, args, {
933
+ cwd,
934
+ env,
935
+ stdio: ["pipe", "pipe", "pipe"]
936
+ });
937
+ return new ChildProcessFallback(child);
938
+ }
939
+ var ChildProcessFallback = class {
940
+ pid;
941
+ child;
942
+ dataEmitter = new EventEmitter();
943
+ exitEmitter = new EventEmitter();
944
+ constructor(child) {
945
+ this.child = child;
946
+ this.pid = child.pid ?? -1;
947
+ child.stdout.setEncoding("utf8");
948
+ child.stderr.setEncoding("utf8");
949
+ child.stdout.on("data", this.handleData);
950
+ child.stderr.on("data", this.handleData);
951
+ child.on("exit", (exitCode, signal) => {
952
+ this.exitEmitter.emit("exit", {
953
+ exitCode: exitCode ?? signalToExitCode(signal),
954
+ signal: void 0
955
+ });
956
+ });
957
+ }
958
+ write(data) {
959
+ this.child.stdin.write(data);
960
+ }
961
+ resize() {
962
+ }
963
+ kill(signal) {
964
+ this.child.kill(signal);
965
+ }
966
+ onData(listener) {
967
+ this.dataEmitter.on("data", listener);
968
+ return {
969
+ dispose: () => {
970
+ this.dataEmitter.off("data", listener);
971
+ }
261
972
  };
262
- const signalNumber = signalNumbers[signal];
263
- if (signalNumber === undefined) {
264
- return 1;
265
- }
266
- return 128 + signalNumber;
973
+ }
974
+ onExit(listener) {
975
+ this.exitEmitter.on("exit", listener);
976
+ return {
977
+ dispose: () => {
978
+ this.exitEmitter.off("exit", listener);
979
+ }
980
+ };
981
+ }
982
+ handleData = (chunk) => {
983
+ this.dataEmitter.emit("data", String(chunk));
984
+ };
985
+ };
986
+ function signalToExitCode(signal) {
987
+ if (signal === null) {
988
+ return 0;
989
+ }
990
+ const signalNumbers = {
991
+ SIGTERM: 15,
992
+ SIGINT: 2,
993
+ SIGHUP: 1,
994
+ SIGKILL: 9
995
+ };
996
+ const signalNumber = signalNumbers[signal];
997
+ if (signalNumber === void 0) {
998
+ return 1;
999
+ }
1000
+ return 128 + signalNumber;
267
1001
  }
268
1002
  function matchPattern(buffer, pattern) {
269
- const clean = normalizeHistoryBuffer(stripAnsi(buffer));
270
- for (const line of clean.split("\n")) {
271
- if (typeof pattern === "string") {
272
- if (line.includes(pattern))
273
- return line;
274
- }
275
- else {
276
- const flags = removeCharacter(pattern.flags, "g");
277
- if (new RegExp(pattern.source, flags).test(line))
278
- return line;
279
- }
1003
+ const clean = normalizeHistoryBuffer(stripAnsi(buffer));
1004
+ for (const line of clean.split("\n")) {
1005
+ if (typeof pattern === "string") {
1006
+ if (line.includes(pattern)) return line;
1007
+ } else {
1008
+ const flags = removeCharacter(pattern.flags, "g");
1009
+ if (new RegExp(pattern.source, flags).test(line)) return line;
280
1010
  }
281
- return null;
1011
+ }
1012
+ return null;
282
1013
  }
283
1014
  function removeCharacter(input, charToRemove) {
284
- let output = "";
285
- for (const character of input) {
286
- if (character !== charToRemove) {
287
- output += character;
288
- }
1015
+ let output = "";
1016
+ for (const character of input) {
1017
+ if (character !== charToRemove) {
1018
+ output += character;
289
1019
  }
290
- return output;
1020
+ }
1021
+ return output;
291
1022
  }
292
1023
  function splitHistoryLines(input) {
293
- const lines = input.split("\n");
294
- if (lines.length > 0 && lines[lines.length - 1] === "") {
295
- lines.pop();
296
- }
297
- return lines;
1024
+ const lines = input.split("\n");
1025
+ if (lines.length > 0 && lines[lines.length - 1] === "") {
1026
+ lines.pop();
1027
+ }
1028
+ return lines;
298
1029
  }
299
1030
  function normalizeHistoryBuffer(input) {
300
- let output = "";
301
- for (const character of input) {
302
- if (character === "\r" || character === "\b") {
303
- continue;
304
- }
305
- output += character;
1031
+ let output = "";
1032
+ for (const character of input) {
1033
+ if (character === "\r" || character === "\b") {
1034
+ continue;
306
1035
  }
307
- return output;
308
- }
309
- function trimTrailingSpaces(input) {
310
- let end = input.length;
311
- while (end > 0 && input[end - 1] === " ") {
312
- end -= 1;
313
- }
314
- return input.slice(0, end);
1036
+ output += character;
1037
+ }
1038
+ return output;
315
1039
  }
316
1040
  function sleep(ms) {
317
- return new Promise((resolve) => {
318
- setTimeout(resolve, ms);
319
- });
1041
+ return new Promise((resolve) => {
1042
+ setTimeout(resolve, ms);
1043
+ });
320
1044
  }
321
1045
  async function waitForExit(exitPromise, timeout) {
322
- return new Promise((resolve) => {
323
- let settled = false;
324
- const timer = setTimeout(() => {
325
- if (settled) {
326
- return;
327
- }
328
- settled = true;
329
- resolve(null);
330
- }, timeout);
331
- void exitPromise.then((code) => {
332
- if (settled) {
333
- return;
334
- }
335
- settled = true;
336
- clearTimeout(timer);
337
- resolve(code);
338
- });
1046
+ return new Promise((resolve) => {
1047
+ let settled = false;
1048
+ const timer = setTimeout(() => {
1049
+ if (settled) {
1050
+ return;
1051
+ }
1052
+ settled = true;
1053
+ resolve(null);
1054
+ }, timeout);
1055
+ void exitPromise.then((code) => {
1056
+ if (settled) {
1057
+ return;
1058
+ }
1059
+ settled = true;
1060
+ clearTimeout(timer);
1061
+ resolve(code);
339
1062
  });
1063
+ });
340
1064
  }
1065
+ export {
1066
+ TerminalSession
1067
+ };
1068
+ //# sourceMappingURL=terminal-session.js.map