terminal-pilot 0.0.28 → 0.0.30

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 (57) hide show
  1. package/dist/cli.js +430 -68
  2. package/dist/cli.js.map +3 -3
  3. package/dist/commands/close-session.js +73 -6
  4. package/dist/commands/close-session.js.map +2 -2
  5. package/dist/commands/create-session.js +80 -9
  6. package/dist/commands/create-session.js.map +2 -2
  7. package/dist/commands/fill.js +73 -6
  8. package/dist/commands/fill.js.map +2 -2
  9. package/dist/commands/get-session.js +73 -6
  10. package/dist/commands/get-session.js.map +2 -2
  11. package/dist/commands/index.js +371 -62
  12. package/dist/commands/index.js.map +3 -3
  13. package/dist/commands/install.js +10 -5
  14. package/dist/commands/install.js.map +2 -2
  15. package/dist/commands/installer.js +10 -5
  16. package/dist/commands/installer.js.map +2 -2
  17. package/dist/commands/list-sessions.js +66 -4
  18. package/dist/commands/list-sessions.js.map +2 -2
  19. package/dist/commands/press-key.js +146 -71
  20. package/dist/commands/press-key.js.map +3 -3
  21. package/dist/commands/read-history.js +81 -7
  22. package/dist/commands/read-history.js.map +2 -2
  23. package/dist/commands/read-screen.js +73 -6
  24. package/dist/commands/read-screen.js.map +2 -2
  25. package/dist/commands/resize.js +75 -8
  26. package/dist/commands/resize.js.map +2 -2
  27. package/dist/commands/runtime.js +66 -4
  28. package/dist/commands/runtime.js.map +2 -2
  29. package/dist/commands/screenshot.js +228 -23
  30. package/dist/commands/screenshot.js.map +3 -3
  31. package/dist/commands/send-signal.js +73 -6
  32. package/dist/commands/send-signal.js.map +2 -2
  33. package/dist/commands/type.js +73 -6
  34. package/dist/commands/type.js.map +2 -2
  35. package/dist/commands/uninstall.js +10 -5
  36. package/dist/commands/uninstall.js.map +2 -2
  37. package/dist/commands/wait-for-exit.js +79 -7
  38. package/dist/commands/wait-for-exit.js.map +2 -2
  39. package/dist/commands/wait-for.js +90 -8
  40. package/dist/commands/wait-for.js.map +3 -3
  41. package/dist/index.js +52 -1
  42. package/dist/index.js.map +2 -2
  43. package/dist/keys.d.ts +1 -0
  44. package/dist/keys.js +15 -0
  45. package/dist/keys.js.map +2 -2
  46. package/dist/terminal-buffer.d.ts +2 -0
  47. package/dist/terminal-buffer.js +38 -1
  48. package/dist/terminal-buffer.js.map +2 -2
  49. package/dist/terminal-pilot.js +52 -1
  50. package/dist/terminal-pilot.js.map +2 -2
  51. package/dist/terminal-session.js +52 -1
  52. package/dist/terminal-session.js.map +2 -2
  53. package/dist/testing/cli-repl.js +430 -68
  54. package/dist/testing/cli-repl.js.map +3 -3
  55. package/dist/testing/qa-cli.js +430 -68
  56. package/dist/testing/qa-cli.js.map +3 -3
  57. package/package.json +1 -1
@@ -678,6 +678,10 @@ var TerminalBuffer = class {
678
678
  }
679
679
  _writePrintable(ch) {
680
680
  const width = this._cellWidth(ch);
681
+ if (width === 0) {
682
+ this._appendCombiningMark(ch);
683
+ return;
684
+ }
681
685
  if (this._autoWrap && this._pendingWrap) {
682
686
  this._cursorX = 0;
683
687
  this._newline();
@@ -712,11 +716,40 @@ var TerminalBuffer = class {
712
716
  _cellWidth(ch) {
713
717
  const codePoint = ch.codePointAt(0);
714
718
  if (codePoint === void 0) return 0;
719
+ if (isCombiningCodePoint(codePoint)) {
720
+ return 0;
721
+ }
715
722
  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) {
716
723
  return Math.min(2, this._cols);
717
724
  }
718
725
  return 1;
719
726
  }
727
+ _appendCombiningMark(ch) {
728
+ const target = this._findCombiningTarget();
729
+ if (target === null) {
730
+ return;
731
+ }
732
+ const cell = this._screen[target.y]?.[target.x];
733
+ if (cell === null || cell === void 0) {
734
+ return;
735
+ }
736
+ cell[1] += ch;
737
+ }
738
+ _findCombiningTarget() {
739
+ const startX = this._pendingWrap ? this._cursorX : this._cursorX - 1;
740
+ for (let y = this._cursorY; y >= 0; y -= 1) {
741
+ const row = this._screen[y];
742
+ if (row === void 0) {
743
+ continue;
744
+ }
745
+ for (let x = y === this._cursorY ? startX : this._cols - 1; x >= 0; x -= 1) {
746
+ if (row[x] !== null) {
747
+ return { x, y };
748
+ }
749
+ }
750
+ }
751
+ return null;
752
+ }
720
753
  _setChar(y, x, ch) {
721
754
  const row = this._screen[y];
722
755
  if (row && x >= 0 && x < this._cols) {
@@ -857,7 +890,8 @@ var TerminalBuffer = class {
857
890
  case "J":
858
891
  if (p0 === 0) {
859
892
  this._eraseLine(this._cursorY, this._cursorX, this._cols - 1);
860
- for (let y = this._cursorY + 1; y < this._rows; y++) this._eraseLine(y, 0, this._cols - 1);
893
+ for (let y = this._cursorY + 1; y < this._rows; y++)
894
+ this._eraseLine(y, 0, this._cols - 1);
861
895
  } else if (p0 === 1) {
862
896
  for (let y = 0; y < this._cursorY; y++) this._eraseLine(y, 0, this._cols - 1);
863
897
  this._eraseLine(this._cursorY, 0, this._cursorX);
@@ -1222,6 +1256,9 @@ function createDefaultStyleState() {
1222
1256
  strikethrough: false
1223
1257
  };
1224
1258
  }
1259
+ function isCombiningCodePoint(codePoint) {
1260
+ return codePoint >= 768 && codePoint <= 879 || codePoint >= 6832 && codePoint <= 6911 || codePoint >= 7616 && codePoint <= 7679 || codePoint >= 8400 && codePoint <= 8447 || codePoint >= 65056 && codePoint <= 65071;
1261
+ }
1225
1262
  function serializeStyleState(state) {
1226
1263
  const codes = [];
1227
1264
  if (state.bold) {
@@ -1275,6 +1312,8 @@ var NAMED_KEY_LOWER = new Map(
1275
1312
  Object.entries(NAMED_KEY_SEQUENCES).map(([k, v]) => [k.toLowerCase(), v])
1276
1313
  );
1277
1314
  var VALID_KEYS_HINT = `Valid keys: ${Object.keys(NAMED_KEY_SEQUENCES).join(", ")}, Control+<letter>, Alt+<key>`;
1315
+ var NAMED_KEY_PATTERN = Object.keys(NAMED_KEY_SEQUENCES).map(caseInsensitivePattern).join("|");
1316
+ var TERMINAL_KEY_PATTERN = `^(?:${NAMED_KEY_PATTERN}|.|[Cc][Oo][Nn][Tt][Rr][Oo][Ll]\\+[A-Za-z]|[Aa][Ll][Tt]\\+.+)$`;
1278
1317
  function unknownKeyError(key) {
1279
1318
  return new Error(`Unknown terminal key: ${key}. ${VALID_KEYS_HINT}`);
1280
1319
  }
@@ -1317,6 +1356,18 @@ function controlKeyToSequence(controlKey) {
1317
1356
  }
1318
1357
  return String.fromCharCode(charCode - 64);
1319
1358
  }
1359
+ function caseInsensitivePattern(value) {
1360
+ let pattern = "";
1361
+ for (const character of value) {
1362
+ const lower = character.toLowerCase();
1363
+ const upper = character.toUpperCase();
1364
+ pattern += lower === upper ? escapePatternCharacter(character) : `[${upper}${lower}]`;
1365
+ }
1366
+ return pattern;
1367
+ }
1368
+ function escapePatternCharacter(character) {
1369
+ return character.replace(/[\\^$.*+?()[\]{}|]/g, "\\$&");
1370
+ }
1320
1371
 
1321
1372
  // src/terminal-screen.ts
1322
1373
  var TerminalScreen = class {
@@ -1756,7 +1807,11 @@ function createTerminalPilotRuntime(options = {}) {
1756
1807
  const pendingNames = /* @__PURE__ */ new Set();
1757
1808
  let pilotPromise;
1758
1809
  function getRequestedName(name, env) {
1759
- return name ?? env?.get(SESSION_ENV_VAR);
1810
+ const requestedName = name ?? env?.get(SESSION_ENV_VAR);
1811
+ if (requestedName !== void 0 && requestedName.trim().length === 0) {
1812
+ throw new UserError("Session name must not be empty.");
1813
+ }
1814
+ return requestedName;
1760
1815
  }
1761
1816
  async function getPilot() {
1762
1817
  pilotPromise ??= launchPilot();
@@ -1792,7 +1847,9 @@ function createTerminalPilotRuntime(options = {}) {
1792
1847
  const sessionId = nameToId.get(name);
1793
1848
  if (sessionId === void 0) {
1794
1849
  const active = await listSessions();
1795
- throw new UserError(`Session "${name}" was not found. ${formatAvailableSessions(active.map((entry) => entry.name))}`);
1850
+ throw new UserError(
1851
+ `Session "${name}" was not found. ${formatAvailableSessions(active.map((entry) => entry.name))}`
1852
+ );
1796
1853
  }
1797
1854
  const pilot = await getPilot();
1798
1855
  try {
@@ -1800,7 +1857,9 @@ function createTerminalPilotRuntime(options = {}) {
1800
1857
  } catch {
1801
1858
  forgetSession(name, sessionId);
1802
1859
  const active = await listSessions();
1803
- throw new UserError(`Session "${name}" was not found. ${formatAvailableSessions(active.map((entry) => entry.name))}`);
1860
+ throw new UserError(
1861
+ `Session "${name}" was not found. ${formatAvailableSessions(active.map((entry) => entry.name))}`
1862
+ );
1804
1863
  }
1805
1864
  }
1806
1865
  async function listSessions() {
@@ -1831,6 +1890,9 @@ function createTerminalPilotRuntime(options = {}) {
1831
1890
  }
1832
1891
  return {
1833
1892
  async createSession(params2, env) {
1893
+ if (params2.command.trim().length === 0) {
1894
+ throw new UserError("Command must not be empty.");
1895
+ }
1834
1896
  const requestedName = getRequestedName(params2.session, env) ?? nextSessionName();
1835
1897
  await discardExitedSessionName(requestedName);
1836
1898
  if (nameToId.has(requestedName) || pendingNames.has(requestedName)) {
@@ -1896,9 +1958,17 @@ function createTerminalPilotRuntime(options = {}) {
1896
1958
 
1897
1959
  // src/commands/wait-for.ts
1898
1960
  var params = S.Object({
1899
- pattern: S.String({ description: "Regular expression pattern to wait for" }),
1900
- session: S.Optional(S.String({ short: "s", description: "Session name" })),
1901
- timeout: S.Optional(S.Number({ short: "t", description: "Maximum wait time in milliseconds" })),
1961
+ pattern: S.String({
1962
+ description: "Regular expression pattern to wait for",
1963
+ minLength: 1,
1964
+ pattern: "\\S"
1965
+ }),
1966
+ session: S.Optional(
1967
+ S.String({ short: "s", description: "Session name", minLength: 1, pattern: "\\S" })
1968
+ ),
1969
+ timeout: S.Optional(
1970
+ S.Number({ short: "t", description: "Maximum wait time in milliseconds", minimum: 0 })
1971
+ ),
1902
1972
  literal: S.Optional(
1903
1973
  S.Boolean({
1904
1974
  short: "l",
@@ -1913,12 +1983,24 @@ var waitFor = defineCommand({
1913
1983
  positional: ["pattern"],
1914
1984
  params,
1915
1985
  handler: async ({ params: params2, env, terminalPilotRuntime }) => {
1916
- const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(params2.session, env);
1986
+ if (params2.pattern.trim().length === 0) {
1987
+ throw new UserError("Wait pattern must not be empty.");
1988
+ }
1989
+ assertTimeout2(params2.timeout);
1990
+ const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(
1991
+ params2.session,
1992
+ env
1993
+ );
1917
1994
  const pattern = params2.literal === true ? params2.pattern : new RegExp(params2.pattern);
1918
1995
  const line = params2.timeout === void 0 ? await namedSession.session.waitFor(pattern) : await namedSession.session.waitFor(pattern, { timeout: params2.timeout });
1919
1996
  return { matched: true, line };
1920
1997
  }
1921
1998
  });
1999
+ function assertTimeout2(timeout) {
2000
+ if (timeout !== void 0 && (!Number.isFinite(timeout) || timeout < 0)) {
2001
+ throw new UserError("Timeout must be a finite non-negative number.");
2002
+ }
2003
+ }
1922
2004
  export {
1923
2005
  waitFor
1924
2006
  };