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.
Files changed (57) hide show
  1. package/dist/cli.js +378 -64
  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 +378 -64
  54. package/dist/testing/cli-repl.js.map +3 -3
  55. package/dist/testing/qa-cli.js +378 -64
  56. package/dist/testing/qa-cli.js.map +3 -3
  57. package/package.json +1 -1
@@ -12574,10 +12574,15 @@ async function writeErrorReport(context) {
12574
12574
 
12575
12575
  // ../toolcraft/src/number-schema.ts
12576
12576
  function isValidNumberSchemaValue(value, schema) {
12577
- return typeof value === "number" && Number.isFinite(value) && (schema.jsonType !== "integer" || Number.isInteger(value));
12577
+ return typeof value === "number" && Number.isFinite(value) && (schema.jsonType !== "integer" || Number.isInteger(value)) && (schema.minimum === void 0 || value >= schema.minimum) && (schema.maximum === void 0 || value <= schema.maximum);
12578
12578
  }
12579
12579
  function getExpectedNumberDescription(schema) {
12580
- return schema.jsonType === "integer" ? "an integer" : "a number";
12580
+ const type2 = schema.jsonType === "integer" ? "an integer" : "a number";
12581
+ const bounds = [
12582
+ schema.minimum === void 0 ? void 0 : `greater than or equal to ${schema.minimum}`,
12583
+ schema.maximum === void 0 ? void 0 : `less than or equal to ${schema.maximum}`
12584
+ ].filter((bound) => bound !== void 0);
12585
+ return bounds.length === 0 ? type2 : `${type2} ${bounds.join(" and ")}`;
12581
12586
  }
12582
12587
 
12583
12588
  // ../toolcraft/src/renderer.ts
@@ -16474,6 +16479,10 @@ var TerminalBuffer = class {
16474
16479
  }
16475
16480
  _writePrintable(ch) {
16476
16481
  const width = this._cellWidth(ch);
16482
+ if (width === 0) {
16483
+ this._appendCombiningMark(ch);
16484
+ return;
16485
+ }
16477
16486
  if (this._autoWrap && this._pendingWrap) {
16478
16487
  this._cursorX = 0;
16479
16488
  this._newline();
@@ -16508,11 +16517,40 @@ var TerminalBuffer = class {
16508
16517
  _cellWidth(ch) {
16509
16518
  const codePoint = ch.codePointAt(0);
16510
16519
  if (codePoint === void 0) return 0;
16520
+ if (isCombiningCodePoint2(codePoint)) {
16521
+ return 0;
16522
+ }
16511
16523
  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) {
16512
16524
  return Math.min(2, this._cols);
16513
16525
  }
16514
16526
  return 1;
16515
16527
  }
16528
+ _appendCombiningMark(ch) {
16529
+ const target = this._findCombiningTarget();
16530
+ if (target === null) {
16531
+ return;
16532
+ }
16533
+ const cell = this._screen[target.y]?.[target.x];
16534
+ if (cell === null || cell === void 0) {
16535
+ return;
16536
+ }
16537
+ cell[1] += ch;
16538
+ }
16539
+ _findCombiningTarget() {
16540
+ const startX = this._pendingWrap ? this._cursorX : this._cursorX - 1;
16541
+ for (let y = this._cursorY; y >= 0; y -= 1) {
16542
+ const row = this._screen[y];
16543
+ if (row === void 0) {
16544
+ continue;
16545
+ }
16546
+ for (let x = y === this._cursorY ? startX : this._cols - 1; x >= 0; x -= 1) {
16547
+ if (row[x] !== null) {
16548
+ return { x, y };
16549
+ }
16550
+ }
16551
+ }
16552
+ return null;
16553
+ }
16516
16554
  _setChar(y, x, ch) {
16517
16555
  const row = this._screen[y];
16518
16556
  if (row && x >= 0 && x < this._cols) {
@@ -16653,7 +16691,8 @@ var TerminalBuffer = class {
16653
16691
  case "J":
16654
16692
  if (p0 === 0) {
16655
16693
  this._eraseLine(this._cursorY, this._cursorX, this._cols - 1);
16656
- for (let y = this._cursorY + 1; y < this._rows; y++) this._eraseLine(y, 0, this._cols - 1);
16694
+ for (let y = this._cursorY + 1; y < this._rows; y++)
16695
+ this._eraseLine(y, 0, this._cols - 1);
16657
16696
  } else if (p0 === 1) {
16658
16697
  for (let y = 0; y < this._cursorY; y++) this._eraseLine(y, 0, this._cols - 1);
16659
16698
  this._eraseLine(this._cursorY, 0, this._cursorX);
@@ -17018,6 +17057,9 @@ function createDefaultStyleState() {
17018
17057
  strikethrough: false
17019
17058
  };
17020
17059
  }
17060
+ function isCombiningCodePoint2(codePoint) {
17061
+ return codePoint >= 768 && codePoint <= 879 || codePoint >= 6832 && codePoint <= 6911 || codePoint >= 7616 && codePoint <= 7679 || codePoint >= 8400 && codePoint <= 8447 || codePoint >= 65056 && codePoint <= 65071;
17062
+ }
17021
17063
  function serializeStyleState(state) {
17022
17064
  const codes = [];
17023
17065
  if (state.bold) {
@@ -17071,6 +17113,8 @@ var NAMED_KEY_LOWER = new Map(
17071
17113
  Object.entries(NAMED_KEY_SEQUENCES).map(([k, v]) => [k.toLowerCase(), v])
17072
17114
  );
17073
17115
  var VALID_KEYS_HINT = `Valid keys: ${Object.keys(NAMED_KEY_SEQUENCES).join(", ")}, Control+<letter>, Alt+<key>`;
17116
+ var NAMED_KEY_PATTERN = Object.keys(NAMED_KEY_SEQUENCES).map(caseInsensitivePattern).join("|");
17117
+ var TERMINAL_KEY_PATTERN = `^(?:${NAMED_KEY_PATTERN}|.|[Cc][Oo][Nn][Tt][Rr][Oo][Ll]\\+[A-Za-z]|[Aa][Ll][Tt]\\+.+)$`;
17074
17118
  function unknownKeyError(key2) {
17075
17119
  return new Error(`Unknown terminal key: ${key2}. ${VALID_KEYS_HINT}`);
17076
17120
  }
@@ -17113,6 +17157,18 @@ function controlKeyToSequence(controlKey) {
17113
17157
  }
17114
17158
  return String.fromCharCode(charCode - 64);
17115
17159
  }
17160
+ function caseInsensitivePattern(value) {
17161
+ let pattern = "";
17162
+ for (const character of value) {
17163
+ const lower = character.toLowerCase();
17164
+ const upper = character.toUpperCase();
17165
+ pattern += lower === upper ? escapePatternCharacter(character) : `[${upper}${lower}]`;
17166
+ }
17167
+ return pattern;
17168
+ }
17169
+ function escapePatternCharacter(character) {
17170
+ return character.replace(/[\\^$.*+?()[\]{}|]/g, "\\$&");
17171
+ }
17116
17172
 
17117
17173
  // src/terminal-screen.ts
17118
17174
  var TerminalScreen = class {
@@ -17552,7 +17608,11 @@ function createTerminalPilotRuntime(options = {}) {
17552
17608
  const pendingNames = /* @__PURE__ */ new Set();
17553
17609
  let pilotPromise;
17554
17610
  function getRequestedName(name, env) {
17555
- return name ?? env?.get(SESSION_ENV_VAR);
17611
+ const requestedName = name ?? env?.get(SESSION_ENV_VAR);
17612
+ if (requestedName !== void 0 && requestedName.trim().length === 0) {
17613
+ throw new UserError("Session name must not be empty.");
17614
+ }
17615
+ return requestedName;
17556
17616
  }
17557
17617
  async function getPilot() {
17558
17618
  pilotPromise ??= launchPilot();
@@ -17588,7 +17648,9 @@ function createTerminalPilotRuntime(options = {}) {
17588
17648
  const sessionId = nameToId.get(name);
17589
17649
  if (sessionId === void 0) {
17590
17650
  const active = await listSessions2();
17591
- throw new UserError(`Session "${name}" was not found. ${formatAvailableSessions(active.map((entry) => entry.name))}`);
17651
+ throw new UserError(
17652
+ `Session "${name}" was not found. ${formatAvailableSessions(active.map((entry) => entry.name))}`
17653
+ );
17592
17654
  }
17593
17655
  const pilot = await getPilot();
17594
17656
  try {
@@ -17596,7 +17658,9 @@ function createTerminalPilotRuntime(options = {}) {
17596
17658
  } catch {
17597
17659
  forgetSession(name, sessionId);
17598
17660
  const active = await listSessions2();
17599
- throw new UserError(`Session "${name}" was not found. ${formatAvailableSessions(active.map((entry) => entry.name))}`);
17661
+ throw new UserError(
17662
+ `Session "${name}" was not found. ${formatAvailableSessions(active.map((entry) => entry.name))}`
17663
+ );
17600
17664
  }
17601
17665
  }
17602
17666
  async function listSessions2() {
@@ -17627,6 +17691,9 @@ function createTerminalPilotRuntime(options = {}) {
17627
17691
  }
17628
17692
  return {
17629
17693
  async createSession(params17, env) {
17694
+ if (params17.command.trim().length === 0) {
17695
+ throw new UserError("Command must not be empty.");
17696
+ }
17630
17697
  const requestedName = getRequestedName(params17.session, env) ?? nextSessionName();
17631
17698
  await discardExitedSessionName(requestedName);
17632
17699
  if (nameToId.has(requestedName) || pendingNames.has(requestedName)) {
@@ -17699,7 +17766,9 @@ async function closeSharedTerminalPilotRuntime() {
17699
17766
 
17700
17767
  // src/commands/close-session.ts
17701
17768
  var params = S.Object({
17702
- session: S.Optional(S.String({ short: "s", description: "Session name" }))
17769
+ session: S.Optional(
17770
+ S.String({ short: "s", description: "Session name", minLength: 1, pattern: "\\S" })
17771
+ )
17703
17772
  });
17704
17773
  var closeSession = defineCommand({
17705
17774
  name: "close-session",
@@ -17707,19 +17776,28 @@ var closeSession = defineCommand({
17707
17776
  scope: ["cli", "mcp", "sdk"],
17708
17777
  params,
17709
17778
  handler: async ({ params: params17, env, terminalPilotRuntime }) => {
17710
- const { exitCode } = await getTerminalPilotRuntime(terminalPilotRuntime).closeSession(params17.session, env);
17779
+ const { exitCode } = await getTerminalPilotRuntime(terminalPilotRuntime).closeSession(
17780
+ params17.session,
17781
+ env
17782
+ );
17711
17783
  return { exitCode };
17712
17784
  }
17713
17785
  });
17714
17786
 
17715
17787
  // src/commands/create-session.ts
17716
17788
  var params2 = S.Object({
17717
- command: S.String({ description: "Command to execute" }),
17789
+ command: S.String({ description: "Command to execute", minLength: 1, pattern: "\\S" }),
17718
17790
  args: S.Optional(S.Array(S.String(), { description: "Command arguments" })),
17719
- session: S.Optional(S.String({ short: "s", description: "Session name" })),
17791
+ session: S.Optional(
17792
+ S.String({ short: "s", description: "Session name", minLength: 1, pattern: "\\S" })
17793
+ ),
17720
17794
  cwd: S.Optional(S.String({ description: "Working directory" })),
17721
- cols: S.Optional(S.Number({ description: "Terminal width in columns" })),
17722
- rows: S.Optional(S.Number({ description: "Terminal height in rows" })),
17795
+ cols: S.Optional(
17796
+ S.Number({ description: "Terminal width in columns", jsonType: "integer", minimum: 1 })
17797
+ ),
17798
+ rows: S.Optional(
17799
+ S.Number({ description: "Terminal height in rows", jsonType: "integer", minimum: 1 })
17800
+ ),
17723
17801
  observe: S.Optional(S.Boolean({ description: "Mirror PTY output to stderr" }))
17724
17802
  });
17725
17803
  var createSession = defineCommand({
@@ -17729,7 +17807,10 @@ var createSession = defineCommand({
17729
17807
  positional: ["command", "args"],
17730
17808
  params: params2,
17731
17809
  handler: async ({ params: params17, env, terminalPilotRuntime }) => {
17732
- const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).createSession(params17, env);
17810
+ const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).createSession(
17811
+ params17,
17812
+ env
17813
+ );
17733
17814
  return { session: namedSession.name, pid: namedSession.session.pid };
17734
17815
  }
17735
17816
  });
@@ -17737,7 +17818,9 @@ var createSession = defineCommand({
17737
17818
  // src/commands/fill.ts
17738
17819
  var params3 = S.Object({
17739
17820
  text: S.String({ description: "Text to write to the session" }),
17740
- session: S.Optional(S.String({ short: "s", description: "Session name" }))
17821
+ session: S.Optional(
17822
+ S.String({ short: "s", description: "Session name", minLength: 1, pattern: "\\S" })
17823
+ )
17741
17824
  });
17742
17825
  var fill = defineCommand({
17743
17826
  name: "fill",
@@ -17746,7 +17829,10 @@ var fill = defineCommand({
17746
17829
  positional: ["text"],
17747
17830
  params: params3,
17748
17831
  handler: async ({ params: params17, env, terminalPilotRuntime }) => {
17749
- const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(params17.session, env);
17832
+ const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(
17833
+ params17.session,
17834
+ env
17835
+ );
17750
17836
  await namedSession.session.fill(params17.text);
17751
17837
  return void 0;
17752
17838
  }
@@ -17754,7 +17840,9 @@ var fill = defineCommand({
17754
17840
 
17755
17841
  // src/commands/get-session.ts
17756
17842
  var params4 = S.Object({
17757
- session: S.Optional(S.String({ short: "s", description: "Session name" }))
17843
+ session: S.Optional(
17844
+ S.String({ short: "s", description: "Session name", minLength: 1, pattern: "\\S" })
17845
+ )
17758
17846
  });
17759
17847
  var getSession = defineCommand({
17760
17848
  name: "get-session",
@@ -17762,7 +17850,10 @@ var getSession = defineCommand({
17762
17850
  scope: ["cli", "mcp", "sdk"],
17763
17851
  params: params4,
17764
17852
  handler: async ({ params: params17, env, terminalPilotRuntime }) => {
17765
- const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(params17.session, env);
17853
+ const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(
17854
+ params17.session,
17855
+ env
17856
+ );
17766
17857
  return {
17767
17858
  session: namedSession.name,
17768
17859
  pid: namedSession.session.pid,
@@ -17790,7 +17881,7 @@ var claudeCodeAgent = {
17790
17881
  CLAUDE_CODE_ENABLE_TELEMETRY: "1"
17791
17882
  }
17792
17883
  },
17793
- configPath: "~/.claude/settings.json",
17884
+ configPath: "~/.claude.json",
17794
17885
  branding: {
17795
17886
  colors: {
17796
17887
  dark: "#C15F3C",
@@ -17805,7 +17896,12 @@ var claudeDesktopAgent = {
17805
17896
  name: "claude-desktop",
17806
17897
  label: "Claude Desktop",
17807
17898
  summary: "Anthropic's official desktop application for Claude",
17808
- configPath: "~/.claude/settings.json",
17899
+ configPath: "~/.config/Claude/claude_desktop_config.json",
17900
+ configPaths: {
17901
+ darwin: "~/Library/Application Support/Claude/claude_desktop_config.json",
17902
+ linux: "~/.config/Claude/claude_desktop_config.json",
17903
+ win32: "~/AppData/Roaming/Claude/claude_desktop_config.json"
17904
+ },
17809
17905
  branding: {
17810
17906
  colors: {
17811
17907
  dark: "#D97757",
@@ -17849,7 +17945,7 @@ var cursorAgent = {
17849
17945
  label: "Cursor",
17850
17946
  summary: "Cursor's CLI coding agent.",
17851
17947
  binaryName: "cursor-agent",
17852
- configPath: "~/.cursor/cli-config.json",
17948
+ configPath: "~/.cursor/mcp.json",
17853
17949
  branding: {
17854
17950
  colors: {
17855
17951
  dark: "#FFFFFF",
@@ -17889,7 +17985,7 @@ var openCodeAgent = {
17889
17985
  OPENCODE_CONFIG_CONTENT: '{"experimental":{"openTelemetry":true}}'
17890
17986
  }
17891
17987
  },
17892
- configPath: "~/.config/opencode/config.json",
17988
+ configPath: "~/.config/opencode/opencode.json",
17893
17989
  branding: {
17894
17990
  colors: {
17895
17991
  dark: "#4A4F55",
@@ -17907,7 +18003,7 @@ var kimiAgent = {
17907
18003
  aliases: ["kimi-cli"],
17908
18004
  binaryName: "kimi",
17909
18005
  apiShapes: ["openai-chat-completions"],
17910
- configPath: "~/.kimi/config.toml",
18006
+ configPath: "~/.kimi/mcp.json",
17911
18007
  branding: {
17912
18008
  colors: {
17913
18009
  dark: "#7B68EE",
@@ -19607,8 +19703,10 @@ var listSessions = defineCommand({
19607
19703
 
19608
19704
  // src/commands/press-key.ts
19609
19705
  var params7 = S.Object({
19610
- key: S.String({ description: "Named key to press" }),
19611
- session: S.Optional(S.String({ short: "s", description: "Session name" }))
19706
+ key: S.String({ description: "Named key to press", pattern: TERMINAL_KEY_PATTERN }),
19707
+ session: S.Optional(
19708
+ S.String({ short: "s", description: "Session name", minLength: 1, pattern: "\\S" })
19709
+ )
19612
19710
  });
19613
19711
  var pressKey = defineCommand({
19614
19712
  name: "press-key",
@@ -19617,16 +19715,36 @@ var pressKey = defineCommand({
19617
19715
  positional: ["key"],
19618
19716
  params: params7,
19619
19717
  handler: async ({ params: params17, env, terminalPilotRuntime }) => {
19620
- const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(params17.session, env);
19718
+ assertTerminalKey(params17.key);
19719
+ const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(
19720
+ params17.session,
19721
+ env
19722
+ );
19621
19723
  await namedSession.session.press(params17.key);
19622
19724
  return void 0;
19623
19725
  }
19624
19726
  });
19727
+ function assertTerminalKey(key2) {
19728
+ try {
19729
+ keyToSequence(key2);
19730
+ } catch (error3) {
19731
+ throw new UserError(error3 instanceof Error ? error3.message : String(error3));
19732
+ }
19733
+ }
19625
19734
 
19626
19735
  // src/commands/read-history.ts
19627
19736
  var params8 = S.Object({
19628
- session: S.Optional(S.String({ short: "s", description: "Session name" })),
19629
- last: S.Optional(S.Number({ short: "n", description: "Return only the last N lines" }))
19737
+ session: S.Optional(
19738
+ S.String({ short: "s", description: "Session name", minLength: 1, pattern: "\\S" })
19739
+ ),
19740
+ last: S.Optional(
19741
+ S.Number({
19742
+ short: "n",
19743
+ description: "Return only the last N lines",
19744
+ jsonType: "integer",
19745
+ minimum: 0
19746
+ })
19747
+ )
19630
19748
  });
19631
19749
  var readHistory = defineCommand({
19632
19750
  name: "read-history",
@@ -19634,7 +19752,10 @@ var readHistory = defineCommand({
19634
19752
  scope: ["cli", "mcp", "sdk"],
19635
19753
  params: params8,
19636
19754
  handler: async ({ params: params17, env, terminalPilotRuntime }) => {
19637
- const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(params17.session, env);
19755
+ const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(
19756
+ params17.session,
19757
+ env
19758
+ );
19638
19759
  const lines = await namedSession.session.history({ last: params17.last });
19639
19760
  return { lines, exitCode: namedSession.session.exitCode };
19640
19761
  }
@@ -19642,7 +19763,9 @@ var readHistory = defineCommand({
19642
19763
 
19643
19764
  // src/commands/read-screen.ts
19644
19765
  var params9 = S.Object({
19645
- session: S.Optional(S.String({ short: "s", description: "Session name" }))
19766
+ session: S.Optional(
19767
+ S.String({ short: "s", description: "Session name", minLength: 1, pattern: "\\S" })
19768
+ )
19646
19769
  });
19647
19770
  var readScreen = defineCommand({
19648
19771
  name: "read-screen",
@@ -19650,7 +19773,10 @@ var readScreen = defineCommand({
19650
19773
  scope: ["cli", "mcp", "sdk"],
19651
19774
  params: params9,
19652
19775
  handler: async ({ params: params17, env, terminalPilotRuntime }) => {
19653
- const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(params17.session, env);
19776
+ const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(
19777
+ params17.session,
19778
+ env
19779
+ );
19654
19780
  const screen = await namedSession.session.screen();
19655
19781
  return {
19656
19782
  lines: [...screen.lines],
@@ -19663,9 +19789,11 @@ var readScreen = defineCommand({
19663
19789
 
19664
19790
  // src/commands/resize.ts
19665
19791
  var params10 = S.Object({
19666
- cols: S.Number({ description: "Terminal width in columns" }),
19667
- rows: S.Number({ description: "Terminal height in rows" }),
19668
- session: S.Optional(S.String({ short: "s", description: "Session name" }))
19792
+ cols: S.Number({ description: "Terminal width in columns", jsonType: "integer", minimum: 1 }),
19793
+ rows: S.Number({ description: "Terminal height in rows", jsonType: "integer", minimum: 1 }),
19794
+ session: S.Optional(
19795
+ S.String({ short: "s", description: "Session name", minLength: 1, pattern: "\\S" })
19796
+ )
19669
19797
  });
19670
19798
  var resize = defineCommand({
19671
19799
  name: "resize",
@@ -19673,7 +19801,10 @@ var resize = defineCommand({
19673
19801
  scope: ["cli", "mcp", "sdk"],
19674
19802
  params: params10,
19675
19803
  handler: async ({ params: params17, env, terminalPilotRuntime }) => {
19676
- const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(params17.session, env);
19804
+ const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(
19805
+ params17.session,
19806
+ env
19807
+ );
19677
19808
  await namedSession.session.resize(params17.cols, params17.rows);
19678
19809
  return void 0;
19679
19810
  }
@@ -19685,6 +19816,9 @@ import { rename as rename4, rm, writeFile as writeFile6 } from "node:fs/promises
19685
19816
 
19686
19817
  // ../terminal-png/src/ansi-parser.ts
19687
19818
  var ESC2 = "\x1B";
19819
+ var TAB_WIDTH = 8;
19820
+ var MAX_TERMINAL_ROWS = 1e3;
19821
+ var MAX_TERMINAL_COLUMNS = 1e3;
19688
19822
  function createDefaultStyle() {
19689
19823
  return {
19690
19824
  fg: null,
@@ -19969,10 +20103,34 @@ function positionParameter(params17, index, fallback) {
19969
20103
  const value = toInteger(params17.split(";")[index]);
19970
20104
  return value === null || value < 1 ? fallback : value;
19971
20105
  }
20106
+ function modeParameter(params17, fallback) {
20107
+ const value = toInteger(params17.split(";")[0]);
20108
+ return value === null ? fallback : value;
20109
+ }
20110
+ function displayWidth3(text4) {
20111
+ if (text4 === " ") {
20112
+ return TAB_WIDTH;
20113
+ }
20114
+ const codePoint = text4.codePointAt(0);
20115
+ if (codePoint === void 0) {
20116
+ return 0;
20117
+ }
20118
+ 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) {
20119
+ return 2;
20120
+ }
20121
+ return 1;
20122
+ }
20123
+ function hasRenderableCell(line) {
20124
+ return (line ?? []).some((cell) => cell !== void 0 && cell.text.length > 0);
20125
+ }
19972
20126
  function buildRuns(lines, lineBreakStyles) {
19973
20127
  const runs = [];
19974
20128
  const defaultStyle = createDefaultStyle();
19975
- for (let row = 0; row < lines.length; row += 1) {
20129
+ let lastRow = lines.length - 1;
20130
+ while (lastRow > 0 && !hasRenderableCell(lines[lastRow]) && lineBreakStyles[lastRow - 1] === void 0) {
20131
+ lastRow -= 1;
20132
+ }
20133
+ for (let row = 0; row <= lastRow; row += 1) {
19976
20134
  const line = lines[row] ?? [];
19977
20135
  let lastCell = line.length - 1;
19978
20136
  while (lastCell >= 0 && line[lastCell] === void 0) {
@@ -19982,7 +20140,7 @@ function buildRuns(lines, lineBreakStyles) {
19982
20140
  const cell = line[column] ?? { text: " ", style: defaultStyle };
19983
20141
  pushRun(runs, cell.style, cell.text);
19984
20142
  }
19985
- if (row < lines.length - 1) {
20143
+ if (row < lastRow) {
19986
20144
  pushRun(runs, lineBreakStyles[row] ?? defaultStyle, "\n");
19987
20145
  }
19988
20146
  }
@@ -19994,7 +20152,21 @@ function parseAnsi2(input) {
19994
20152
  let style = createDefaultStyle();
19995
20153
  let row = 0;
19996
20154
  let column = 0;
20155
+ let savedRow = 0;
20156
+ let savedColumn = 0;
19997
20157
  let index = 0;
20158
+ const clampRow = (nextRow) => {
20159
+ if (nextRow < 0) {
20160
+ return 0;
20161
+ }
20162
+ return Math.min(nextRow, MAX_TERMINAL_ROWS - 1);
20163
+ };
20164
+ const clampColumn = (nextColumn) => {
20165
+ if (nextColumn < 0) {
20166
+ return 0;
20167
+ }
20168
+ return Math.min(nextColumn, MAX_TERMINAL_COLUMNS - 1);
20169
+ };
19998
20170
  const ensureLine = () => {
19999
20171
  while (lines.length <= row) {
20000
20172
  lines.push([]);
@@ -20002,12 +20174,64 @@ function parseAnsi2(input) {
20002
20174
  };
20003
20175
  const moveDown = (keepColumn) => {
20004
20176
  lineBreakStyles[row] = cloneStyle(style);
20005
- row += 1;
20177
+ row = clampRow(row + 1);
20006
20178
  if (!keepColumn) {
20007
20179
  column = 0;
20008
20180
  }
20009
20181
  ensureLine();
20010
20182
  };
20183
+ const eraseLine = (mode) => {
20184
+ const line = lines[row] ?? [];
20185
+ if (mode === 1) {
20186
+ for (let cell = 0; cell <= column; cell += 1) {
20187
+ delete line[cell];
20188
+ }
20189
+ return;
20190
+ }
20191
+ if (mode === 2) {
20192
+ lines[row] = [];
20193
+ return;
20194
+ }
20195
+ line.splice(column);
20196
+ };
20197
+ const eraseDisplay = (mode) => {
20198
+ if (mode === 1) {
20199
+ for (let lineRow = 0; lineRow < row; lineRow += 1) {
20200
+ lines[lineRow] = [];
20201
+ }
20202
+ eraseLine(1);
20203
+ return;
20204
+ }
20205
+ if (mode === 2 || mode === 3) {
20206
+ lines.length = 0;
20207
+ lineBreakStyles.length = 0;
20208
+ ensureLine();
20209
+ return;
20210
+ }
20211
+ eraseLine(0);
20212
+ lines.splice(row + 1);
20213
+ lineBreakStyles.splice(row);
20214
+ };
20215
+ const saveCursor = () => {
20216
+ savedRow = row;
20217
+ savedColumn = column;
20218
+ };
20219
+ const restoreCursor = () => {
20220
+ row = clampRow(savedRow);
20221
+ column = clampColumn(savedColumn);
20222
+ ensureLine();
20223
+ };
20224
+ const writeText = (text4) => {
20225
+ const width = displayWidth3(text4);
20226
+ if (width === 0) {
20227
+ return;
20228
+ }
20229
+ lines[row][column] = { text: text4, style: cloneStyle(style) };
20230
+ for (let offset = 1; offset < width && column + offset < MAX_TERMINAL_COLUMNS; offset += 1) {
20231
+ lines[row][column + offset] = { text: "", style: cloneStyle(style) };
20232
+ }
20233
+ column = clampColumn(column + width);
20234
+ };
20011
20235
  while (index < input.length) {
20012
20236
  const char = input[index];
20013
20237
  if (char === "\n") {
@@ -20030,38 +20254,73 @@ function parseAnsi2(input) {
20030
20254
  index += 1;
20031
20255
  continue;
20032
20256
  }
20257
+ if (char === " ") {
20258
+ const nextTabStop = Math.min(
20259
+ Math.floor(column / TAB_WIDTH) * TAB_WIDTH + TAB_WIDTH,
20260
+ MAX_TERMINAL_COLUMNS
20261
+ );
20262
+ while (column < nextTabStop) {
20263
+ writeText(" ");
20264
+ }
20265
+ index += 1;
20266
+ continue;
20267
+ }
20033
20268
  if (char === ESC2 && input[index + 1] === "]") {
20034
20269
  index = parseOscEnd(input, index);
20035
20270
  continue;
20036
20271
  }
20272
+ if (char === ESC2 && input[index + 1] === "7") {
20273
+ saveCursor();
20274
+ index += 2;
20275
+ continue;
20276
+ }
20277
+ if (char === ESC2 && input[index + 1] === "8") {
20278
+ restoreCursor();
20279
+ index += 2;
20280
+ continue;
20281
+ }
20037
20282
  const csiPrefixLength = char === "\x9B" ? 1 : char === ESC2 && input[index + 1] === "[" ? 2 : null;
20038
20283
  if (csiPrefixLength !== null) {
20039
20284
  const sequence = parseCsi(input, index, csiPrefixLength);
20040
20285
  if (sequence.final === "m") {
20041
20286
  style = applySgr(style, sequence.params);
20042
20287
  } else if (sequence.final === "G") {
20043
- column = positionParameter(sequence.params, 0, 1) - 1;
20288
+ column = clampColumn(positionParameter(sequence.params, 0, 1) - 1);
20044
20289
  } else if (sequence.final === "C") {
20045
- column += positionParameter(sequence.params, 0, 1);
20290
+ column = clampColumn(column + positionParameter(sequence.params, 0, 1));
20046
20291
  } else if (sequence.final === "D") {
20047
20292
  column = Math.max(0, column - positionParameter(sequence.params, 0, 1));
20048
20293
  } else if (sequence.final === "A") {
20049
- row = Math.max(0, row - positionParameter(sequence.params, 0, 1));
20294
+ row = clampRow(row - positionParameter(sequence.params, 0, 1));
20050
20295
  } else if (sequence.final === "B") {
20051
- row += positionParameter(sequence.params, 0, 1);
20296
+ row = clampRow(row + positionParameter(sequence.params, 0, 1));
20297
+ ensureLine();
20298
+ } else if (sequence.final === "E") {
20299
+ row = clampRow(row + positionParameter(sequence.params, 0, 1));
20300
+ column = 0;
20052
20301
  ensureLine();
20302
+ } else if (sequence.final === "F") {
20303
+ row = clampRow(row - positionParameter(sequence.params, 0, 1));
20304
+ column = 0;
20053
20305
  } else if (sequence.final === "H" || sequence.final === "f") {
20054
- row = positionParameter(sequence.params, 0, 1) - 1;
20055
- column = positionParameter(sequence.params, 1, 1) - 1;
20306
+ row = clampRow(positionParameter(sequence.params, 0, 1) - 1);
20307
+ column = clampColumn(positionParameter(sequence.params, 1, 1) - 1);
20056
20308
  ensureLine();
20309
+ } else if (sequence.final === "K") {
20310
+ eraseLine(modeParameter(sequence.params, 0));
20311
+ } else if (sequence.final === "J") {
20312
+ eraseDisplay(modeParameter(sequence.params, 0));
20313
+ } else if (sequence.final === "s") {
20314
+ saveCursor();
20315
+ } else if (sequence.final === "u") {
20316
+ restoreCursor();
20057
20317
  }
20058
20318
  index = sequence.end;
20059
20319
  continue;
20060
20320
  }
20061
20321
  const codePoint = input.codePointAt(index);
20062
20322
  const text4 = codePoint === void 0 ? "" : String.fromCodePoint(codePoint);
20063
- lines[row][column] = { text: text4, style: cloneStyle(style) };
20064
- column += 1;
20323
+ writeText(text4);
20065
20324
  index += text4.length;
20066
20325
  }
20067
20326
  return buildRuns(lines, lineBreakStyles);
@@ -20469,11 +20728,11 @@ function splitIntoLines(runs) {
20469
20728
  }
20470
20729
  function measureLines(lines) {
20471
20730
  return Math.max(
20472
- ...lines.map((line) => displayWidth3(line.map((run) => run.text).join("")) * CHARACTER_WIDTH),
20731
+ ...lines.map((line) => displayWidth4(line.map((run) => run.text).join("")) * CHARACTER_WIDTH),
20473
20732
  0
20474
20733
  );
20475
20734
  }
20476
- function displayWidth3(text4, startColumn = 0) {
20735
+ function displayWidth4(text4, startColumn = 0) {
20477
20736
  const segmenter = new Intl.Segmenter();
20478
20737
  let column = startColumn;
20479
20738
  for (const { segment } of segmenter.segment(text4)) {
@@ -20535,7 +20794,7 @@ function renderBackgrounds(line, startX, y, height) {
20535
20794
  let column = 0;
20536
20795
  const rectangles = [];
20537
20796
  for (const run of line) {
20538
- const width = displayWidth3(run.text, column);
20797
+ const width = displayWidth4(run.text, column);
20539
20798
  const background = resolveBackgroundColor(run);
20540
20799
  if (background !== BACKGROUND && width > 0) {
20541
20800
  rectangles.push(`<rect x="${formatNumber(startX + column * CHARACTER_WIDTH)}" y="${formatNumber(y)}" width="${formatNumber(width * CHARACTER_WIDTH)}" height="${formatNumber(height)}" fill="${escapeXmlAttribute(background)}" />`);
@@ -20569,7 +20828,7 @@ function renderRun(run) {
20569
20828
  if (run.dim) {
20570
20829
  attributes.push('opacity="0.7"');
20571
20830
  }
20572
- const text4 = run.conceal ? " ".repeat(displayWidth3(run.text)) : run.text;
20831
+ const text4 = run.conceal ? " ".repeat(displayWidth4(run.text)) : run.text;
20573
20832
  return `<tspan ${attributes.join(" ")}>${escapeXmlText(text4)}</tspan>`;
20574
20833
  }
20575
20834
  function renderWindowControls() {
@@ -20618,13 +20877,16 @@ async function renderTerminalPng(ansiText, options = {}) {
20618
20877
  if (options.padding !== void 0 && (!Number.isInteger(options.padding) || options.padding < 0)) {
20619
20878
  throw new Error("Padding must be a non-negative integer.");
20620
20879
  }
20880
+ if (options.output !== void 0 && options.output.length === 0) {
20881
+ throw new Error("Output path must not be empty.");
20882
+ }
20621
20883
  const runs = parseAnsi2(ansiText);
20622
20884
  const svg = renderSvg(runs, {
20623
20885
  padding: options.padding,
20624
20886
  window: options.window
20625
20887
  });
20626
20888
  const png = renderPng(svg);
20627
- if (options.output) {
20889
+ if (options.output !== void 0) {
20628
20890
  const temporaryPath = `${options.output}.${randomUUID10()}.tmp`;
20629
20891
  let temporaryCreated = false;
20630
20892
  try {
@@ -20650,10 +20912,19 @@ function isAlreadyExistsError3(error3) {
20650
20912
 
20651
20913
  // src/commands/screenshot.ts
20652
20914
  var params11 = S.Object({
20653
- session: S.Optional(S.String({ short: "s", description: "Session name" })),
20915
+ session: S.Optional(
20916
+ S.String({ short: "s", description: "Session name", minLength: 1, pattern: "\\S" })
20917
+ ),
20654
20918
  output: S.String({ short: "o", description: "Path to the output PNG file" }),
20655
20919
  window: S.Optional(S.Boolean({ description: "Include terminal window chrome", default: true })),
20656
- padding: S.Optional(S.Number({ short: "p", description: "Padding around terminal content" }))
20920
+ padding: S.Optional(
20921
+ S.Number({
20922
+ short: "p",
20923
+ description: "Padding around terminal content",
20924
+ jsonType: "integer",
20925
+ minimum: 0
20926
+ })
20927
+ )
20657
20928
  });
20658
20929
  var screenshot = defineCommand({
20659
20930
  name: "screenshot",
@@ -20661,7 +20932,10 @@ var screenshot = defineCommand({
20661
20932
  scope: ["cli"],
20662
20933
  params: params11,
20663
20934
  handler: async ({ params: params17, env, terminalPilotRuntime }) => {
20664
- const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(params17.session, env);
20935
+ const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(
20936
+ params17.session,
20937
+ env
20938
+ );
20665
20939
  const screen = await namedSession.session.screen();
20666
20940
  await renderTerminalPng(screen.rawLines.join("\n"), {
20667
20941
  output: params17.output,
@@ -20675,7 +20949,9 @@ var screenshot = defineCommand({
20675
20949
  // src/commands/send-signal.ts
20676
20950
  var params12 = S.Object({
20677
20951
  signal: S.String({ description: "Signal to send to the session process" }),
20678
- session: S.Optional(S.String({ short: "s", description: "Session name" }))
20952
+ session: S.Optional(
20953
+ S.String({ short: "s", description: "Session name", minLength: 1, pattern: "\\S" })
20954
+ )
20679
20955
  });
20680
20956
  var sendSignal = defineCommand({
20681
20957
  name: "send-signal",
@@ -20684,7 +20960,10 @@ var sendSignal = defineCommand({
20684
20960
  positional: ["signal"],
20685
20961
  params: params12,
20686
20962
  handler: async ({ params: params17, env, terminalPilotRuntime }) => {
20687
- const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(params17.session, env);
20963
+ const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(
20964
+ params17.session,
20965
+ env
20966
+ );
20688
20967
  await namedSession.session.signal(params17.signal);
20689
20968
  return void 0;
20690
20969
  }
@@ -20693,7 +20972,9 @@ var sendSignal = defineCommand({
20693
20972
  // src/commands/type.ts
20694
20973
  var params13 = S.Object({
20695
20974
  text: S.String({ description: "Text to write to the session" }),
20696
- session: S.Optional(S.String({ short: "s", description: "Session name" }))
20975
+ session: S.Optional(
20976
+ S.String({ short: "s", description: "Session name", minLength: 1, pattern: "\\S" })
20977
+ )
20697
20978
  });
20698
20979
  var type = defineCommand({
20699
20980
  name: "type",
@@ -20702,7 +20983,10 @@ var type = defineCommand({
20702
20983
  positional: ["text"],
20703
20984
  params: params13,
20704
20985
  handler: async ({ params: params17, env, terminalPilotRuntime }) => {
20705
- const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(params17.session, env);
20986
+ const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(
20987
+ params17.session,
20988
+ env
20989
+ );
20706
20990
  await namedSession.session.type(params17.text);
20707
20991
  return void 0;
20708
20992
  }
@@ -20780,9 +21064,17 @@ async function folderExists(fs4, folderPath) {
20780
21064
 
20781
21065
  // src/commands/wait-for.ts
20782
21066
  var params15 = S.Object({
20783
- pattern: S.String({ description: "Regular expression pattern to wait for" }),
20784
- session: S.Optional(S.String({ short: "s", description: "Session name" })),
20785
- timeout: S.Optional(S.Number({ short: "t", description: "Maximum wait time in milliseconds" })),
21067
+ pattern: S.String({
21068
+ description: "Regular expression pattern to wait for",
21069
+ minLength: 1,
21070
+ pattern: "\\S"
21071
+ }),
21072
+ session: S.Optional(
21073
+ S.String({ short: "s", description: "Session name", minLength: 1, pattern: "\\S" })
21074
+ ),
21075
+ timeout: S.Optional(
21076
+ S.Number({ short: "t", description: "Maximum wait time in milliseconds", minimum: 0 })
21077
+ ),
20786
21078
  literal: S.Optional(
20787
21079
  S.Boolean({
20788
21080
  short: "l",
@@ -20797,17 +21089,33 @@ var waitFor = defineCommand({
20797
21089
  positional: ["pattern"],
20798
21090
  params: params15,
20799
21091
  handler: async ({ params: params17, env, terminalPilotRuntime }) => {
20800
- const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(params17.session, env);
21092
+ if (params17.pattern.trim().length === 0) {
21093
+ throw new UserError("Wait pattern must not be empty.");
21094
+ }
21095
+ assertTimeout2(params17.timeout);
21096
+ const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(
21097
+ params17.session,
21098
+ env
21099
+ );
20801
21100
  const pattern = params17.literal === true ? params17.pattern : new RegExp(params17.pattern);
20802
21101
  const line = params17.timeout === void 0 ? await namedSession.session.waitFor(pattern) : await namedSession.session.waitFor(pattern, { timeout: params17.timeout });
20803
21102
  return { matched: true, line };
20804
21103
  }
20805
21104
  });
21105
+ function assertTimeout2(timeout) {
21106
+ if (timeout !== void 0 && (!Number.isFinite(timeout) || timeout < 0)) {
21107
+ throw new UserError("Timeout must be a finite non-negative number.");
21108
+ }
21109
+ }
20806
21110
 
20807
21111
  // src/commands/wait-for-exit.ts
20808
21112
  var params16 = S.Object({
20809
- session: S.Optional(S.String({ short: "s", description: "Session name" })),
20810
- timeout: S.Optional(S.Number({ short: "t", description: "Maximum wait time in milliseconds" }))
21113
+ session: S.Optional(
21114
+ S.String({ short: "s", description: "Session name", minLength: 1, pattern: "\\S" })
21115
+ ),
21116
+ timeout: S.Optional(
21117
+ S.Number({ short: "t", description: "Maximum wait time in milliseconds", minimum: 0 })
21118
+ )
20811
21119
  });
20812
21120
  var waitForExit2 = defineCommand({
20813
21121
  name: "wait-for-exit",
@@ -20815,7 +21123,13 @@ var waitForExit2 = defineCommand({
20815
21123
  scope: ["cli", "mcp", "sdk"],
20816
21124
  params: params16,
20817
21125
  handler: async ({ params: params17, env, terminalPilotRuntime }) => {
20818
- const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(params17.session, env);
21126
+ if (params17.timeout !== void 0 && (!Number.isFinite(params17.timeout) || params17.timeout < 0)) {
21127
+ throw new UserError("Timeout must be a finite non-negative number.");
21128
+ }
21129
+ const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(
21130
+ params17.session,
21131
+ env
21132
+ );
20819
21133
  const exitCode = await namedSession.session.waitForExit(
20820
21134
  params17.timeout === void 0 ? void 0 : { timeout: params17.timeout }
20821
21135
  );