terminal-pilot 0.0.28 → 0.0.29
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 +378 -64
- package/dist/cli.js.map +3 -3
- package/dist/commands/close-session.js +73 -6
- package/dist/commands/close-session.js.map +2 -2
- package/dist/commands/create-session.js +80 -9
- package/dist/commands/create-session.js.map +2 -2
- package/dist/commands/fill.js +73 -6
- package/dist/commands/fill.js.map +2 -2
- package/dist/commands/get-session.js +73 -6
- package/dist/commands/get-session.js.map +2 -2
- package/dist/commands/index.js +371 -62
- package/dist/commands/index.js.map +3 -3
- package/dist/commands/install.js +10 -5
- package/dist/commands/install.js.map +2 -2
- package/dist/commands/installer.js +10 -5
- package/dist/commands/installer.js.map +2 -2
- package/dist/commands/list-sessions.js +66 -4
- package/dist/commands/list-sessions.js.map +2 -2
- package/dist/commands/press-key.js +146 -71
- package/dist/commands/press-key.js.map +3 -3
- package/dist/commands/read-history.js +81 -7
- package/dist/commands/read-history.js.map +2 -2
- package/dist/commands/read-screen.js +73 -6
- package/dist/commands/read-screen.js.map +2 -2
- package/dist/commands/resize.js +75 -8
- package/dist/commands/resize.js.map +2 -2
- package/dist/commands/runtime.js +66 -4
- package/dist/commands/runtime.js.map +2 -2
- package/dist/commands/screenshot.js +228 -23
- package/dist/commands/screenshot.js.map +3 -3
- package/dist/commands/send-signal.js +73 -6
- package/dist/commands/send-signal.js.map +2 -2
- package/dist/commands/type.js +73 -6
- package/dist/commands/type.js.map +2 -2
- package/dist/commands/uninstall.js +10 -5
- package/dist/commands/uninstall.js.map +2 -2
- package/dist/commands/wait-for-exit.js +79 -7
- package/dist/commands/wait-for-exit.js.map +2 -2
- package/dist/commands/wait-for.js +90 -8
- package/dist/commands/wait-for.js.map +3 -3
- package/dist/index.js +52 -1
- package/dist/index.js.map +2 -2
- package/dist/keys.d.ts +1 -0
- package/dist/keys.js +15 -0
- package/dist/keys.js.map +2 -2
- package/dist/terminal-buffer.d.ts +2 -0
- package/dist/terminal-buffer.js +38 -1
- package/dist/terminal-buffer.js.map +2 -2
- package/dist/terminal-pilot.js +52 -1
- package/dist/terminal-pilot.js.map +2 -2
- package/dist/terminal-session.js +52 -1
- package/dist/terminal-session.js.map +2 -2
- package/dist/testing/cli-repl.js +378 -64
- package/dist/testing/cli-repl.js.map +3 -3
- package/dist/testing/qa-cli.js +378 -64
- package/dist/testing/qa-cli.js.map +3 -3
- package/package.json +1 -1
|
@@ -431,6 +431,9 @@ import { rename, rm, writeFile } from "node:fs/promises";
|
|
|
431
431
|
|
|
432
432
|
// ../terminal-png/src/ansi-parser.ts
|
|
433
433
|
var ESC = "\x1B";
|
|
434
|
+
var TAB_WIDTH = 8;
|
|
435
|
+
var MAX_TERMINAL_ROWS = 1e3;
|
|
436
|
+
var MAX_TERMINAL_COLUMNS = 1e3;
|
|
434
437
|
function createDefaultStyle() {
|
|
435
438
|
return {
|
|
436
439
|
fg: null,
|
|
@@ -715,10 +718,34 @@ function positionParameter(params2, index, fallback) {
|
|
|
715
718
|
const value = toInteger(params2.split(";")[index]);
|
|
716
719
|
return value === null || value < 1 ? fallback : value;
|
|
717
720
|
}
|
|
721
|
+
function modeParameter(params2, fallback) {
|
|
722
|
+
const value = toInteger(params2.split(";")[0]);
|
|
723
|
+
return value === null ? fallback : value;
|
|
724
|
+
}
|
|
725
|
+
function displayWidth(text) {
|
|
726
|
+
if (text === " ") {
|
|
727
|
+
return TAB_WIDTH;
|
|
728
|
+
}
|
|
729
|
+
const codePoint = text.codePointAt(0);
|
|
730
|
+
if (codePoint === void 0) {
|
|
731
|
+
return 0;
|
|
732
|
+
}
|
|
733
|
+
if (codePoint >= 4352 && codePoint <= 4447 || codePoint === 9001 || codePoint === 9002 || codePoint >= 11904 && codePoint <= 42191 && codePoint !== 12351 || codePoint >= 44032 && codePoint <= 55203 || codePoint >= 63744 && codePoint <= 64255 || codePoint >= 65040 && codePoint <= 65049 || codePoint >= 65072 && codePoint <= 65135 || codePoint >= 65280 && codePoint <= 65376 || codePoint >= 65504 && codePoint <= 65510 || codePoint >= 127744 && codePoint <= 128591 || codePoint >= 129280 && codePoint <= 129535 || codePoint >= 131072 && codePoint <= 262141) {
|
|
734
|
+
return 2;
|
|
735
|
+
}
|
|
736
|
+
return 1;
|
|
737
|
+
}
|
|
738
|
+
function hasRenderableCell(line) {
|
|
739
|
+
return (line ?? []).some((cell) => cell !== void 0 && cell.text.length > 0);
|
|
740
|
+
}
|
|
718
741
|
function buildRuns(lines, lineBreakStyles) {
|
|
719
742
|
const runs = [];
|
|
720
743
|
const defaultStyle = createDefaultStyle();
|
|
721
|
-
|
|
744
|
+
let lastRow = lines.length - 1;
|
|
745
|
+
while (lastRow > 0 && !hasRenderableCell(lines[lastRow]) && lineBreakStyles[lastRow - 1] === void 0) {
|
|
746
|
+
lastRow -= 1;
|
|
747
|
+
}
|
|
748
|
+
for (let row = 0; row <= lastRow; row += 1) {
|
|
722
749
|
const line = lines[row] ?? [];
|
|
723
750
|
let lastCell = line.length - 1;
|
|
724
751
|
while (lastCell >= 0 && line[lastCell] === void 0) {
|
|
@@ -728,7 +755,7 @@ function buildRuns(lines, lineBreakStyles) {
|
|
|
728
755
|
const cell = line[column] ?? { text: " ", style: defaultStyle };
|
|
729
756
|
pushRun(runs, cell.style, cell.text);
|
|
730
757
|
}
|
|
731
|
-
if (row <
|
|
758
|
+
if (row < lastRow) {
|
|
732
759
|
pushRun(runs, lineBreakStyles[row] ?? defaultStyle, "\n");
|
|
733
760
|
}
|
|
734
761
|
}
|
|
@@ -740,7 +767,21 @@ function parseAnsi(input) {
|
|
|
740
767
|
let style = createDefaultStyle();
|
|
741
768
|
let row = 0;
|
|
742
769
|
let column = 0;
|
|
770
|
+
let savedRow = 0;
|
|
771
|
+
let savedColumn = 0;
|
|
743
772
|
let index = 0;
|
|
773
|
+
const clampRow = (nextRow) => {
|
|
774
|
+
if (nextRow < 0) {
|
|
775
|
+
return 0;
|
|
776
|
+
}
|
|
777
|
+
return Math.min(nextRow, MAX_TERMINAL_ROWS - 1);
|
|
778
|
+
};
|
|
779
|
+
const clampColumn = (nextColumn) => {
|
|
780
|
+
if (nextColumn < 0) {
|
|
781
|
+
return 0;
|
|
782
|
+
}
|
|
783
|
+
return Math.min(nextColumn, MAX_TERMINAL_COLUMNS - 1);
|
|
784
|
+
};
|
|
744
785
|
const ensureLine = () => {
|
|
745
786
|
while (lines.length <= row) {
|
|
746
787
|
lines.push([]);
|
|
@@ -748,12 +789,64 @@ function parseAnsi(input) {
|
|
|
748
789
|
};
|
|
749
790
|
const moveDown = (keepColumn) => {
|
|
750
791
|
lineBreakStyles[row] = cloneStyle(style);
|
|
751
|
-
row
|
|
792
|
+
row = clampRow(row + 1);
|
|
752
793
|
if (!keepColumn) {
|
|
753
794
|
column = 0;
|
|
754
795
|
}
|
|
755
796
|
ensureLine();
|
|
756
797
|
};
|
|
798
|
+
const eraseLine = (mode) => {
|
|
799
|
+
const line = lines[row] ?? [];
|
|
800
|
+
if (mode === 1) {
|
|
801
|
+
for (let cell = 0; cell <= column; cell += 1) {
|
|
802
|
+
delete line[cell];
|
|
803
|
+
}
|
|
804
|
+
return;
|
|
805
|
+
}
|
|
806
|
+
if (mode === 2) {
|
|
807
|
+
lines[row] = [];
|
|
808
|
+
return;
|
|
809
|
+
}
|
|
810
|
+
line.splice(column);
|
|
811
|
+
};
|
|
812
|
+
const eraseDisplay = (mode) => {
|
|
813
|
+
if (mode === 1) {
|
|
814
|
+
for (let lineRow = 0; lineRow < row; lineRow += 1) {
|
|
815
|
+
lines[lineRow] = [];
|
|
816
|
+
}
|
|
817
|
+
eraseLine(1);
|
|
818
|
+
return;
|
|
819
|
+
}
|
|
820
|
+
if (mode === 2 || mode === 3) {
|
|
821
|
+
lines.length = 0;
|
|
822
|
+
lineBreakStyles.length = 0;
|
|
823
|
+
ensureLine();
|
|
824
|
+
return;
|
|
825
|
+
}
|
|
826
|
+
eraseLine(0);
|
|
827
|
+
lines.splice(row + 1);
|
|
828
|
+
lineBreakStyles.splice(row);
|
|
829
|
+
};
|
|
830
|
+
const saveCursor = () => {
|
|
831
|
+
savedRow = row;
|
|
832
|
+
savedColumn = column;
|
|
833
|
+
};
|
|
834
|
+
const restoreCursor = () => {
|
|
835
|
+
row = clampRow(savedRow);
|
|
836
|
+
column = clampColumn(savedColumn);
|
|
837
|
+
ensureLine();
|
|
838
|
+
};
|
|
839
|
+
const writeText = (text) => {
|
|
840
|
+
const width = displayWidth(text);
|
|
841
|
+
if (width === 0) {
|
|
842
|
+
return;
|
|
843
|
+
}
|
|
844
|
+
lines[row][column] = { text, style: cloneStyle(style) };
|
|
845
|
+
for (let offset = 1; offset < width && column + offset < MAX_TERMINAL_COLUMNS; offset += 1) {
|
|
846
|
+
lines[row][column + offset] = { text: "", style: cloneStyle(style) };
|
|
847
|
+
}
|
|
848
|
+
column = clampColumn(column + width);
|
|
849
|
+
};
|
|
757
850
|
while (index < input.length) {
|
|
758
851
|
const char = input[index];
|
|
759
852
|
if (char === "\n") {
|
|
@@ -776,38 +869,73 @@ function parseAnsi(input) {
|
|
|
776
869
|
index += 1;
|
|
777
870
|
continue;
|
|
778
871
|
}
|
|
872
|
+
if (char === " ") {
|
|
873
|
+
const nextTabStop = Math.min(
|
|
874
|
+
Math.floor(column / TAB_WIDTH) * TAB_WIDTH + TAB_WIDTH,
|
|
875
|
+
MAX_TERMINAL_COLUMNS
|
|
876
|
+
);
|
|
877
|
+
while (column < nextTabStop) {
|
|
878
|
+
writeText(" ");
|
|
879
|
+
}
|
|
880
|
+
index += 1;
|
|
881
|
+
continue;
|
|
882
|
+
}
|
|
779
883
|
if (char === ESC && input[index + 1] === "]") {
|
|
780
884
|
index = parseOscEnd(input, index);
|
|
781
885
|
continue;
|
|
782
886
|
}
|
|
887
|
+
if (char === ESC && input[index + 1] === "7") {
|
|
888
|
+
saveCursor();
|
|
889
|
+
index += 2;
|
|
890
|
+
continue;
|
|
891
|
+
}
|
|
892
|
+
if (char === ESC && input[index + 1] === "8") {
|
|
893
|
+
restoreCursor();
|
|
894
|
+
index += 2;
|
|
895
|
+
continue;
|
|
896
|
+
}
|
|
783
897
|
const csiPrefixLength = char === "\x9B" ? 1 : char === ESC && input[index + 1] === "[" ? 2 : null;
|
|
784
898
|
if (csiPrefixLength !== null) {
|
|
785
899
|
const sequence = parseCsi(input, index, csiPrefixLength);
|
|
786
900
|
if (sequence.final === "m") {
|
|
787
901
|
style = applySgr(style, sequence.params);
|
|
788
902
|
} else if (sequence.final === "G") {
|
|
789
|
-
column = positionParameter(sequence.params, 0, 1) - 1;
|
|
903
|
+
column = clampColumn(positionParameter(sequence.params, 0, 1) - 1);
|
|
790
904
|
} else if (sequence.final === "C") {
|
|
791
|
-
column
|
|
905
|
+
column = clampColumn(column + positionParameter(sequence.params, 0, 1));
|
|
792
906
|
} else if (sequence.final === "D") {
|
|
793
907
|
column = Math.max(0, column - positionParameter(sequence.params, 0, 1));
|
|
794
908
|
} else if (sequence.final === "A") {
|
|
795
|
-
row =
|
|
909
|
+
row = clampRow(row - positionParameter(sequence.params, 0, 1));
|
|
796
910
|
} else if (sequence.final === "B") {
|
|
797
|
-
row
|
|
911
|
+
row = clampRow(row + positionParameter(sequence.params, 0, 1));
|
|
798
912
|
ensureLine();
|
|
913
|
+
} else if (sequence.final === "E") {
|
|
914
|
+
row = clampRow(row + positionParameter(sequence.params, 0, 1));
|
|
915
|
+
column = 0;
|
|
916
|
+
ensureLine();
|
|
917
|
+
} else if (sequence.final === "F") {
|
|
918
|
+
row = clampRow(row - positionParameter(sequence.params, 0, 1));
|
|
919
|
+
column = 0;
|
|
799
920
|
} else if (sequence.final === "H" || sequence.final === "f") {
|
|
800
|
-
row = positionParameter(sequence.params, 0, 1) - 1;
|
|
801
|
-
column = positionParameter(sequence.params, 1, 1) - 1;
|
|
921
|
+
row = clampRow(positionParameter(sequence.params, 0, 1) - 1);
|
|
922
|
+
column = clampColumn(positionParameter(sequence.params, 1, 1) - 1);
|
|
802
923
|
ensureLine();
|
|
924
|
+
} else if (sequence.final === "K") {
|
|
925
|
+
eraseLine(modeParameter(sequence.params, 0));
|
|
926
|
+
} else if (sequence.final === "J") {
|
|
927
|
+
eraseDisplay(modeParameter(sequence.params, 0));
|
|
928
|
+
} else if (sequence.final === "s") {
|
|
929
|
+
saveCursor();
|
|
930
|
+
} else if (sequence.final === "u") {
|
|
931
|
+
restoreCursor();
|
|
803
932
|
}
|
|
804
933
|
index = sequence.end;
|
|
805
934
|
continue;
|
|
806
935
|
}
|
|
807
936
|
const codePoint = input.codePointAt(index);
|
|
808
937
|
const text = codePoint === void 0 ? "" : String.fromCodePoint(codePoint);
|
|
809
|
-
|
|
810
|
-
column += 1;
|
|
938
|
+
writeText(text);
|
|
811
939
|
index += text.length;
|
|
812
940
|
}
|
|
813
941
|
return buildRuns(lines, lineBreakStyles);
|
|
@@ -1215,11 +1343,11 @@ function splitIntoLines(runs) {
|
|
|
1215
1343
|
}
|
|
1216
1344
|
function measureLines(lines) {
|
|
1217
1345
|
return Math.max(
|
|
1218
|
-
...lines.map((line) =>
|
|
1346
|
+
...lines.map((line) => displayWidth2(line.map((run) => run.text).join("")) * CHARACTER_WIDTH),
|
|
1219
1347
|
0
|
|
1220
1348
|
);
|
|
1221
1349
|
}
|
|
1222
|
-
function
|
|
1350
|
+
function displayWidth2(text, startColumn = 0) {
|
|
1223
1351
|
const segmenter = new Intl.Segmenter();
|
|
1224
1352
|
let column = startColumn;
|
|
1225
1353
|
for (const { segment } of segmenter.segment(text)) {
|
|
@@ -1281,7 +1409,7 @@ function renderBackgrounds(line, startX, y, height) {
|
|
|
1281
1409
|
let column = 0;
|
|
1282
1410
|
const rectangles = [];
|
|
1283
1411
|
for (const run of line) {
|
|
1284
|
-
const width =
|
|
1412
|
+
const width = displayWidth2(run.text, column);
|
|
1285
1413
|
const background = resolveBackgroundColor(run);
|
|
1286
1414
|
if (background !== BACKGROUND && width > 0) {
|
|
1287
1415
|
rectangles.push(`<rect x="${formatNumber(startX + column * CHARACTER_WIDTH)}" y="${formatNumber(y)}" width="${formatNumber(width * CHARACTER_WIDTH)}" height="${formatNumber(height)}" fill="${escapeXmlAttribute(background)}" />`);
|
|
@@ -1315,7 +1443,7 @@ function renderRun(run) {
|
|
|
1315
1443
|
if (run.dim) {
|
|
1316
1444
|
attributes.push('opacity="0.7"');
|
|
1317
1445
|
}
|
|
1318
|
-
const text = run.conceal ? " ".repeat(
|
|
1446
|
+
const text = run.conceal ? " ".repeat(displayWidth2(run.text)) : run.text;
|
|
1319
1447
|
return `<tspan ${attributes.join(" ")}>${escapeXmlText(text)}</tspan>`;
|
|
1320
1448
|
}
|
|
1321
1449
|
function renderWindowControls() {
|
|
@@ -1364,13 +1492,16 @@ async function renderTerminalPng(ansiText, options = {}) {
|
|
|
1364
1492
|
if (options.padding !== void 0 && (!Number.isInteger(options.padding) || options.padding < 0)) {
|
|
1365
1493
|
throw new Error("Padding must be a non-negative integer.");
|
|
1366
1494
|
}
|
|
1495
|
+
if (options.output !== void 0 && options.output.length === 0) {
|
|
1496
|
+
throw new Error("Output path must not be empty.");
|
|
1497
|
+
}
|
|
1367
1498
|
const runs = parseAnsi(ansiText);
|
|
1368
1499
|
const svg = renderSvg(runs, {
|
|
1369
1500
|
padding: options.padding,
|
|
1370
1501
|
window: options.window
|
|
1371
1502
|
});
|
|
1372
1503
|
const png = renderPng(svg);
|
|
1373
|
-
if (options.output) {
|
|
1504
|
+
if (options.output !== void 0) {
|
|
1374
1505
|
const temporaryPath = `${options.output}.${randomUUID()}.tmp`;
|
|
1375
1506
|
let temporaryCreated = false;
|
|
1376
1507
|
try {
|
|
@@ -1647,6 +1778,10 @@ var TerminalBuffer = class {
|
|
|
1647
1778
|
}
|
|
1648
1779
|
_writePrintable(ch) {
|
|
1649
1780
|
const width = this._cellWidth(ch);
|
|
1781
|
+
if (width === 0) {
|
|
1782
|
+
this._appendCombiningMark(ch);
|
|
1783
|
+
return;
|
|
1784
|
+
}
|
|
1650
1785
|
if (this._autoWrap && this._pendingWrap) {
|
|
1651
1786
|
this._cursorX = 0;
|
|
1652
1787
|
this._newline();
|
|
@@ -1681,11 +1816,40 @@ var TerminalBuffer = class {
|
|
|
1681
1816
|
_cellWidth(ch) {
|
|
1682
1817
|
const codePoint = ch.codePointAt(0);
|
|
1683
1818
|
if (codePoint === void 0) return 0;
|
|
1819
|
+
if (isCombiningCodePoint(codePoint)) {
|
|
1820
|
+
return 0;
|
|
1821
|
+
}
|
|
1684
1822
|
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) {
|
|
1685
1823
|
return Math.min(2, this._cols);
|
|
1686
1824
|
}
|
|
1687
1825
|
return 1;
|
|
1688
1826
|
}
|
|
1827
|
+
_appendCombiningMark(ch) {
|
|
1828
|
+
const target = this._findCombiningTarget();
|
|
1829
|
+
if (target === null) {
|
|
1830
|
+
return;
|
|
1831
|
+
}
|
|
1832
|
+
const cell = this._screen[target.y]?.[target.x];
|
|
1833
|
+
if (cell === null || cell === void 0) {
|
|
1834
|
+
return;
|
|
1835
|
+
}
|
|
1836
|
+
cell[1] += ch;
|
|
1837
|
+
}
|
|
1838
|
+
_findCombiningTarget() {
|
|
1839
|
+
const startX = this._pendingWrap ? this._cursorX : this._cursorX - 1;
|
|
1840
|
+
for (let y = this._cursorY; y >= 0; y -= 1) {
|
|
1841
|
+
const row = this._screen[y];
|
|
1842
|
+
if (row === void 0) {
|
|
1843
|
+
continue;
|
|
1844
|
+
}
|
|
1845
|
+
for (let x = y === this._cursorY ? startX : this._cols - 1; x >= 0; x -= 1) {
|
|
1846
|
+
if (row[x] !== null) {
|
|
1847
|
+
return { x, y };
|
|
1848
|
+
}
|
|
1849
|
+
}
|
|
1850
|
+
}
|
|
1851
|
+
return null;
|
|
1852
|
+
}
|
|
1689
1853
|
_setChar(y, x, ch) {
|
|
1690
1854
|
const row = this._screen[y];
|
|
1691
1855
|
if (row && x >= 0 && x < this._cols) {
|
|
@@ -1826,7 +1990,8 @@ var TerminalBuffer = class {
|
|
|
1826
1990
|
case "J":
|
|
1827
1991
|
if (p0 === 0) {
|
|
1828
1992
|
this._eraseLine(this._cursorY, this._cursorX, this._cols - 1);
|
|
1829
|
-
for (let y = this._cursorY + 1; y < this._rows; y++)
|
|
1993
|
+
for (let y = this._cursorY + 1; y < this._rows; y++)
|
|
1994
|
+
this._eraseLine(y, 0, this._cols - 1);
|
|
1830
1995
|
} else if (p0 === 1) {
|
|
1831
1996
|
for (let y = 0; y < this._cursorY; y++) this._eraseLine(y, 0, this._cols - 1);
|
|
1832
1997
|
this._eraseLine(this._cursorY, 0, this._cursorX);
|
|
@@ -2191,6 +2356,9 @@ function createDefaultStyleState() {
|
|
|
2191
2356
|
strikethrough: false
|
|
2192
2357
|
};
|
|
2193
2358
|
}
|
|
2359
|
+
function isCombiningCodePoint(codePoint) {
|
|
2360
|
+
return codePoint >= 768 && codePoint <= 879 || codePoint >= 6832 && codePoint <= 6911 || codePoint >= 7616 && codePoint <= 7679 || codePoint >= 8400 && codePoint <= 8447 || codePoint >= 65056 && codePoint <= 65071;
|
|
2361
|
+
}
|
|
2194
2362
|
function serializeStyleState(state) {
|
|
2195
2363
|
const codes = [];
|
|
2196
2364
|
if (state.bold) {
|
|
@@ -2244,6 +2412,8 @@ var NAMED_KEY_LOWER = new Map(
|
|
|
2244
2412
|
Object.entries(NAMED_KEY_SEQUENCES).map(([k, v]) => [k.toLowerCase(), v])
|
|
2245
2413
|
);
|
|
2246
2414
|
var VALID_KEYS_HINT = `Valid keys: ${Object.keys(NAMED_KEY_SEQUENCES).join(", ")}, Control+<letter>, Alt+<key>`;
|
|
2415
|
+
var NAMED_KEY_PATTERN = Object.keys(NAMED_KEY_SEQUENCES).map(caseInsensitivePattern).join("|");
|
|
2416
|
+
var TERMINAL_KEY_PATTERN = `^(?:${NAMED_KEY_PATTERN}|.|[Cc][Oo][Nn][Tt][Rr][Oo][Ll]\\+[A-Za-z]|[Aa][Ll][Tt]\\+.+)$`;
|
|
2247
2417
|
function unknownKeyError(key) {
|
|
2248
2418
|
return new Error(`Unknown terminal key: ${key}. ${VALID_KEYS_HINT}`);
|
|
2249
2419
|
}
|
|
@@ -2286,6 +2456,18 @@ function controlKeyToSequence(controlKey) {
|
|
|
2286
2456
|
}
|
|
2287
2457
|
return String.fromCharCode(charCode - 64);
|
|
2288
2458
|
}
|
|
2459
|
+
function caseInsensitivePattern(value) {
|
|
2460
|
+
let pattern = "";
|
|
2461
|
+
for (const character of value) {
|
|
2462
|
+
const lower = character.toLowerCase();
|
|
2463
|
+
const upper = character.toUpperCase();
|
|
2464
|
+
pattern += lower === upper ? escapePatternCharacter(character) : `[${upper}${lower}]`;
|
|
2465
|
+
}
|
|
2466
|
+
return pattern;
|
|
2467
|
+
}
|
|
2468
|
+
function escapePatternCharacter(character) {
|
|
2469
|
+
return character.replace(/[\\^$.*+?()[\]{}|]/g, "\\$&");
|
|
2470
|
+
}
|
|
2289
2471
|
|
|
2290
2472
|
// src/terminal-screen.ts
|
|
2291
2473
|
var TerminalScreen = class {
|
|
@@ -2725,7 +2907,11 @@ function createTerminalPilotRuntime(options = {}) {
|
|
|
2725
2907
|
const pendingNames = /* @__PURE__ */ new Set();
|
|
2726
2908
|
let pilotPromise;
|
|
2727
2909
|
function getRequestedName(name, env) {
|
|
2728
|
-
|
|
2910
|
+
const requestedName = name ?? env?.get(SESSION_ENV_VAR);
|
|
2911
|
+
if (requestedName !== void 0 && requestedName.trim().length === 0) {
|
|
2912
|
+
throw new UserError("Session name must not be empty.");
|
|
2913
|
+
}
|
|
2914
|
+
return requestedName;
|
|
2729
2915
|
}
|
|
2730
2916
|
async function getPilot() {
|
|
2731
2917
|
pilotPromise ??= launchPilot();
|
|
@@ -2761,7 +2947,9 @@ function createTerminalPilotRuntime(options = {}) {
|
|
|
2761
2947
|
const sessionId = nameToId.get(name);
|
|
2762
2948
|
if (sessionId === void 0) {
|
|
2763
2949
|
const active = await listSessions();
|
|
2764
|
-
throw new UserError(
|
|
2950
|
+
throw new UserError(
|
|
2951
|
+
`Session "${name}" was not found. ${formatAvailableSessions(active.map((entry) => entry.name))}`
|
|
2952
|
+
);
|
|
2765
2953
|
}
|
|
2766
2954
|
const pilot = await getPilot();
|
|
2767
2955
|
try {
|
|
@@ -2769,7 +2957,9 @@ function createTerminalPilotRuntime(options = {}) {
|
|
|
2769
2957
|
} catch {
|
|
2770
2958
|
forgetSession(name, sessionId);
|
|
2771
2959
|
const active = await listSessions();
|
|
2772
|
-
throw new UserError(
|
|
2960
|
+
throw new UserError(
|
|
2961
|
+
`Session "${name}" was not found. ${formatAvailableSessions(active.map((entry) => entry.name))}`
|
|
2962
|
+
);
|
|
2773
2963
|
}
|
|
2774
2964
|
}
|
|
2775
2965
|
async function listSessions() {
|
|
@@ -2800,6 +2990,9 @@ function createTerminalPilotRuntime(options = {}) {
|
|
|
2800
2990
|
}
|
|
2801
2991
|
return {
|
|
2802
2992
|
async createSession(params2, env) {
|
|
2993
|
+
if (params2.command.trim().length === 0) {
|
|
2994
|
+
throw new UserError("Command must not be empty.");
|
|
2995
|
+
}
|
|
2803
2996
|
const requestedName = getRequestedName(params2.session, env) ?? nextSessionName();
|
|
2804
2997
|
await discardExitedSessionName(requestedName);
|
|
2805
2998
|
if (nameToId.has(requestedName) || pendingNames.has(requestedName)) {
|
|
@@ -2865,10 +3058,19 @@ function createTerminalPilotRuntime(options = {}) {
|
|
|
2865
3058
|
|
|
2866
3059
|
// src/commands/screenshot.ts
|
|
2867
3060
|
var params = S.Object({
|
|
2868
|
-
session: S.Optional(
|
|
3061
|
+
session: S.Optional(
|
|
3062
|
+
S.String({ short: "s", description: "Session name", minLength: 1, pattern: "\\S" })
|
|
3063
|
+
),
|
|
2869
3064
|
output: S.String({ short: "o", description: "Path to the output PNG file" }),
|
|
2870
3065
|
window: S.Optional(S.Boolean({ description: "Include terminal window chrome", default: true })),
|
|
2871
|
-
padding: S.Optional(
|
|
3066
|
+
padding: S.Optional(
|
|
3067
|
+
S.Number({
|
|
3068
|
+
short: "p",
|
|
3069
|
+
description: "Padding around terminal content",
|
|
3070
|
+
jsonType: "integer",
|
|
3071
|
+
minimum: 0
|
|
3072
|
+
})
|
|
3073
|
+
)
|
|
2872
3074
|
});
|
|
2873
3075
|
var screenshot = defineCommand({
|
|
2874
3076
|
name: "screenshot",
|
|
@@ -2876,7 +3078,10 @@ var screenshot = defineCommand({
|
|
|
2876
3078
|
scope: ["cli"],
|
|
2877
3079
|
params,
|
|
2878
3080
|
handler: async ({ params: params2, env, terminalPilotRuntime }) => {
|
|
2879
|
-
const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(
|
|
3081
|
+
const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(
|
|
3082
|
+
params2.session,
|
|
3083
|
+
env
|
|
3084
|
+
);
|
|
2880
3085
|
const screen = await namedSession.session.screen();
|
|
2881
3086
|
await renderTerminalPng(screen.rawLines.join("\n"), {
|
|
2882
3087
|
output: params2.output,
|