terminal-pilot 0.0.17 → 0.0.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +6271 -2048
- package/dist/cli.js.map +4 -4
- package/dist/commands/close-session.d.ts +4 -4
- package/dist/commands/close-session.js +437 -108
- package/dist/commands/close-session.js.map +2 -2
- package/dist/commands/create-session.d.ts +16 -16
- package/dist/commands/create-session.js +437 -108
- package/dist/commands/create-session.js.map +2 -2
- package/dist/commands/fill.d.ts +6 -6
- package/dist/commands/fill.js +437 -108
- package/dist/commands/fill.js.map +2 -2
- package/dist/commands/get-session.d.ts +4 -4
- package/dist/commands/get-session.js +437 -108
- package/dist/commands/get-session.js.map +2 -2
- package/dist/commands/index.d.ts +330 -107
- package/dist/commands/index.js +1951 -336
- package/dist/commands/index.js.map +4 -4
- package/dist/commands/install.d.ts +8 -8
- package/dist/commands/install.js +1242 -134
- package/dist/commands/install.js.map +4 -4
- package/dist/commands/installer.d.ts +5 -0
- package/dist/commands/installer.js +606 -37
- package/dist/commands/installer.js.map +4 -4
- package/dist/commands/list-sessions.d.ts +2 -2
- package/dist/commands/list-sessions.js +437 -108
- package/dist/commands/list-sessions.js.map +2 -2
- package/dist/commands/press-key.d.ts +6 -6
- package/dist/commands/press-key.js +437 -108
- package/dist/commands/press-key.js.map +2 -2
- package/dist/commands/read-history.d.ts +6 -6
- package/dist/commands/read-history.js +437 -108
- package/dist/commands/read-history.js.map +2 -2
- package/dist/commands/read-screen.d.ts +4 -4
- package/dist/commands/read-screen.js +437 -108
- package/dist/commands/read-screen.js.map +2 -2
- package/dist/commands/resize.d.ts +8 -8
- package/dist/commands/resize.js +437 -108
- package/dist/commands/resize.js.map +2 -2
- package/dist/commands/runtime.js +356 -89
- package/dist/commands/runtime.js.map +2 -2
- package/dist/commands/screenshot.d.ts +10 -10
- package/dist/commands/screenshot.js +672 -148
- package/dist/commands/screenshot.js.map +3 -3
- package/dist/commands/send-signal.d.ts +6 -6
- package/dist/commands/send-signal.js +437 -108
- package/dist/commands/send-signal.js.map +2 -2
- package/dist/commands/type.d.ts +6 -6
- package/dist/commands/type.js +437 -108
- package/dist/commands/type.js.map +2 -2
- package/dist/commands/uninstall.d.ts +4 -4
- package/dist/commands/uninstall.js +708 -64
- package/dist/commands/uninstall.js.map +4 -4
- package/dist/commands/wait-for-exit.d.ts +6 -6
- package/dist/commands/wait-for-exit.js +437 -108
- package/dist/commands/wait-for-exit.js.map +2 -2
- package/dist/commands/wait-for.d.ts +10 -10
- package/dist/commands/wait-for.js +437 -108
- package/dist/commands/wait-for.js.map +2 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.js +318 -80
- package/dist/index.js.map +3 -3
- package/dist/terminal-buffer.d.ts +18 -0
- package/dist/terminal-buffer.js +234 -43
- package/dist/terminal-buffer.js.map +2 -2
- package/dist/terminal-pilot.js +312 -73
- package/dist/terminal-pilot.js.map +2 -2
- package/dist/terminal-session.d.ts +2 -2
- package/dist/terminal-session.js +306 -68
- package/dist/terminal-session.js.map +2 -2
- package/dist/testing/cli-repl.js +6267 -2044
- package/dist/testing/cli-repl.js.map +4 -4
- package/dist/testing/qa-cli.js +6291 -2068
- package/dist/testing/qa-cli.js.map +4 -4
- package/package.json +6 -5
|
@@ -3,8 +3,8 @@ import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
|
3
3
|
|
|
4
4
|
// ../toolcraft/src/user-error.ts
|
|
5
5
|
var UserError = class extends Error {
|
|
6
|
-
constructor(message) {
|
|
7
|
-
super(message);
|
|
6
|
+
constructor(message, options) {
|
|
7
|
+
super(message, options);
|
|
8
8
|
this.name = "UserError";
|
|
9
9
|
}
|
|
10
10
|
};
|
|
@@ -40,13 +40,20 @@ function Json() {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
// ../toolcraft-schema/src/oneof.ts
|
|
43
|
-
function assertValidBranches(branches) {
|
|
43
|
+
function assertValidBranches(branches, discriminator) {
|
|
44
44
|
if (Object.keys(branches).length === 0) {
|
|
45
45
|
throw new Error("OneOf schema requires at least one branch");
|
|
46
46
|
}
|
|
47
|
+
for (const [branchName, branch] of Object.entries(branches)) {
|
|
48
|
+
if (Object.prototype.hasOwnProperty.call(branch.shape, discriminator)) {
|
|
49
|
+
throw new Error(
|
|
50
|
+
`OneOf branch "${branchName}" must not declare discriminator field "${discriminator}".`
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
47
54
|
}
|
|
48
55
|
function OneOf(config) {
|
|
49
|
-
assertValidBranches(config.branches);
|
|
56
|
+
assertValidBranches(config.branches, config.discriminator);
|
|
50
57
|
return {
|
|
51
58
|
kind: "oneOf",
|
|
52
59
|
discriminator: config.discriminator,
|
|
@@ -66,22 +73,37 @@ function Record(value) {
|
|
|
66
73
|
function isOptionalSchema(schema) {
|
|
67
74
|
return schema.kind === "optional";
|
|
68
75
|
}
|
|
69
|
-
function
|
|
70
|
-
|
|
71
|
-
|
|
76
|
+
function getRequiredKeys(schema) {
|
|
77
|
+
return Object.keys(schema.shape).filter((key) => !isOptionalSchema(schema.shape[key])).sort();
|
|
78
|
+
}
|
|
79
|
+
function assertUniqueRequiredKeyFingerprints(branches) {
|
|
80
|
+
const fingerprints = /* @__PURE__ */ new Map();
|
|
81
|
+
branches.forEach((branch, index) => {
|
|
82
|
+
const requiredKeys = getRequiredKeys(branch);
|
|
83
|
+
const fingerprint = JSON.stringify(requiredKeys);
|
|
84
|
+
const existing = fingerprints.get(fingerprint);
|
|
85
|
+
if (existing === void 0) {
|
|
86
|
+
fingerprints.set(fingerprint, {
|
|
87
|
+
display: requiredKeys.join("+"),
|
|
88
|
+
indices: [index]
|
|
89
|
+
});
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
existing.indices.push(index);
|
|
93
|
+
});
|
|
94
|
+
for (const { display, indices } of fingerprints.values()) {
|
|
95
|
+
if (indices.length > 1) {
|
|
96
|
+
throw new Error(
|
|
97
|
+
`Union branches [${indices.join(", ")}] share required-key fingerprint "${display}". Each branch must require a distinct set of keys.`
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
72
101
|
}
|
|
73
102
|
function assertValidBranches2(branches) {
|
|
74
103
|
if (branches.length === 0) {
|
|
75
104
|
throw new Error("Union schema requires at least one branch");
|
|
76
105
|
}
|
|
77
|
-
|
|
78
|
-
for (const branch of branches) {
|
|
79
|
-
const fingerprint = getRequiredKeyFingerprint(branch);
|
|
80
|
-
if (fingerprints.has(fingerprint)) {
|
|
81
|
-
throw new Error("Union schema branches must have unique required-key fingerprints");
|
|
82
|
-
}
|
|
83
|
-
fingerprints.add(fingerprint);
|
|
84
|
-
}
|
|
106
|
+
assertUniqueRequiredKeyFingerprints(branches);
|
|
85
107
|
}
|
|
86
108
|
function Union(branches) {
|
|
87
109
|
assertValidBranches2(branches);
|
|
@@ -100,15 +122,47 @@ function assertValidEnumValues(values) {
|
|
|
100
122
|
if (uniqueValues.size !== values.length) {
|
|
101
123
|
throw new Error("Enum schema values must be unique");
|
|
102
124
|
}
|
|
125
|
+
if (values.some((value) => typeof value === "number" && !Number.isFinite(value))) {
|
|
126
|
+
throw new Error("Enum schema numeric values must be finite");
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
function assertNonNegativeInteger(value, name) {
|
|
130
|
+
if (value !== void 0 && (!Number.isInteger(value) || value < 0)) {
|
|
131
|
+
throw new Error(`${name} must be a non-negative integer`);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
function assertFiniteNumber(value, name) {
|
|
135
|
+
if (value !== void 0 && !Number.isFinite(value)) {
|
|
136
|
+
throw new Error(`${name} must be finite`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
function assertPattern(pattern) {
|
|
140
|
+
if (pattern === void 0) {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
try {
|
|
144
|
+
new RegExp(pattern);
|
|
145
|
+
} catch {
|
|
146
|
+
throw new Error("pattern must be a valid regular expression");
|
|
147
|
+
}
|
|
103
148
|
}
|
|
104
149
|
var S = {
|
|
105
150
|
String(options = {}) {
|
|
151
|
+
assertNonNegativeInteger(options.minLength, "minLength");
|
|
152
|
+
assertNonNegativeInteger(options.maxLength, "maxLength");
|
|
153
|
+
assertPattern(options.pattern);
|
|
106
154
|
return {
|
|
107
155
|
kind: "string",
|
|
108
156
|
...options
|
|
109
157
|
};
|
|
110
158
|
},
|
|
111
159
|
Number(options = {}) {
|
|
160
|
+
assertFiniteNumber(options.minimum, "minimum");
|
|
161
|
+
assertFiniteNumber(options.maximum, "maximum");
|
|
162
|
+
assertFiniteNumber(options.default, "default");
|
|
163
|
+
if (options.jsonType === "integer" && options.default !== void 0 && !Number.isInteger(options.default)) {
|
|
164
|
+
throw new Error("default must be an integer");
|
|
165
|
+
}
|
|
112
166
|
return {
|
|
113
167
|
kind: "number",
|
|
114
168
|
...options
|
|
@@ -122,6 +176,9 @@ var S = {
|
|
|
122
176
|
},
|
|
123
177
|
Enum(values, options = {}) {
|
|
124
178
|
assertValidEnumValues(values);
|
|
179
|
+
if (options.jsonType === "integer" && values.some((value) => typeof value !== "number" || !Number.isInteger(value))) {
|
|
180
|
+
throw new Error("Integer enum values must be integers");
|
|
181
|
+
}
|
|
125
182
|
return {
|
|
126
183
|
kind: "enum",
|
|
127
184
|
values,
|
|
@@ -129,6 +186,8 @@ var S = {
|
|
|
129
186
|
};
|
|
130
187
|
},
|
|
131
188
|
Array(item, options = {}) {
|
|
189
|
+
assertNonNegativeInteger(options.minItems, "minItems");
|
|
190
|
+
assertNonNegativeInteger(options.maxItems, "maxItems");
|
|
132
191
|
return {
|
|
133
192
|
kind: "array",
|
|
134
193
|
item,
|
|
@@ -341,12 +400,15 @@ function materializeCommand(command, inherited) {
|
|
|
341
400
|
}
|
|
342
401
|
function defineCommand(config) {
|
|
343
402
|
validateHumanInLoopOnDefine(config);
|
|
344
|
-
return materializeCommand(
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
403
|
+
return materializeCommand(
|
|
404
|
+
createBaseCommand(config),
|
|
405
|
+
{
|
|
406
|
+
scope: void 0,
|
|
407
|
+
humanInLoop: void 0,
|
|
408
|
+
secrets: {},
|
|
409
|
+
requires: void 0
|
|
410
|
+
}
|
|
411
|
+
);
|
|
350
412
|
}
|
|
351
413
|
|
|
352
414
|
// src/terminal-pilot.ts
|
|
@@ -434,27 +496,53 @@ function consumeTerminatedString(input, index, allowBellTerminator) {
|
|
|
434
496
|
|
|
435
497
|
// src/terminal-buffer.ts
|
|
436
498
|
var RESET_SGR = "\x1B[0m";
|
|
499
|
+
var DEC_SPECIAL_GRAPHICS = {
|
|
500
|
+
j: "\u2518",
|
|
501
|
+
k: "\u2510",
|
|
502
|
+
l: "\u250C",
|
|
503
|
+
m: "\u2514",
|
|
504
|
+
n: "\u253C",
|
|
505
|
+
q: "\u2500",
|
|
506
|
+
t: "\u251C",
|
|
507
|
+
u: "\u2524",
|
|
508
|
+
v: "\u2534",
|
|
509
|
+
w: "\u252C",
|
|
510
|
+
x: "\u2502"
|
|
511
|
+
};
|
|
437
512
|
var TerminalBuffer = class {
|
|
438
513
|
_cols;
|
|
439
514
|
_rows;
|
|
440
515
|
_screen;
|
|
516
|
+
_primaryScreen = null;
|
|
441
517
|
_cursorX = 0;
|
|
442
518
|
_cursorY = 0;
|
|
443
|
-
_savedCursor
|
|
519
|
+
_savedCursor;
|
|
444
520
|
_scrollTop = 0;
|
|
445
521
|
_scrollBottom;
|
|
446
522
|
_state = 0 /* Normal */;
|
|
447
523
|
_csiParams = "";
|
|
448
524
|
_csiPrivate = "";
|
|
449
525
|
_autoWrap = true;
|
|
526
|
+
_pendingWrap = false;
|
|
527
|
+
_originMode = false;
|
|
528
|
+
_insertMode = false;
|
|
529
|
+
_tabStops;
|
|
530
|
+
_lastPrintedChar = null;
|
|
450
531
|
_style = createDefaultStyleState();
|
|
451
532
|
_styleSequence = "";
|
|
533
|
+
_stringState = 0 /* Normal */;
|
|
534
|
+
_charsetTarget = null;
|
|
535
|
+
_g0Charset = "ascii";
|
|
536
|
+
_g1Charset = "ascii";
|
|
537
|
+
_shiftOut = false;
|
|
452
538
|
displayBuffer;
|
|
453
539
|
constructor(cols, rows) {
|
|
454
540
|
this._cols = cols;
|
|
455
541
|
this._rows = rows;
|
|
456
542
|
this._scrollBottom = rows - 1;
|
|
457
543
|
this._screen = this._makeScreen(cols, rows);
|
|
544
|
+
this._tabStops = this._createDefaultTabStops(cols);
|
|
545
|
+
this._savedCursor = this._createSavedCursorState();
|
|
458
546
|
this.displayBuffer = Object.defineProperties(
|
|
459
547
|
{},
|
|
460
548
|
{
|
|
@@ -510,8 +598,12 @@ var TerminalBuffer = class {
|
|
|
510
598
|
}
|
|
511
599
|
this._cols = cols;
|
|
512
600
|
this._rows = rows;
|
|
513
|
-
this._scrollTop = 0;
|
|
514
|
-
this._scrollBottom = rows - 1;
|
|
601
|
+
this._scrollTop = this._clamp(this._scrollTop, 0, rows - 1);
|
|
602
|
+
this._scrollBottom = this._clamp(this._scrollBottom, 0, rows - 1);
|
|
603
|
+
if (this._scrollTop >= this._scrollBottom) {
|
|
604
|
+
this._scrollTop = 0;
|
|
605
|
+
this._scrollBottom = rows - 1;
|
|
606
|
+
}
|
|
515
607
|
this._cursorX = this._clamp(this._cursorX, 0, cols - 1);
|
|
516
608
|
this._cursorY = this._clamp(this._cursorY, 0, rows - 1);
|
|
517
609
|
}
|
|
@@ -521,13 +613,96 @@ var TerminalBuffer = class {
|
|
|
521
613
|
_makeRow(cols) {
|
|
522
614
|
return Array(cols).fill(null);
|
|
523
615
|
}
|
|
616
|
+
_createDefaultTabStops(cols) {
|
|
617
|
+
const tabStops = /* @__PURE__ */ new Set();
|
|
618
|
+
for (let column = 8; column < cols; column += 8) {
|
|
619
|
+
tabStops.add(column);
|
|
620
|
+
}
|
|
621
|
+
return tabStops;
|
|
622
|
+
}
|
|
524
623
|
_clamp(value, min, max) {
|
|
525
624
|
return Math.max(min, Math.min(max, value));
|
|
526
625
|
}
|
|
626
|
+
_createSavedCursorState() {
|
|
627
|
+
return {
|
|
628
|
+
x: this._cursorX,
|
|
629
|
+
y: this._cursorY,
|
|
630
|
+
autoWrap: this._autoWrap,
|
|
631
|
+
style: { ...this._style, fg: this._style.fg?.slice(), bg: this._style.bg?.slice() },
|
|
632
|
+
styleSequence: this._styleSequence
|
|
633
|
+
};
|
|
634
|
+
}
|
|
635
|
+
_saveCursor() {
|
|
636
|
+
this._savedCursor = this._createSavedCursorState();
|
|
637
|
+
}
|
|
638
|
+
_restoreCursor() {
|
|
639
|
+
this._cursorX = this._clamp(this._savedCursor.x, 0, this._cols - 1);
|
|
640
|
+
this._cursorY = this._clamp(this._savedCursor.y, 0, this._rows - 1);
|
|
641
|
+
this._autoWrap = this._savedCursor.autoWrap;
|
|
642
|
+
this._style = {
|
|
643
|
+
...this._savedCursor.style,
|
|
644
|
+
fg: this._savedCursor.style.fg?.slice(),
|
|
645
|
+
bg: this._savedCursor.style.bg?.slice()
|
|
646
|
+
};
|
|
647
|
+
this._styleSequence = this._savedCursor.styleSequence;
|
|
648
|
+
}
|
|
649
|
+
_resetModes() {
|
|
650
|
+
this._autoWrap = true;
|
|
651
|
+
this._originMode = false;
|
|
652
|
+
this._insertMode = false;
|
|
653
|
+
this._pendingWrap = false;
|
|
654
|
+
this._tabStops = this._createDefaultTabStops(this._cols);
|
|
655
|
+
this._g0Charset = "ascii";
|
|
656
|
+
this._g1Charset = "ascii";
|
|
657
|
+
this._shiftOut = false;
|
|
658
|
+
this._resetStyle();
|
|
659
|
+
}
|
|
660
|
+
_writePrintable(ch) {
|
|
661
|
+
const width = this._cellWidth(ch);
|
|
662
|
+
if (this._autoWrap && this._pendingWrap) {
|
|
663
|
+
this._cursorX = 0;
|
|
664
|
+
this._newline();
|
|
665
|
+
} else if (this._autoWrap && this._cursorX + width > this._cols) {
|
|
666
|
+
this._cursorX = 0;
|
|
667
|
+
this._newline();
|
|
668
|
+
}
|
|
669
|
+
if (this._insertMode) {
|
|
670
|
+
const row = this._screen[this._cursorY];
|
|
671
|
+
if (row) {
|
|
672
|
+
row.splice(this._cursorX, 0, ...Array(width).fill(null));
|
|
673
|
+
row.splice(this._cols);
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
this._setChar(this._cursorY, this._cursorX, ch);
|
|
677
|
+
for (let column = 1; column < width && this._cursorX + column < this._cols; column += 1) {
|
|
678
|
+
const row = this._screen[this._cursorY];
|
|
679
|
+
if (row) row[this._cursorX + column] = null;
|
|
680
|
+
}
|
|
681
|
+
this._lastPrintedChar = ch;
|
|
682
|
+
if (!this._autoWrap) {
|
|
683
|
+
this._cursorX = Math.min(this._cursorX + width, this._cols - 1);
|
|
684
|
+
this._pendingWrap = false;
|
|
685
|
+
} else if (this._cursorX + width >= this._cols) {
|
|
686
|
+
this._cursorX = this._cols - 1;
|
|
687
|
+
this._pendingWrap = true;
|
|
688
|
+
} else {
|
|
689
|
+
this._cursorX += width;
|
|
690
|
+
this._pendingWrap = false;
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
_cellWidth(ch) {
|
|
694
|
+
const codePoint = ch.codePointAt(0);
|
|
695
|
+
if (codePoint === void 0) return 0;
|
|
696
|
+
if (codePoint >= 4352 && codePoint <= 4447 || codePoint === 9001 || codePoint === 9002 || codePoint >= 11904 && codePoint <= 12350 || codePoint >= 12353 && codePoint <= 13247 || codePoint >= 13312 && codePoint <= 19903 || codePoint >= 19968 && codePoint <= 42191 || codePoint >= 44032 && codePoint <= 55215 || codePoint >= 63744 && codePoint <= 64255 || codePoint >= 65040 && codePoint <= 65049 || codePoint >= 65072 && codePoint <= 65135 || codePoint >= 65280 && codePoint <= 65376 || codePoint >= 65504 && codePoint <= 65510 || codePoint >= 127488 && codePoint <= 131069 || codePoint >= 131072 && codePoint <= 262141) {
|
|
697
|
+
return Math.min(2, this._cols);
|
|
698
|
+
}
|
|
699
|
+
return 1;
|
|
700
|
+
}
|
|
527
701
|
_setChar(y, x, ch) {
|
|
528
702
|
const row = this._screen[y];
|
|
529
703
|
if (row && x >= 0 && x < this._cols) {
|
|
530
|
-
const
|
|
704
|
+
const renderedChar = this._style.conceal ? " " : ch;
|
|
705
|
+
const cell = [renderedChar.charCodeAt(0), renderedChar];
|
|
531
706
|
if (this._styleSequence.length > 0) {
|
|
532
707
|
Object.defineProperty(cell, "style", {
|
|
533
708
|
value: this._styleSequence,
|
|
@@ -558,6 +733,7 @@ var TerminalBuffer = class {
|
|
|
558
733
|
}
|
|
559
734
|
}
|
|
560
735
|
_newline() {
|
|
736
|
+
this._pendingWrap = false;
|
|
561
737
|
if (this._cursorY === this._scrollBottom) {
|
|
562
738
|
this._scrollUp(1);
|
|
563
739
|
} else {
|
|
@@ -566,7 +742,11 @@ var TerminalBuffer = class {
|
|
|
566
742
|
}
|
|
567
743
|
_parseCsiParams() {
|
|
568
744
|
if (!this._csiParams) return [];
|
|
569
|
-
|
|
745
|
+
const values = this._csiParams.split(";").flatMap((segment) => segment.split(":")).map((segment) => segment === "" ? 0 : parseInt(segment, 10));
|
|
746
|
+
if ((values[0] === 38 || values[0] === 48) && values[1] === 2 && values[2] === 0) {
|
|
747
|
+
values.splice(2, 1);
|
|
748
|
+
}
|
|
749
|
+
return values;
|
|
570
750
|
}
|
|
571
751
|
_execCsi(final) {
|
|
572
752
|
const params2 = this._parseCsiParams();
|
|
@@ -577,21 +757,45 @@ var TerminalBuffer = class {
|
|
|
577
757
|
if (params2.includes(7)) {
|
|
578
758
|
this._autoWrap = final === "h";
|
|
579
759
|
}
|
|
760
|
+
if (params2.includes(6)) {
|
|
761
|
+
this._originMode = final === "h";
|
|
762
|
+
this._cursorX = 0;
|
|
763
|
+
this._cursorY = this._originMode ? this._scrollTop : 0;
|
|
764
|
+
}
|
|
580
765
|
if (params2.includes(1049)) {
|
|
581
766
|
if (final === "h") {
|
|
767
|
+
this._primaryScreen = {
|
|
768
|
+
screen: this._screen,
|
|
769
|
+
cursorX: this._cursorX,
|
|
770
|
+
cursorY: this._cursorY,
|
|
771
|
+
pendingWrap: this._pendingWrap,
|
|
772
|
+
style: { ...this._style, fg: this._style.fg?.slice(), bg: this._style.bg?.slice() },
|
|
773
|
+
styleSequence: this._styleSequence
|
|
774
|
+
};
|
|
582
775
|
this._screen = this._makeScreen(this._cols, this._rows);
|
|
583
776
|
this._cursorX = 0;
|
|
584
777
|
this._cursorY = 0;
|
|
778
|
+
this._pendingWrap = false;
|
|
585
779
|
} else {
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
780
|
+
if (this._primaryScreen !== null) {
|
|
781
|
+
this._screen = this._primaryScreen.screen;
|
|
782
|
+
this._cursorX = this._primaryScreen.cursorX;
|
|
783
|
+
this._cursorY = this._primaryScreen.cursorY;
|
|
784
|
+
this._pendingWrap = this._primaryScreen.pendingWrap;
|
|
785
|
+
this._style = this._primaryScreen.style;
|
|
786
|
+
this._styleSequence = this._primaryScreen.styleSequence;
|
|
787
|
+
this._primaryScreen = null;
|
|
788
|
+
}
|
|
589
789
|
}
|
|
590
|
-
this._resetStyle();
|
|
790
|
+
if (final === "h") this._resetStyle();
|
|
591
791
|
}
|
|
592
792
|
}
|
|
593
793
|
return;
|
|
594
794
|
}
|
|
795
|
+
if ((final === "h" || final === "l") && params2.includes(4)) {
|
|
796
|
+
this._insertMode = final === "h";
|
|
797
|
+
return;
|
|
798
|
+
}
|
|
595
799
|
switch (final) {
|
|
596
800
|
case "A":
|
|
597
801
|
this._cursorY = this._clamp(this._cursorY - Math.max(1, p0), 0, this._rows - 1);
|
|
@@ -623,7 +827,7 @@ var TerminalBuffer = class {
|
|
|
623
827
|
case "H":
|
|
624
828
|
// cursor position
|
|
625
829
|
case "f":
|
|
626
|
-
this._cursorY = this._clamp(Math.max(1, p0) - 1, 0, this._rows - 1);
|
|
830
|
+
this._cursorY = this._originMode ? this._clamp(this._scrollTop + Math.max(1, p0) - 1, this._scrollTop, this._scrollBottom) : this._clamp(Math.max(1, p0) - 1, 0, this._rows - 1);
|
|
627
831
|
this._cursorX = this._clamp(Math.max(1, p1) - 1, 0, this._cols - 1);
|
|
628
832
|
break;
|
|
629
833
|
case "I":
|
|
@@ -638,7 +842,7 @@ var TerminalBuffer = class {
|
|
|
638
842
|
} else if (p0 === 1) {
|
|
639
843
|
for (let y = 0; y < this._cursorY; y++) this._eraseLine(y, 0, this._cols - 1);
|
|
640
844
|
this._eraseLine(this._cursorY, 0, this._cursorX);
|
|
641
|
-
} else if (p0 === 2
|
|
845
|
+
} else if (p0 === 2) {
|
|
642
846
|
for (let y = 0; y < this._rows; y++) this._eraseLine(y, 0, this._cols - 1);
|
|
643
847
|
}
|
|
644
848
|
break;
|
|
@@ -651,6 +855,9 @@ var TerminalBuffer = class {
|
|
|
651
855
|
this._eraseLine(this._cursorY, this._cursorX, this._cursorX + Math.max(1, p0) - 1);
|
|
652
856
|
break;
|
|
653
857
|
case "L": {
|
|
858
|
+
if (this._cursorY < this._scrollTop || this._cursorY > this._scrollBottom) {
|
|
859
|
+
break;
|
|
860
|
+
}
|
|
654
861
|
const n = Math.max(1, p0);
|
|
655
862
|
for (let i = 0; i < n; i++) {
|
|
656
863
|
this._screen.splice(this._scrollBottom, 1);
|
|
@@ -659,6 +866,9 @@ var TerminalBuffer = class {
|
|
|
659
866
|
break;
|
|
660
867
|
}
|
|
661
868
|
case "M": {
|
|
869
|
+
if (this._cursorY < this._scrollTop || this._cursorY > this._scrollBottom) {
|
|
870
|
+
break;
|
|
871
|
+
}
|
|
662
872
|
const n = Math.max(1, p0);
|
|
663
873
|
for (let i = 0; i < n; i++) {
|
|
664
874
|
this._screen.splice(this._cursorY, 1);
|
|
@@ -697,6 +907,13 @@ var TerminalBuffer = class {
|
|
|
697
907
|
}
|
|
698
908
|
break;
|
|
699
909
|
}
|
|
910
|
+
case "b":
|
|
911
|
+
if (this._lastPrintedChar !== null) {
|
|
912
|
+
for (let index = 0; index < Math.max(1, p0); index += 1) {
|
|
913
|
+
this._writePrintable(this._lastPrintedChar);
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
break;
|
|
700
917
|
case "d":
|
|
701
918
|
this._cursorY = this._clamp(Math.max(1, p0) - 1, 0, this._rows - 1);
|
|
702
919
|
break;
|
|
@@ -711,15 +928,19 @@ var TerminalBuffer = class {
|
|
|
711
928
|
this._scrollBottom = bottom;
|
|
712
929
|
}
|
|
713
930
|
this._cursorX = 0;
|
|
714
|
-
this._cursorY = 0;
|
|
931
|
+
this._cursorY = this._originMode ? this._scrollTop : 0;
|
|
715
932
|
break;
|
|
716
933
|
}
|
|
717
934
|
case "s":
|
|
718
|
-
this.
|
|
935
|
+
this._saveCursor();
|
|
719
936
|
break;
|
|
720
937
|
case "u":
|
|
721
|
-
this.
|
|
722
|
-
|
|
938
|
+
this._restoreCursor();
|
|
939
|
+
break;
|
|
940
|
+
case "p":
|
|
941
|
+
if (this._csiPrivate === "!") {
|
|
942
|
+
this._resetModes();
|
|
943
|
+
}
|
|
723
944
|
break;
|
|
724
945
|
case "m":
|
|
725
946
|
this._applySgr(params2);
|
|
@@ -730,6 +951,14 @@ var TerminalBuffer = class {
|
|
|
730
951
|
}
|
|
731
952
|
_feed(ch) {
|
|
732
953
|
const code = ch.charCodeAt(0);
|
|
954
|
+
if (this._state !== 0 /* Normal */ && (code === 24 || code === 26)) {
|
|
955
|
+
this._state = 0 /* Normal */;
|
|
956
|
+
return;
|
|
957
|
+
}
|
|
958
|
+
if (this._state === 2 /* Csi */ && code === 27) {
|
|
959
|
+
this._state = 1 /* Escape */;
|
|
960
|
+
return;
|
|
961
|
+
}
|
|
733
962
|
switch (this._state) {
|
|
734
963
|
case 0 /* Normal */:
|
|
735
964
|
this._feedNormal(ch, code);
|
|
@@ -744,20 +973,37 @@ var TerminalBuffer = class {
|
|
|
744
973
|
if (code === 7 || code === 156) {
|
|
745
974
|
this._state = 0 /* Normal */;
|
|
746
975
|
} else if (code === 27) {
|
|
747
|
-
this.
|
|
976
|
+
this._stringState = 3 /* Osc */;
|
|
977
|
+
this._state = 5 /* StringEscape */;
|
|
748
978
|
}
|
|
749
979
|
break;
|
|
750
980
|
case 4 /* Str */:
|
|
751
|
-
if (code === 156
|
|
981
|
+
if (code === 156) {
|
|
752
982
|
this._state = 0 /* Normal */;
|
|
753
983
|
} else if (code === 27) {
|
|
754
|
-
this.
|
|
984
|
+
this._stringState = 4 /* Str */;
|
|
985
|
+
this._state = 5 /* StringEscape */;
|
|
755
986
|
}
|
|
756
987
|
break;
|
|
757
|
-
case 5 /*
|
|
988
|
+
case 5 /* StringEscape */:
|
|
989
|
+
this._state = ch === "\\" ? 0 /* Normal */ : this._stringState;
|
|
990
|
+
break;
|
|
991
|
+
case 6 /* EscCharset */:
|
|
992
|
+
if (this._charsetTarget === "g0") this._g0Charset = ch === "0" ? "graphics" : "ascii";
|
|
993
|
+
if (this._charsetTarget === "g1") this._g1Charset = ch === "0" ? "graphics" : "ascii";
|
|
994
|
+
this._charsetTarget = null;
|
|
758
995
|
this._state = 0 /* Normal */;
|
|
759
996
|
break;
|
|
760
|
-
case
|
|
997
|
+
case 7 /* EscHash */:
|
|
998
|
+
if (ch === "8") {
|
|
999
|
+
for (let row = 0; row < this._rows; row += 1) {
|
|
1000
|
+
for (let column = 0; column < this._cols; column += 1) {
|
|
1001
|
+
this._setChar(row, column, "E");
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
this._cursorX = 0;
|
|
1005
|
+
this._cursorY = 0;
|
|
1006
|
+
}
|
|
761
1007
|
this._state = 0 /* Normal */;
|
|
762
1008
|
break;
|
|
763
1009
|
}
|
|
@@ -773,32 +1019,28 @@ var TerminalBuffer = class {
|
|
|
773
1019
|
this._state = 3 /* Osc */;
|
|
774
1020
|
} else if (code === 144 || code === 152 || code === 158 || code === 159) {
|
|
775
1021
|
this._state = 4 /* Str */;
|
|
1022
|
+
} else if (code === 133) {
|
|
1023
|
+
this._cursorX = 0;
|
|
1024
|
+
this._newline();
|
|
1025
|
+
} else if (code === 156) {
|
|
776
1026
|
} else if (code === 7 || code === 5 || code === 6) {
|
|
777
1027
|
} else if (code === 8) {
|
|
1028
|
+
this._pendingWrap = false;
|
|
778
1029
|
if (this._cursorX > 0) this._cursorX--;
|
|
779
1030
|
} else if (code === 127) {
|
|
780
|
-
if (this._cursorX > 0) {
|
|
781
|
-
this._cursorX--;
|
|
782
|
-
this._setChar(this._cursorY, this._cursorX, " ");
|
|
783
|
-
}
|
|
784
1031
|
} else if (code === 9) {
|
|
785
|
-
|
|
1032
|
+
const nextTabStop = [...this._tabStops].sort((left, right) => left - right).find((tabStop) => tabStop > this._cursorX);
|
|
1033
|
+
this._cursorX = nextTabStop ?? this._cols - 1;
|
|
786
1034
|
} else if (code === 10 || code === 11 || code === 12) {
|
|
787
1035
|
this._newline();
|
|
788
1036
|
} else if (code === 13) {
|
|
1037
|
+
this._pendingWrap = false;
|
|
789
1038
|
this._cursorX = 0;
|
|
790
1039
|
} else if (code === 14 || code === 15) {
|
|
1040
|
+
this._shiftOut = code === 14;
|
|
791
1041
|
} else if (code >= 32 && code !== 127) {
|
|
792
|
-
this.
|
|
793
|
-
this.
|
|
794
|
-
if (!this._autoWrap) {
|
|
795
|
-
this._cursorX = Math.min(this._cursorX, this._cols - 1);
|
|
796
|
-
return;
|
|
797
|
-
}
|
|
798
|
-
if (this._cursorX >= this._cols) {
|
|
799
|
-
this._cursorX = 0;
|
|
800
|
-
this._newline();
|
|
801
|
-
}
|
|
1042
|
+
const charset = this._shiftOut ? this._g1Charset : this._g0Charset;
|
|
1043
|
+
this._writePrintable(charset === "graphics" ? DEC_SPECIAL_GRAPHICS[ch] ?? ch : ch);
|
|
802
1044
|
}
|
|
803
1045
|
}
|
|
804
1046
|
_feedEscape(ch, code) {
|
|
@@ -812,14 +1054,14 @@ var TerminalBuffer = class {
|
|
|
812
1054
|
} else if (code === 80 || code === 88 || code === 94 || code === 95) {
|
|
813
1055
|
this._state = 4 /* Str */;
|
|
814
1056
|
} else if (code === 40 || code === 41 || code === 42 || code === 43 || code === 45 || code === 46) {
|
|
815
|
-
this.
|
|
1057
|
+
this._charsetTarget = code === 40 ? "g0" : code === 41 ? "g1" : null;
|
|
1058
|
+
this._state = 6 /* EscCharset */;
|
|
816
1059
|
} else if (code === 35) {
|
|
817
|
-
this._state =
|
|
1060
|
+
this._state = 7 /* EscHash */;
|
|
818
1061
|
} else if (code === 55) {
|
|
819
|
-
this.
|
|
1062
|
+
this._saveCursor();
|
|
820
1063
|
} else if (code === 56) {
|
|
821
|
-
this.
|
|
822
|
-
this._cursorY = this._clamp(this._savedCursor.y, 0, this._rows - 1);
|
|
1064
|
+
this._restoreCursor();
|
|
823
1065
|
} else if (code === 68) {
|
|
824
1066
|
this._newline();
|
|
825
1067
|
} else if (code === 69) {
|
|
@@ -832,14 +1074,15 @@ var TerminalBuffer = class {
|
|
|
832
1074
|
this._cursorY = Math.max(0, this._cursorY - 1);
|
|
833
1075
|
}
|
|
834
1076
|
} else if (code === 72) {
|
|
1077
|
+
this._tabStops.add(this._cursorX);
|
|
835
1078
|
} else if (code === 99) {
|
|
836
1079
|
this._screen = this._makeScreen(this._cols, this._rows);
|
|
837
1080
|
this._cursorX = 0;
|
|
838
1081
|
this._cursorY = 0;
|
|
839
|
-
this._savedCursor = { x: 0, y: 0 };
|
|
840
1082
|
this._scrollTop = 0;
|
|
841
1083
|
this._scrollBottom = this._rows - 1;
|
|
842
|
-
this.
|
|
1084
|
+
this._resetModes();
|
|
1085
|
+
this._savedCursor = this._createSavedCursorState();
|
|
843
1086
|
}
|
|
844
1087
|
}
|
|
845
1088
|
_feedCsi(ch, code) {
|
|
@@ -848,7 +1091,7 @@ var TerminalBuffer = class {
|
|
|
848
1091
|
this._state = 0 /* Normal */;
|
|
849
1092
|
} else if (code === 63 || code === 33 || code === 62 || code === 32) {
|
|
850
1093
|
this._csiPrivate = ch;
|
|
851
|
-
} else if (code >= 48 && code <= 57 || code === 59) {
|
|
1094
|
+
} else if (code >= 48 && code <= 57 || code === 59 || code === 58) {
|
|
852
1095
|
this._csiParams += ch;
|
|
853
1096
|
}
|
|
854
1097
|
}
|
|
@@ -879,6 +1122,9 @@ var TerminalBuffer = class {
|
|
|
879
1122
|
case 7:
|
|
880
1123
|
this._style.inverse = true;
|
|
881
1124
|
break;
|
|
1125
|
+
case 8:
|
|
1126
|
+
this._style.conceal = true;
|
|
1127
|
+
break;
|
|
882
1128
|
case 9:
|
|
883
1129
|
this._style.strikethrough = true;
|
|
884
1130
|
break;
|
|
@@ -896,6 +1142,9 @@ var TerminalBuffer = class {
|
|
|
896
1142
|
case 27:
|
|
897
1143
|
this._style.inverse = false;
|
|
898
1144
|
break;
|
|
1145
|
+
case 28:
|
|
1146
|
+
this._style.conceal = false;
|
|
1147
|
+
break;
|
|
899
1148
|
case 29:
|
|
900
1149
|
this._style.strikethrough = false;
|
|
901
1150
|
break;
|
|
@@ -950,6 +1199,7 @@ function createDefaultStyleState() {
|
|
|
950
1199
|
italic: false,
|
|
951
1200
|
underline: false,
|
|
952
1201
|
inverse: false,
|
|
1202
|
+
conceal: false,
|
|
953
1203
|
strikethrough: false
|
|
954
1204
|
};
|
|
955
1205
|
}
|
|
@@ -970,6 +1220,9 @@ function serializeStyleState(state) {
|
|
|
970
1220
|
if (state.inverse) {
|
|
971
1221
|
codes.push(7);
|
|
972
1222
|
}
|
|
1223
|
+
if (state.conceal) {
|
|
1224
|
+
codes.push(8);
|
|
1225
|
+
}
|
|
973
1226
|
if (state.strikethrough) {
|
|
974
1227
|
codes.push(9);
|
|
975
1228
|
}
|
|
@@ -1088,6 +1341,7 @@ var WAIT_FOR_POLL_MS = 10;
|
|
|
1088
1341
|
var TYPE_DELAY_MS = 15;
|
|
1089
1342
|
var CLOSE_AFTER_SIGNAL_GRACE_MS = 250;
|
|
1090
1343
|
var CLOSE_AFTER_SIGTERM_MS = 1e3;
|
|
1344
|
+
var CLOSE_AFTER_SIGKILL_MS = 1e3;
|
|
1091
1345
|
var TerminalSession = class {
|
|
1092
1346
|
id;
|
|
1093
1347
|
command;
|
|
@@ -1101,8 +1355,7 @@ var TerminalSession = class {
|
|
|
1101
1355
|
lastDataAt = Date.now();
|
|
1102
1356
|
currentCols;
|
|
1103
1357
|
currentRows;
|
|
1104
|
-
|
|
1105
|
-
signalRequested = false;
|
|
1358
|
+
closePromise = null;
|
|
1106
1359
|
constructor({
|
|
1107
1360
|
id,
|
|
1108
1361
|
command,
|
|
@@ -1113,6 +1366,7 @@ var TerminalSession = class {
|
|
|
1113
1366
|
rows = DEFAULT_ROWS,
|
|
1114
1367
|
observe = false
|
|
1115
1368
|
}) {
|
|
1369
|
+
assertTerminalGeometry(cols, rows);
|
|
1116
1370
|
this.id = id;
|
|
1117
1371
|
this.command = command;
|
|
1118
1372
|
this.currentCols = cols;
|
|
@@ -1157,7 +1411,7 @@ var TerminalSession = class {
|
|
|
1157
1411
|
}
|
|
1158
1412
|
async send(raw) {
|
|
1159
1413
|
if (this.exitCode !== null) {
|
|
1160
|
-
|
|
1414
|
+
throw new Error(`Terminal session "${this.id}" has already exited.`);
|
|
1161
1415
|
}
|
|
1162
1416
|
this.pty.write(raw);
|
|
1163
1417
|
}
|
|
@@ -1165,22 +1419,26 @@ var TerminalSession = class {
|
|
|
1165
1419
|
if (this.exitCode !== null) {
|
|
1166
1420
|
return;
|
|
1167
1421
|
}
|
|
1168
|
-
this.signalRequested = true;
|
|
1169
1422
|
this.pty.kill(sig);
|
|
1170
1423
|
}
|
|
1171
1424
|
async waitFor(pattern, opts) {
|
|
1172
1425
|
const timeout = opts?.timeout ?? DEFAULT_TIMEOUT_MS;
|
|
1426
|
+
assertTimeout(timeout);
|
|
1173
1427
|
const startedAt = Date.now();
|
|
1174
1428
|
while (Date.now() - startedAt <= timeout) {
|
|
1175
1429
|
const matched = matchPattern(this.rawBuffer, pattern);
|
|
1176
1430
|
if (matched !== null) {
|
|
1177
1431
|
return matched;
|
|
1178
1432
|
}
|
|
1433
|
+
if (this.exitCode !== null) {
|
|
1434
|
+
throw new Error(`Terminal session "${this.id}" exited before matching pattern: ${String(pattern)}`);
|
|
1435
|
+
}
|
|
1179
1436
|
await sleep(WAIT_FOR_POLL_MS);
|
|
1180
1437
|
}
|
|
1181
1438
|
throw new Error(`Timed out waiting for pattern after ${timeout}ms: ${String(pattern)}`);
|
|
1182
1439
|
}
|
|
1183
1440
|
async waitForQuiet(ms) {
|
|
1441
|
+
assertQuietPeriod(ms);
|
|
1184
1442
|
while (true) {
|
|
1185
1443
|
const remaining = ms - (Date.now() - this.lastDataAt);
|
|
1186
1444
|
if (remaining <= 0) {
|
|
@@ -1213,10 +1471,14 @@ var TerminalSession = class {
|
|
|
1213
1471
|
if (opts?.last === void 0) {
|
|
1214
1472
|
return lines;
|
|
1215
1473
|
}
|
|
1474
|
+
if (!Number.isInteger(opts.last) || opts.last < 0) {
|
|
1475
|
+
throw new Error("History last must be a non-negative integer.");
|
|
1476
|
+
}
|
|
1216
1477
|
const start = Math.max(0, lines.length - opts.last);
|
|
1217
1478
|
return lines.slice(start);
|
|
1218
1479
|
}
|
|
1219
1480
|
async resize(cols, rows) {
|
|
1481
|
+
assertTerminalGeometry(cols, rows);
|
|
1220
1482
|
this.currentCols = cols;
|
|
1221
1483
|
this.currentRows = rows;
|
|
1222
1484
|
if (this.exitCode === null) {
|
|
@@ -1225,6 +1487,9 @@ var TerminalSession = class {
|
|
|
1225
1487
|
this.terminal.resize(cols, rows);
|
|
1226
1488
|
}
|
|
1227
1489
|
async waitForExit(opts) {
|
|
1490
|
+
if (opts?.timeout !== void 0) {
|
|
1491
|
+
assertTimeout(opts.timeout);
|
|
1492
|
+
}
|
|
1228
1493
|
if (this.exitCode !== null) {
|
|
1229
1494
|
return this.exitCode;
|
|
1230
1495
|
}
|
|
@@ -1241,32 +1506,52 @@ var TerminalSession = class {
|
|
|
1241
1506
|
if (this.exitCode !== null) {
|
|
1242
1507
|
return this.exitCode;
|
|
1243
1508
|
}
|
|
1244
|
-
|
|
1245
|
-
this.
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1509
|
+
this.closePromise ??= this.closeProcess().catch((error) => {
|
|
1510
|
+
this.closePromise = null;
|
|
1511
|
+
throw error;
|
|
1512
|
+
});
|
|
1513
|
+
return this.closePromise;
|
|
1514
|
+
}
|
|
1515
|
+
async closeProcess() {
|
|
1516
|
+
const gracefulExitCode = await waitForExit(this.exitPromise, CLOSE_AFTER_SIGNAL_GRACE_MS);
|
|
1517
|
+
if (gracefulExitCode !== null) {
|
|
1518
|
+
return gracefulExitCode;
|
|
1519
|
+
}
|
|
1520
|
+
if (this.exitCode === null) {
|
|
1521
|
+
this.pty.kill("SIGTERM");
|
|
1522
|
+
const afterSigterm = await waitForExit(this.exitPromise, CLOSE_AFTER_SIGTERM_MS);
|
|
1523
|
+
if (afterSigterm !== null) {
|
|
1524
|
+
return afterSigterm;
|
|
1259
1525
|
}
|
|
1260
|
-
|
|
1261
|
-
|
|
1526
|
+
}
|
|
1527
|
+
if (this.exitCode === null) {
|
|
1528
|
+
this.pty.kill("SIGKILL");
|
|
1529
|
+
const afterSigkill = await waitForExit(this.exitPromise, CLOSE_AFTER_SIGKILL_MS);
|
|
1530
|
+
if (afterSigkill !== null) {
|
|
1531
|
+
return afterSigkill;
|
|
1262
1532
|
}
|
|
1263
1533
|
}
|
|
1264
|
-
|
|
1534
|
+
throw new Error("Timed out waiting for process to exit after SIGKILL.");
|
|
1265
1535
|
}
|
|
1266
1536
|
on(event, cb) {
|
|
1267
1537
|
this.emitter.on(event, cb);
|
|
1268
1538
|
}
|
|
1269
1539
|
};
|
|
1540
|
+
function assertTerminalGeometry(cols, rows) {
|
|
1541
|
+
if (!Number.isInteger(cols) || cols <= 0 || !Number.isInteger(rows) || rows <= 0) {
|
|
1542
|
+
throw new Error("Terminal columns and rows must be positive integers.");
|
|
1543
|
+
}
|
|
1544
|
+
}
|
|
1545
|
+
function assertTimeout(timeout) {
|
|
1546
|
+
if (!Number.isFinite(timeout) || timeout < 0) {
|
|
1547
|
+
throw new Error("Timeout must be a finite non-negative number.");
|
|
1548
|
+
}
|
|
1549
|
+
}
|
|
1550
|
+
function assertQuietPeriod(duration) {
|
|
1551
|
+
if (!Number.isFinite(duration) || duration < 0) {
|
|
1552
|
+
throw new Error("Quiet period must be a finite non-negative number.");
|
|
1553
|
+
}
|
|
1554
|
+
}
|
|
1270
1555
|
function createPtyProcess({
|
|
1271
1556
|
command,
|
|
1272
1557
|
args,
|
|
@@ -1343,13 +1628,28 @@ function splitHistoryLines(input) {
|
|
|
1343
1628
|
}
|
|
1344
1629
|
function normalizeHistoryBuffer(input) {
|
|
1345
1630
|
let output = "";
|
|
1631
|
+
let line = "";
|
|
1632
|
+
let cursor = 0;
|
|
1346
1633
|
for (const character of input) {
|
|
1347
|
-
if (character === "\r"
|
|
1634
|
+
if (character === "\r") {
|
|
1635
|
+
cursor = 0;
|
|
1348
1636
|
continue;
|
|
1349
1637
|
}
|
|
1350
|
-
|
|
1638
|
+
if (character === "\b") {
|
|
1639
|
+
cursor = Math.max(0, cursor - 1);
|
|
1640
|
+
continue;
|
|
1641
|
+
}
|
|
1642
|
+
if (character === "\n") {
|
|
1643
|
+
output += `${line}
|
|
1644
|
+
`;
|
|
1645
|
+
line = "";
|
|
1646
|
+
cursor = 0;
|
|
1647
|
+
continue;
|
|
1648
|
+
}
|
|
1649
|
+
line = `${line.slice(0, cursor)}${character}${line.slice(cursor + 1)}`;
|
|
1650
|
+
cursor += 1;
|
|
1351
1651
|
}
|
|
1352
|
-
return output;
|
|
1652
|
+
return output + line;
|
|
1353
1653
|
}
|
|
1354
1654
|
function sleep(ms) {
|
|
1355
1655
|
return new Promise((resolve) => {
|
|
@@ -1414,11 +1714,12 @@ var TerminalPilot = class _TerminalPilot {
|
|
|
1414
1714
|
}
|
|
1415
1715
|
async close() {
|
|
1416
1716
|
const sessions = [...this.sessionMap.values()];
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1717
|
+
await Promise.all(
|
|
1718
|
+
sessions.map(async (session) => {
|
|
1719
|
+
await session.close();
|
|
1720
|
+
this.sessionMap.delete(session.id);
|
|
1721
|
+
})
|
|
1722
|
+
);
|
|
1422
1723
|
}
|
|
1423
1724
|
};
|
|
1424
1725
|
|
|
@@ -1436,6 +1737,7 @@ function createTerminalPilotRuntime(options = {}) {
|
|
|
1436
1737
|
const launchPilot = options.launchPilot ?? TerminalPilot.launch;
|
|
1437
1738
|
const nameToId = /* @__PURE__ */ new Map();
|
|
1438
1739
|
const idToName = /* @__PURE__ */ new Map();
|
|
1740
|
+
const pendingNames = /* @__PURE__ */ new Set();
|
|
1439
1741
|
let pilotPromise;
|
|
1440
1742
|
function getRequestedName(name, env) {
|
|
1441
1743
|
return name ?? env?.get(SESSION_ENV_VAR);
|
|
@@ -1446,7 +1748,7 @@ function createTerminalPilotRuntime(options = {}) {
|
|
|
1446
1748
|
}
|
|
1447
1749
|
function nextSessionName() {
|
|
1448
1750
|
let index = 1;
|
|
1449
|
-
while (nameToId.has(`s${index}`)) {
|
|
1751
|
+
while (nameToId.has(`s${index}`) || pendingNames.has(`s${index}`)) {
|
|
1450
1752
|
index += 1;
|
|
1451
1753
|
}
|
|
1452
1754
|
return `s${index}`;
|
|
@@ -1457,8 +1759,12 @@ function createTerminalPilotRuntime(options = {}) {
|
|
|
1457
1759
|
return { name, session };
|
|
1458
1760
|
}
|
|
1459
1761
|
function forgetSession(name, sessionId) {
|
|
1460
|
-
nameToId.
|
|
1461
|
-
|
|
1762
|
+
if (nameToId.get(name) === sessionId) {
|
|
1763
|
+
nameToId.delete(name);
|
|
1764
|
+
}
|
|
1765
|
+
if (idToName.get(sessionId) === name) {
|
|
1766
|
+
idToName.delete(sessionId);
|
|
1767
|
+
}
|
|
1462
1768
|
}
|
|
1463
1769
|
function formatAvailableSessions(names) {
|
|
1464
1770
|
if (names.length === 0) {
|
|
@@ -1491,22 +1797,44 @@ function createTerminalPilotRuntime(options = {}) {
|
|
|
1491
1797
|
return [{ name, session }];
|
|
1492
1798
|
});
|
|
1493
1799
|
}
|
|
1800
|
+
async function discardExitedSessionName(name) {
|
|
1801
|
+
const sessionId = nameToId.get(name);
|
|
1802
|
+
if (sessionId === void 0) {
|
|
1803
|
+
return;
|
|
1804
|
+
}
|
|
1805
|
+
const pilot = await getPilot();
|
|
1806
|
+
try {
|
|
1807
|
+
const session = pilot.getSession(sessionId);
|
|
1808
|
+
if (session.exitCode === null) {
|
|
1809
|
+
return;
|
|
1810
|
+
}
|
|
1811
|
+
pilot.deleteSession(sessionId);
|
|
1812
|
+
} catch {
|
|
1813
|
+
}
|
|
1814
|
+
forgetSession(name, sessionId);
|
|
1815
|
+
}
|
|
1494
1816
|
return {
|
|
1495
1817
|
async createSession(params2, env) {
|
|
1496
1818
|
const requestedName = getRequestedName(params2.session, env) ?? nextSessionName();
|
|
1497
|
-
|
|
1819
|
+
await discardExitedSessionName(requestedName);
|
|
1820
|
+
if (nameToId.has(requestedName) || pendingNames.has(requestedName)) {
|
|
1498
1821
|
throw new UserError(`Session "${requestedName}" already exists.`);
|
|
1499
1822
|
}
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1823
|
+
pendingNames.add(requestedName);
|
|
1824
|
+
try {
|
|
1825
|
+
const pilot = await getPilot();
|
|
1826
|
+
const session = await pilot.newSession({
|
|
1827
|
+
command: params2.command,
|
|
1828
|
+
args: params2.args,
|
|
1829
|
+
cwd: params2.cwd,
|
|
1830
|
+
cols: params2.cols,
|
|
1831
|
+
rows: params2.rows,
|
|
1832
|
+
observe: params2.observe
|
|
1833
|
+
});
|
|
1834
|
+
return rememberSession(requestedName, session);
|
|
1835
|
+
} finally {
|
|
1836
|
+
pendingNames.delete(requestedName);
|
|
1837
|
+
}
|
|
1510
1838
|
},
|
|
1511
1839
|
async resolveSession(name, env) {
|
|
1512
1840
|
const requestedName = getRequestedName(name, env);
|
|
@@ -1545,6 +1873,7 @@ function createTerminalPilotRuntime(options = {}) {
|
|
|
1545
1873
|
pilotPromise = void 0;
|
|
1546
1874
|
nameToId.clear();
|
|
1547
1875
|
idToName.clear();
|
|
1876
|
+
pendingNames.clear();
|
|
1548
1877
|
}
|
|
1549
1878
|
};
|
|
1550
1879
|
}
|