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
@@ -12581,10 +12581,15 @@ async function writeErrorReport(context) {
12581
12581
 
12582
12582
  // ../toolcraft/src/number-schema.ts
12583
12583
  function isValidNumberSchemaValue(value, schema) {
12584
- return typeof value === "number" && Number.isFinite(value) && (schema.jsonType !== "integer" || Number.isInteger(value));
12584
+ 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);
12585
12585
  }
12586
12586
  function getExpectedNumberDescription(schema) {
12587
- return schema.jsonType === "integer" ? "an integer" : "a number";
12587
+ const type2 = schema.jsonType === "integer" ? "an integer" : "a number";
12588
+ const bounds = [
12589
+ schema.minimum === void 0 ? void 0 : `greater than or equal to ${schema.minimum}`,
12590
+ schema.maximum === void 0 ? void 0 : `less than or equal to ${schema.maximum}`
12591
+ ].filter((bound) => bound !== void 0);
12592
+ return bounds.length === 0 ? type2 : `${type2} ${bounds.join(" and ")}`;
12588
12593
  }
12589
12594
 
12590
12595
  // ../toolcraft/src/renderer.ts
@@ -16481,6 +16486,10 @@ var TerminalBuffer = class {
16481
16486
  }
16482
16487
  _writePrintable(ch) {
16483
16488
  const width = this._cellWidth(ch);
16489
+ if (width === 0) {
16490
+ this._appendCombiningMark(ch);
16491
+ return;
16492
+ }
16484
16493
  if (this._autoWrap && this._pendingWrap) {
16485
16494
  this._cursorX = 0;
16486
16495
  this._newline();
@@ -16515,11 +16524,40 @@ var TerminalBuffer = class {
16515
16524
  _cellWidth(ch) {
16516
16525
  const codePoint = ch.codePointAt(0);
16517
16526
  if (codePoint === void 0) return 0;
16527
+ if (isCombiningCodePoint2(codePoint)) {
16528
+ return 0;
16529
+ }
16518
16530
  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) {
16519
16531
  return Math.min(2, this._cols);
16520
16532
  }
16521
16533
  return 1;
16522
16534
  }
16535
+ _appendCombiningMark(ch) {
16536
+ const target = this._findCombiningTarget();
16537
+ if (target === null) {
16538
+ return;
16539
+ }
16540
+ const cell = this._screen[target.y]?.[target.x];
16541
+ if (cell === null || cell === void 0) {
16542
+ return;
16543
+ }
16544
+ cell[1] += ch;
16545
+ }
16546
+ _findCombiningTarget() {
16547
+ const startX = this._pendingWrap ? this._cursorX : this._cursorX - 1;
16548
+ for (let y = this._cursorY; y >= 0; y -= 1) {
16549
+ const row = this._screen[y];
16550
+ if (row === void 0) {
16551
+ continue;
16552
+ }
16553
+ for (let x = y === this._cursorY ? startX : this._cols - 1; x >= 0; x -= 1) {
16554
+ if (row[x] !== null) {
16555
+ return { x, y };
16556
+ }
16557
+ }
16558
+ }
16559
+ return null;
16560
+ }
16523
16561
  _setChar(y, x, ch) {
16524
16562
  const row = this._screen[y];
16525
16563
  if (row && x >= 0 && x < this._cols) {
@@ -16660,7 +16698,8 @@ var TerminalBuffer = class {
16660
16698
  case "J":
16661
16699
  if (p0 === 0) {
16662
16700
  this._eraseLine(this._cursorY, this._cursorX, this._cols - 1);
16663
- for (let y = this._cursorY + 1; y < this._rows; y++) this._eraseLine(y, 0, this._cols - 1);
16701
+ for (let y = this._cursorY + 1; y < this._rows; y++)
16702
+ this._eraseLine(y, 0, this._cols - 1);
16664
16703
  } else if (p0 === 1) {
16665
16704
  for (let y = 0; y < this._cursorY; y++) this._eraseLine(y, 0, this._cols - 1);
16666
16705
  this._eraseLine(this._cursorY, 0, this._cursorX);
@@ -17025,6 +17064,9 @@ function createDefaultStyleState() {
17025
17064
  strikethrough: false
17026
17065
  };
17027
17066
  }
17067
+ function isCombiningCodePoint2(codePoint) {
17068
+ return codePoint >= 768 && codePoint <= 879 || codePoint >= 6832 && codePoint <= 6911 || codePoint >= 7616 && codePoint <= 7679 || codePoint >= 8400 && codePoint <= 8447 || codePoint >= 65056 && codePoint <= 65071;
17069
+ }
17028
17070
  function serializeStyleState(state) {
17029
17071
  const codes = [];
17030
17072
  if (state.bold) {
@@ -17078,6 +17120,8 @@ var NAMED_KEY_LOWER = new Map(
17078
17120
  Object.entries(NAMED_KEY_SEQUENCES).map(([k, v]) => [k.toLowerCase(), v])
17079
17121
  );
17080
17122
  var VALID_KEYS_HINT = `Valid keys: ${Object.keys(NAMED_KEY_SEQUENCES).join(", ")}, Control+<letter>, Alt+<key>`;
17123
+ var NAMED_KEY_PATTERN = Object.keys(NAMED_KEY_SEQUENCES).map(caseInsensitivePattern).join("|");
17124
+ var TERMINAL_KEY_PATTERN = `^(?:${NAMED_KEY_PATTERN}|.|[Cc][Oo][Nn][Tt][Rr][Oo][Ll]\\+[A-Za-z]|[Aa][Ll][Tt]\\+.+)$`;
17081
17125
  function unknownKeyError(key2) {
17082
17126
  return new Error(`Unknown terminal key: ${key2}. ${VALID_KEYS_HINT}`);
17083
17127
  }
@@ -17120,6 +17164,18 @@ function controlKeyToSequence(controlKey) {
17120
17164
  }
17121
17165
  return String.fromCharCode(charCode - 64);
17122
17166
  }
17167
+ function caseInsensitivePattern(value) {
17168
+ let pattern = "";
17169
+ for (const character of value) {
17170
+ const lower = character.toLowerCase();
17171
+ const upper = character.toUpperCase();
17172
+ pattern += lower === upper ? escapePatternCharacter(character) : `[${upper}${lower}]`;
17173
+ }
17174
+ return pattern;
17175
+ }
17176
+ function escapePatternCharacter(character) {
17177
+ return character.replace(/[\\^$.*+?()[\]{}|]/g, "\\$&");
17178
+ }
17123
17179
 
17124
17180
  // src/terminal-screen.ts
17125
17181
  var TerminalScreen = class {
@@ -17559,7 +17615,11 @@ function createTerminalPilotRuntime(options = {}) {
17559
17615
  const pendingNames = /* @__PURE__ */ new Set();
17560
17616
  let pilotPromise;
17561
17617
  function getRequestedName(name, env) {
17562
- return name ?? env?.get(SESSION_ENV_VAR);
17618
+ const requestedName = name ?? env?.get(SESSION_ENV_VAR);
17619
+ if (requestedName !== void 0 && requestedName.trim().length === 0) {
17620
+ throw new UserError("Session name must not be empty.");
17621
+ }
17622
+ return requestedName;
17563
17623
  }
17564
17624
  async function getPilot() {
17565
17625
  pilotPromise ??= launchPilot();
@@ -17595,7 +17655,9 @@ function createTerminalPilotRuntime(options = {}) {
17595
17655
  const sessionId = nameToId.get(name);
17596
17656
  if (sessionId === void 0) {
17597
17657
  const active = await listSessions2();
17598
- throw new UserError(`Session "${name}" was not found. ${formatAvailableSessions(active.map((entry) => entry.name))}`);
17658
+ throw new UserError(
17659
+ `Session "${name}" was not found. ${formatAvailableSessions(active.map((entry) => entry.name))}`
17660
+ );
17599
17661
  }
17600
17662
  const pilot = await getPilot();
17601
17663
  try {
@@ -17603,7 +17665,9 @@ function createTerminalPilotRuntime(options = {}) {
17603
17665
  } catch {
17604
17666
  forgetSession(name, sessionId);
17605
17667
  const active = await listSessions2();
17606
- throw new UserError(`Session "${name}" was not found. ${formatAvailableSessions(active.map((entry) => entry.name))}`);
17668
+ throw new UserError(
17669
+ `Session "${name}" was not found. ${formatAvailableSessions(active.map((entry) => entry.name))}`
17670
+ );
17607
17671
  }
17608
17672
  }
17609
17673
  async function listSessions2() {
@@ -17634,6 +17698,9 @@ function createTerminalPilotRuntime(options = {}) {
17634
17698
  }
17635
17699
  return {
17636
17700
  async createSession(params17, env) {
17701
+ if (params17.command.trim().length === 0) {
17702
+ throw new UserError("Command must not be empty.");
17703
+ }
17637
17704
  const requestedName = getRequestedName(params17.session, env) ?? nextSessionName();
17638
17705
  await discardExitedSessionName(requestedName);
17639
17706
  if (nameToId.has(requestedName) || pendingNames.has(requestedName)) {
@@ -17706,7 +17773,9 @@ async function closeSharedTerminalPilotRuntime() {
17706
17773
 
17707
17774
  // src/commands/close-session.ts
17708
17775
  var params = S.Object({
17709
- session: S.Optional(S.String({ short: "s", description: "Session name" }))
17776
+ session: S.Optional(
17777
+ S.String({ short: "s", description: "Session name", minLength: 1, pattern: "\\S" })
17778
+ )
17710
17779
  });
17711
17780
  var closeSession = defineCommand({
17712
17781
  name: "close-session",
@@ -17714,19 +17783,28 @@ var closeSession = defineCommand({
17714
17783
  scope: ["cli", "mcp", "sdk"],
17715
17784
  params,
17716
17785
  handler: async ({ params: params17, env, terminalPilotRuntime }) => {
17717
- const { exitCode } = await getTerminalPilotRuntime(terminalPilotRuntime).closeSession(params17.session, env);
17786
+ const { exitCode } = await getTerminalPilotRuntime(terminalPilotRuntime).closeSession(
17787
+ params17.session,
17788
+ env
17789
+ );
17718
17790
  return { exitCode };
17719
17791
  }
17720
17792
  });
17721
17793
 
17722
17794
  // src/commands/create-session.ts
17723
17795
  var params2 = S.Object({
17724
- command: S.String({ description: "Command to execute" }),
17796
+ command: S.String({ description: "Command to execute", minLength: 1, pattern: "\\S" }),
17725
17797
  args: S.Optional(S.Array(S.String(), { description: "Command arguments" })),
17726
- session: S.Optional(S.String({ short: "s", description: "Session name" })),
17798
+ session: S.Optional(
17799
+ S.String({ short: "s", description: "Session name", minLength: 1, pattern: "\\S" })
17800
+ ),
17727
17801
  cwd: S.Optional(S.String({ description: "Working directory" })),
17728
- cols: S.Optional(S.Number({ description: "Terminal width in columns" })),
17729
- rows: S.Optional(S.Number({ description: "Terminal height in rows" })),
17802
+ cols: S.Optional(
17803
+ S.Number({ description: "Terminal width in columns", jsonType: "integer", minimum: 1 })
17804
+ ),
17805
+ rows: S.Optional(
17806
+ S.Number({ description: "Terminal height in rows", jsonType: "integer", minimum: 1 })
17807
+ ),
17730
17808
  observe: S.Optional(S.Boolean({ description: "Mirror PTY output to stderr" }))
17731
17809
  });
17732
17810
  var createSession = defineCommand({
@@ -17736,7 +17814,10 @@ var createSession = defineCommand({
17736
17814
  positional: ["command", "args"],
17737
17815
  params: params2,
17738
17816
  handler: async ({ params: params17, env, terminalPilotRuntime }) => {
17739
- const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).createSession(params17, env);
17817
+ const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).createSession(
17818
+ params17,
17819
+ env
17820
+ );
17740
17821
  return { session: namedSession.name, pid: namedSession.session.pid };
17741
17822
  }
17742
17823
  });
@@ -17744,7 +17825,9 @@ var createSession = defineCommand({
17744
17825
  // src/commands/fill.ts
17745
17826
  var params3 = S.Object({
17746
17827
  text: S.String({ description: "Text to write to the session" }),
17747
- session: S.Optional(S.String({ short: "s", description: "Session name" }))
17828
+ session: S.Optional(
17829
+ S.String({ short: "s", description: "Session name", minLength: 1, pattern: "\\S" })
17830
+ )
17748
17831
  });
17749
17832
  var fill = defineCommand({
17750
17833
  name: "fill",
@@ -17753,7 +17836,10 @@ var fill = defineCommand({
17753
17836
  positional: ["text"],
17754
17837
  params: params3,
17755
17838
  handler: async ({ params: params17, env, terminalPilotRuntime }) => {
17756
- const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(params17.session, env);
17839
+ const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(
17840
+ params17.session,
17841
+ env
17842
+ );
17757
17843
  await namedSession.session.fill(params17.text);
17758
17844
  return void 0;
17759
17845
  }
@@ -17761,7 +17847,9 @@ var fill = defineCommand({
17761
17847
 
17762
17848
  // src/commands/get-session.ts
17763
17849
  var params4 = S.Object({
17764
- session: S.Optional(S.String({ short: "s", description: "Session name" }))
17850
+ session: S.Optional(
17851
+ S.String({ short: "s", description: "Session name", minLength: 1, pattern: "\\S" })
17852
+ )
17765
17853
  });
17766
17854
  var getSession = defineCommand({
17767
17855
  name: "get-session",
@@ -17769,7 +17857,10 @@ var getSession = defineCommand({
17769
17857
  scope: ["cli", "mcp", "sdk"],
17770
17858
  params: params4,
17771
17859
  handler: async ({ params: params17, env, terminalPilotRuntime }) => {
17772
- const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(params17.session, env);
17860
+ const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(
17861
+ params17.session,
17862
+ env
17863
+ );
17773
17864
  return {
17774
17865
  session: namedSession.name,
17775
17866
  pid: namedSession.session.pid,
@@ -17797,7 +17888,7 @@ var claudeCodeAgent = {
17797
17888
  CLAUDE_CODE_ENABLE_TELEMETRY: "1"
17798
17889
  }
17799
17890
  },
17800
- configPath: "~/.claude/settings.json",
17891
+ configPath: "~/.claude.json",
17801
17892
  branding: {
17802
17893
  colors: {
17803
17894
  dark: "#C15F3C",
@@ -17812,7 +17903,12 @@ var claudeDesktopAgent = {
17812
17903
  name: "claude-desktop",
17813
17904
  label: "Claude Desktop",
17814
17905
  summary: "Anthropic's official desktop application for Claude",
17815
- configPath: "~/.claude/settings.json",
17906
+ configPath: "~/.config/Claude/claude_desktop_config.json",
17907
+ configPaths: {
17908
+ darwin: "~/Library/Application Support/Claude/claude_desktop_config.json",
17909
+ linux: "~/.config/Claude/claude_desktop_config.json",
17910
+ win32: "~/AppData/Roaming/Claude/claude_desktop_config.json"
17911
+ },
17816
17912
  branding: {
17817
17913
  colors: {
17818
17914
  dark: "#D97757",
@@ -17856,7 +17952,7 @@ var cursorAgent = {
17856
17952
  label: "Cursor",
17857
17953
  summary: "Cursor's CLI coding agent.",
17858
17954
  binaryName: "cursor-agent",
17859
- configPath: "~/.cursor/cli-config.json",
17955
+ configPath: "~/.cursor/mcp.json",
17860
17956
  branding: {
17861
17957
  colors: {
17862
17958
  dark: "#FFFFFF",
@@ -17896,7 +17992,7 @@ var openCodeAgent = {
17896
17992
  OPENCODE_CONFIG_CONTENT: '{"experimental":{"openTelemetry":true}}'
17897
17993
  }
17898
17994
  },
17899
- configPath: "~/.config/opencode/config.json",
17995
+ configPath: "~/.config/opencode/opencode.json",
17900
17996
  branding: {
17901
17997
  colors: {
17902
17998
  dark: "#4A4F55",
@@ -17914,7 +18010,7 @@ var kimiAgent = {
17914
18010
  aliases: ["kimi-cli"],
17915
18011
  binaryName: "kimi",
17916
18012
  apiShapes: ["openai-chat-completions"],
17917
- configPath: "~/.kimi/config.toml",
18013
+ configPath: "~/.kimi/mcp.json",
17918
18014
  branding: {
17919
18015
  colors: {
17920
18016
  dark: "#7B68EE",
@@ -19614,8 +19710,10 @@ var listSessions = defineCommand({
19614
19710
 
19615
19711
  // src/commands/press-key.ts
19616
19712
  var params7 = S.Object({
19617
- key: S.String({ description: "Named key to press" }),
19618
- session: S.Optional(S.String({ short: "s", description: "Session name" }))
19713
+ key: S.String({ description: "Named key to press", pattern: TERMINAL_KEY_PATTERN }),
19714
+ session: S.Optional(
19715
+ S.String({ short: "s", description: "Session name", minLength: 1, pattern: "\\S" })
19716
+ )
19619
19717
  });
19620
19718
  var pressKey = defineCommand({
19621
19719
  name: "press-key",
@@ -19624,16 +19722,36 @@ var pressKey = defineCommand({
19624
19722
  positional: ["key"],
19625
19723
  params: params7,
19626
19724
  handler: async ({ params: params17, env, terminalPilotRuntime }) => {
19627
- const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(params17.session, env);
19725
+ assertTerminalKey(params17.key);
19726
+ const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(
19727
+ params17.session,
19728
+ env
19729
+ );
19628
19730
  await namedSession.session.press(params17.key);
19629
19731
  return void 0;
19630
19732
  }
19631
19733
  });
19734
+ function assertTerminalKey(key2) {
19735
+ try {
19736
+ keyToSequence(key2);
19737
+ } catch (error3) {
19738
+ throw new UserError(error3 instanceof Error ? error3.message : String(error3));
19739
+ }
19740
+ }
19632
19741
 
19633
19742
  // src/commands/read-history.ts
19634
19743
  var params8 = S.Object({
19635
- session: S.Optional(S.String({ short: "s", description: "Session name" })),
19636
- last: S.Optional(S.Number({ short: "n", description: "Return only the last N lines" }))
19744
+ session: S.Optional(
19745
+ S.String({ short: "s", description: "Session name", minLength: 1, pattern: "\\S" })
19746
+ ),
19747
+ last: S.Optional(
19748
+ S.Number({
19749
+ short: "n",
19750
+ description: "Return only the last N lines",
19751
+ jsonType: "integer",
19752
+ minimum: 0
19753
+ })
19754
+ )
19637
19755
  });
19638
19756
  var readHistory = defineCommand({
19639
19757
  name: "read-history",
@@ -19641,7 +19759,10 @@ var readHistory = defineCommand({
19641
19759
  scope: ["cli", "mcp", "sdk"],
19642
19760
  params: params8,
19643
19761
  handler: async ({ params: params17, env, terminalPilotRuntime }) => {
19644
- const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(params17.session, env);
19762
+ const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(
19763
+ params17.session,
19764
+ env
19765
+ );
19645
19766
  const lines = await namedSession.session.history({ last: params17.last });
19646
19767
  return { lines, exitCode: namedSession.session.exitCode };
19647
19768
  }
@@ -19649,7 +19770,9 @@ var readHistory = defineCommand({
19649
19770
 
19650
19771
  // src/commands/read-screen.ts
19651
19772
  var params9 = S.Object({
19652
- session: S.Optional(S.String({ short: "s", description: "Session name" }))
19773
+ session: S.Optional(
19774
+ S.String({ short: "s", description: "Session name", minLength: 1, pattern: "\\S" })
19775
+ )
19653
19776
  });
19654
19777
  var readScreen = defineCommand({
19655
19778
  name: "read-screen",
@@ -19657,7 +19780,10 @@ var readScreen = defineCommand({
19657
19780
  scope: ["cli", "mcp", "sdk"],
19658
19781
  params: params9,
19659
19782
  handler: async ({ params: params17, env, terminalPilotRuntime }) => {
19660
- const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(params17.session, env);
19783
+ const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(
19784
+ params17.session,
19785
+ env
19786
+ );
19661
19787
  const screen = await namedSession.session.screen();
19662
19788
  return {
19663
19789
  lines: [...screen.lines],
@@ -19670,9 +19796,11 @@ var readScreen = defineCommand({
19670
19796
 
19671
19797
  // src/commands/resize.ts
19672
19798
  var params10 = S.Object({
19673
- cols: S.Number({ description: "Terminal width in columns" }),
19674
- rows: S.Number({ description: "Terminal height in rows" }),
19675
- session: S.Optional(S.String({ short: "s", description: "Session name" }))
19799
+ cols: S.Number({ description: "Terminal width in columns", jsonType: "integer", minimum: 1 }),
19800
+ rows: S.Number({ description: "Terminal height in rows", jsonType: "integer", minimum: 1 }),
19801
+ session: S.Optional(
19802
+ S.String({ short: "s", description: "Session name", minLength: 1, pattern: "\\S" })
19803
+ )
19676
19804
  });
19677
19805
  var resize = defineCommand({
19678
19806
  name: "resize",
@@ -19680,7 +19808,10 @@ var resize = defineCommand({
19680
19808
  scope: ["cli", "mcp", "sdk"],
19681
19809
  params: params10,
19682
19810
  handler: async ({ params: params17, env, terminalPilotRuntime }) => {
19683
- const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(params17.session, env);
19811
+ const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(
19812
+ params17.session,
19813
+ env
19814
+ );
19684
19815
  await namedSession.session.resize(params17.cols, params17.rows);
19685
19816
  return void 0;
19686
19817
  }
@@ -19692,6 +19823,9 @@ import { rename as rename4, rm, writeFile as writeFile6 } from "node:fs/promises
19692
19823
 
19693
19824
  // ../terminal-png/src/ansi-parser.ts
19694
19825
  var ESC2 = "\x1B";
19826
+ var TAB_WIDTH = 8;
19827
+ var MAX_TERMINAL_ROWS = 1e3;
19828
+ var MAX_TERMINAL_COLUMNS = 1e3;
19695
19829
  function createDefaultStyle() {
19696
19830
  return {
19697
19831
  fg: null,
@@ -19976,10 +20110,34 @@ function positionParameter(params17, index, fallback) {
19976
20110
  const value = toInteger(params17.split(";")[index]);
19977
20111
  return value === null || value < 1 ? fallback : value;
19978
20112
  }
20113
+ function modeParameter(params17, fallback) {
20114
+ const value = toInteger(params17.split(";")[0]);
20115
+ return value === null ? fallback : value;
20116
+ }
20117
+ function displayWidth3(text4) {
20118
+ if (text4 === " ") {
20119
+ return TAB_WIDTH;
20120
+ }
20121
+ const codePoint = text4.codePointAt(0);
20122
+ if (codePoint === void 0) {
20123
+ return 0;
20124
+ }
20125
+ 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) {
20126
+ return 2;
20127
+ }
20128
+ return 1;
20129
+ }
20130
+ function hasRenderableCell(line) {
20131
+ return (line ?? []).some((cell) => cell !== void 0 && cell.text.length > 0);
20132
+ }
19979
20133
  function buildRuns(lines, lineBreakStyles) {
19980
20134
  const runs = [];
19981
20135
  const defaultStyle = createDefaultStyle();
19982
- for (let row = 0; row < lines.length; row += 1) {
20136
+ let lastRow = lines.length - 1;
20137
+ while (lastRow > 0 && !hasRenderableCell(lines[lastRow]) && lineBreakStyles[lastRow - 1] === void 0) {
20138
+ lastRow -= 1;
20139
+ }
20140
+ for (let row = 0; row <= lastRow; row += 1) {
19983
20141
  const line = lines[row] ?? [];
19984
20142
  let lastCell = line.length - 1;
19985
20143
  while (lastCell >= 0 && line[lastCell] === void 0) {
@@ -19989,7 +20147,7 @@ function buildRuns(lines, lineBreakStyles) {
19989
20147
  const cell = line[column] ?? { text: " ", style: defaultStyle };
19990
20148
  pushRun(runs, cell.style, cell.text);
19991
20149
  }
19992
- if (row < lines.length - 1) {
20150
+ if (row < lastRow) {
19993
20151
  pushRun(runs, lineBreakStyles[row] ?? defaultStyle, "\n");
19994
20152
  }
19995
20153
  }
@@ -20001,7 +20159,21 @@ function parseAnsi2(input) {
20001
20159
  let style = createDefaultStyle();
20002
20160
  let row = 0;
20003
20161
  let column = 0;
20162
+ let savedRow = 0;
20163
+ let savedColumn = 0;
20004
20164
  let index = 0;
20165
+ const clampRow = (nextRow) => {
20166
+ if (nextRow < 0) {
20167
+ return 0;
20168
+ }
20169
+ return Math.min(nextRow, MAX_TERMINAL_ROWS - 1);
20170
+ };
20171
+ const clampColumn = (nextColumn) => {
20172
+ if (nextColumn < 0) {
20173
+ return 0;
20174
+ }
20175
+ return Math.min(nextColumn, MAX_TERMINAL_COLUMNS - 1);
20176
+ };
20005
20177
  const ensureLine = () => {
20006
20178
  while (lines.length <= row) {
20007
20179
  lines.push([]);
@@ -20009,12 +20181,64 @@ function parseAnsi2(input) {
20009
20181
  };
20010
20182
  const moveDown = (keepColumn) => {
20011
20183
  lineBreakStyles[row] = cloneStyle(style);
20012
- row += 1;
20184
+ row = clampRow(row + 1);
20013
20185
  if (!keepColumn) {
20014
20186
  column = 0;
20015
20187
  }
20016
20188
  ensureLine();
20017
20189
  };
20190
+ const eraseLine = (mode) => {
20191
+ const line = lines[row] ?? [];
20192
+ if (mode === 1) {
20193
+ for (let cell = 0; cell <= column; cell += 1) {
20194
+ delete line[cell];
20195
+ }
20196
+ return;
20197
+ }
20198
+ if (mode === 2) {
20199
+ lines[row] = [];
20200
+ return;
20201
+ }
20202
+ line.splice(column);
20203
+ };
20204
+ const eraseDisplay = (mode) => {
20205
+ if (mode === 1) {
20206
+ for (let lineRow = 0; lineRow < row; lineRow += 1) {
20207
+ lines[lineRow] = [];
20208
+ }
20209
+ eraseLine(1);
20210
+ return;
20211
+ }
20212
+ if (mode === 2 || mode === 3) {
20213
+ lines.length = 0;
20214
+ lineBreakStyles.length = 0;
20215
+ ensureLine();
20216
+ return;
20217
+ }
20218
+ eraseLine(0);
20219
+ lines.splice(row + 1);
20220
+ lineBreakStyles.splice(row);
20221
+ };
20222
+ const saveCursor = () => {
20223
+ savedRow = row;
20224
+ savedColumn = column;
20225
+ };
20226
+ const restoreCursor = () => {
20227
+ row = clampRow(savedRow);
20228
+ column = clampColumn(savedColumn);
20229
+ ensureLine();
20230
+ };
20231
+ const writeText = (text4) => {
20232
+ const width = displayWidth3(text4);
20233
+ if (width === 0) {
20234
+ return;
20235
+ }
20236
+ lines[row][column] = { text: text4, style: cloneStyle(style) };
20237
+ for (let offset = 1; offset < width && column + offset < MAX_TERMINAL_COLUMNS; offset += 1) {
20238
+ lines[row][column + offset] = { text: "", style: cloneStyle(style) };
20239
+ }
20240
+ column = clampColumn(column + width);
20241
+ };
20018
20242
  while (index < input.length) {
20019
20243
  const char = input[index];
20020
20244
  if (char === "\n") {
@@ -20037,38 +20261,73 @@ function parseAnsi2(input) {
20037
20261
  index += 1;
20038
20262
  continue;
20039
20263
  }
20264
+ if (char === " ") {
20265
+ const nextTabStop = Math.min(
20266
+ Math.floor(column / TAB_WIDTH) * TAB_WIDTH + TAB_WIDTH,
20267
+ MAX_TERMINAL_COLUMNS
20268
+ );
20269
+ while (column < nextTabStop) {
20270
+ writeText(" ");
20271
+ }
20272
+ index += 1;
20273
+ continue;
20274
+ }
20040
20275
  if (char === ESC2 && input[index + 1] === "]") {
20041
20276
  index = parseOscEnd(input, index);
20042
20277
  continue;
20043
20278
  }
20279
+ if (char === ESC2 && input[index + 1] === "7") {
20280
+ saveCursor();
20281
+ index += 2;
20282
+ continue;
20283
+ }
20284
+ if (char === ESC2 && input[index + 1] === "8") {
20285
+ restoreCursor();
20286
+ index += 2;
20287
+ continue;
20288
+ }
20044
20289
  const csiPrefixLength = char === "\x9B" ? 1 : char === ESC2 && input[index + 1] === "[" ? 2 : null;
20045
20290
  if (csiPrefixLength !== null) {
20046
20291
  const sequence = parseCsi(input, index, csiPrefixLength);
20047
20292
  if (sequence.final === "m") {
20048
20293
  style = applySgr(style, sequence.params);
20049
20294
  } else if (sequence.final === "G") {
20050
- column = positionParameter(sequence.params, 0, 1) - 1;
20295
+ column = clampColumn(positionParameter(sequence.params, 0, 1) - 1);
20051
20296
  } else if (sequence.final === "C") {
20052
- column += positionParameter(sequence.params, 0, 1);
20297
+ column = clampColumn(column + positionParameter(sequence.params, 0, 1));
20053
20298
  } else if (sequence.final === "D") {
20054
20299
  column = Math.max(0, column - positionParameter(sequence.params, 0, 1));
20055
20300
  } else if (sequence.final === "A") {
20056
- row = Math.max(0, row - positionParameter(sequence.params, 0, 1));
20301
+ row = clampRow(row - positionParameter(sequence.params, 0, 1));
20057
20302
  } else if (sequence.final === "B") {
20058
- row += positionParameter(sequence.params, 0, 1);
20303
+ row = clampRow(row + positionParameter(sequence.params, 0, 1));
20304
+ ensureLine();
20305
+ } else if (sequence.final === "E") {
20306
+ row = clampRow(row + positionParameter(sequence.params, 0, 1));
20307
+ column = 0;
20059
20308
  ensureLine();
20309
+ } else if (sequence.final === "F") {
20310
+ row = clampRow(row - positionParameter(sequence.params, 0, 1));
20311
+ column = 0;
20060
20312
  } else if (sequence.final === "H" || sequence.final === "f") {
20061
- row = positionParameter(sequence.params, 0, 1) - 1;
20062
- column = positionParameter(sequence.params, 1, 1) - 1;
20313
+ row = clampRow(positionParameter(sequence.params, 0, 1) - 1);
20314
+ column = clampColumn(positionParameter(sequence.params, 1, 1) - 1);
20063
20315
  ensureLine();
20316
+ } else if (sequence.final === "K") {
20317
+ eraseLine(modeParameter(sequence.params, 0));
20318
+ } else if (sequence.final === "J") {
20319
+ eraseDisplay(modeParameter(sequence.params, 0));
20320
+ } else if (sequence.final === "s") {
20321
+ saveCursor();
20322
+ } else if (sequence.final === "u") {
20323
+ restoreCursor();
20064
20324
  }
20065
20325
  index = sequence.end;
20066
20326
  continue;
20067
20327
  }
20068
20328
  const codePoint = input.codePointAt(index);
20069
20329
  const text4 = codePoint === void 0 ? "" : String.fromCodePoint(codePoint);
20070
- lines[row][column] = { text: text4, style: cloneStyle(style) };
20071
- column += 1;
20330
+ writeText(text4);
20072
20331
  index += text4.length;
20073
20332
  }
20074
20333
  return buildRuns(lines, lineBreakStyles);
@@ -20476,11 +20735,11 @@ function splitIntoLines(runs) {
20476
20735
  }
20477
20736
  function measureLines(lines) {
20478
20737
  return Math.max(
20479
- ...lines.map((line) => displayWidth3(line.map((run) => run.text).join("")) * CHARACTER_WIDTH),
20738
+ ...lines.map((line) => displayWidth4(line.map((run) => run.text).join("")) * CHARACTER_WIDTH),
20480
20739
  0
20481
20740
  );
20482
20741
  }
20483
- function displayWidth3(text4, startColumn = 0) {
20742
+ function displayWidth4(text4, startColumn = 0) {
20484
20743
  const segmenter = new Intl.Segmenter();
20485
20744
  let column = startColumn;
20486
20745
  for (const { segment } of segmenter.segment(text4)) {
@@ -20542,7 +20801,7 @@ function renderBackgrounds(line, startX, y, height) {
20542
20801
  let column = 0;
20543
20802
  const rectangles = [];
20544
20803
  for (const run of line) {
20545
- const width = displayWidth3(run.text, column);
20804
+ const width = displayWidth4(run.text, column);
20546
20805
  const background = resolveBackgroundColor(run);
20547
20806
  if (background !== BACKGROUND && width > 0) {
20548
20807
  rectangles.push(`<rect x="${formatNumber(startX + column * CHARACTER_WIDTH)}" y="${formatNumber(y)}" width="${formatNumber(width * CHARACTER_WIDTH)}" height="${formatNumber(height)}" fill="${escapeXmlAttribute(background)}" />`);
@@ -20576,7 +20835,7 @@ function renderRun(run) {
20576
20835
  if (run.dim) {
20577
20836
  attributes.push('opacity="0.7"');
20578
20837
  }
20579
- const text4 = run.conceal ? " ".repeat(displayWidth3(run.text)) : run.text;
20838
+ const text4 = run.conceal ? " ".repeat(displayWidth4(run.text)) : run.text;
20580
20839
  return `<tspan ${attributes.join(" ")}>${escapeXmlText(text4)}</tspan>`;
20581
20840
  }
20582
20841
  function renderWindowControls() {
@@ -20625,13 +20884,16 @@ async function renderTerminalPng(ansiText, options = {}) {
20625
20884
  if (options.padding !== void 0 && (!Number.isInteger(options.padding) || options.padding < 0)) {
20626
20885
  throw new Error("Padding must be a non-negative integer.");
20627
20886
  }
20887
+ if (options.output !== void 0 && options.output.length === 0) {
20888
+ throw new Error("Output path must not be empty.");
20889
+ }
20628
20890
  const runs = parseAnsi2(ansiText);
20629
20891
  const svg = renderSvg(runs, {
20630
20892
  padding: options.padding,
20631
20893
  window: options.window
20632
20894
  });
20633
20895
  const png = renderPng(svg);
20634
- if (options.output) {
20896
+ if (options.output !== void 0) {
20635
20897
  const temporaryPath = `${options.output}.${randomUUID10()}.tmp`;
20636
20898
  let temporaryCreated = false;
20637
20899
  try {
@@ -20657,10 +20919,19 @@ function isAlreadyExistsError3(error3) {
20657
20919
 
20658
20920
  // src/commands/screenshot.ts
20659
20921
  var params11 = S.Object({
20660
- session: S.Optional(S.String({ short: "s", description: "Session name" })),
20922
+ session: S.Optional(
20923
+ S.String({ short: "s", description: "Session name", minLength: 1, pattern: "\\S" })
20924
+ ),
20661
20925
  output: S.String({ short: "o", description: "Path to the output PNG file" }),
20662
20926
  window: S.Optional(S.Boolean({ description: "Include terminal window chrome", default: true })),
20663
- padding: S.Optional(S.Number({ short: "p", description: "Padding around terminal content" }))
20927
+ padding: S.Optional(
20928
+ S.Number({
20929
+ short: "p",
20930
+ description: "Padding around terminal content",
20931
+ jsonType: "integer",
20932
+ minimum: 0
20933
+ })
20934
+ )
20664
20935
  });
20665
20936
  var screenshot = defineCommand({
20666
20937
  name: "screenshot",
@@ -20668,7 +20939,10 @@ var screenshot = defineCommand({
20668
20939
  scope: ["cli"],
20669
20940
  params: params11,
20670
20941
  handler: async ({ params: params17, env, terminalPilotRuntime }) => {
20671
- const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(params17.session, env);
20942
+ const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(
20943
+ params17.session,
20944
+ env
20945
+ );
20672
20946
  const screen = await namedSession.session.screen();
20673
20947
  await renderTerminalPng(screen.rawLines.join("\n"), {
20674
20948
  output: params17.output,
@@ -20682,7 +20956,9 @@ var screenshot = defineCommand({
20682
20956
  // src/commands/send-signal.ts
20683
20957
  var params12 = S.Object({
20684
20958
  signal: S.String({ description: "Signal to send to the session process" }),
20685
- session: S.Optional(S.String({ short: "s", description: "Session name" }))
20959
+ session: S.Optional(
20960
+ S.String({ short: "s", description: "Session name", minLength: 1, pattern: "\\S" })
20961
+ )
20686
20962
  });
20687
20963
  var sendSignal = defineCommand({
20688
20964
  name: "send-signal",
@@ -20691,7 +20967,10 @@ var sendSignal = defineCommand({
20691
20967
  positional: ["signal"],
20692
20968
  params: params12,
20693
20969
  handler: async ({ params: params17, env, terminalPilotRuntime }) => {
20694
- const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(params17.session, env);
20970
+ const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(
20971
+ params17.session,
20972
+ env
20973
+ );
20695
20974
  await namedSession.session.signal(params17.signal);
20696
20975
  return void 0;
20697
20976
  }
@@ -20700,7 +20979,9 @@ var sendSignal = defineCommand({
20700
20979
  // src/commands/type.ts
20701
20980
  var params13 = S.Object({
20702
20981
  text: S.String({ description: "Text to write to the session" }),
20703
- session: S.Optional(S.String({ short: "s", description: "Session name" }))
20982
+ session: S.Optional(
20983
+ S.String({ short: "s", description: "Session name", minLength: 1, pattern: "\\S" })
20984
+ )
20704
20985
  });
20705
20986
  var type = defineCommand({
20706
20987
  name: "type",
@@ -20709,7 +20990,10 @@ var type = defineCommand({
20709
20990
  positional: ["text"],
20710
20991
  params: params13,
20711
20992
  handler: async ({ params: params17, env, terminalPilotRuntime }) => {
20712
- const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(params17.session, env);
20993
+ const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(
20994
+ params17.session,
20995
+ env
20996
+ );
20713
20997
  await namedSession.session.type(params17.text);
20714
20998
  return void 0;
20715
20999
  }
@@ -20787,9 +21071,17 @@ async function folderExists(fs4, folderPath) {
20787
21071
 
20788
21072
  // src/commands/wait-for.ts
20789
21073
  var params15 = S.Object({
20790
- pattern: S.String({ description: "Regular expression pattern to wait for" }),
20791
- session: S.Optional(S.String({ short: "s", description: "Session name" })),
20792
- timeout: S.Optional(S.Number({ short: "t", description: "Maximum wait time in milliseconds" })),
21074
+ pattern: S.String({
21075
+ description: "Regular expression pattern to wait for",
21076
+ minLength: 1,
21077
+ pattern: "\\S"
21078
+ }),
21079
+ session: S.Optional(
21080
+ S.String({ short: "s", description: "Session name", minLength: 1, pattern: "\\S" })
21081
+ ),
21082
+ timeout: S.Optional(
21083
+ S.Number({ short: "t", description: "Maximum wait time in milliseconds", minimum: 0 })
21084
+ ),
20793
21085
  literal: S.Optional(
20794
21086
  S.Boolean({
20795
21087
  short: "l",
@@ -20804,17 +21096,33 @@ var waitFor = defineCommand({
20804
21096
  positional: ["pattern"],
20805
21097
  params: params15,
20806
21098
  handler: async ({ params: params17, env, terminalPilotRuntime }) => {
20807
- const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(params17.session, env);
21099
+ if (params17.pattern.trim().length === 0) {
21100
+ throw new UserError("Wait pattern must not be empty.");
21101
+ }
21102
+ assertTimeout2(params17.timeout);
21103
+ const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(
21104
+ params17.session,
21105
+ env
21106
+ );
20808
21107
  const pattern = params17.literal === true ? params17.pattern : new RegExp(params17.pattern);
20809
21108
  const line = params17.timeout === void 0 ? await namedSession.session.waitFor(pattern) : await namedSession.session.waitFor(pattern, { timeout: params17.timeout });
20810
21109
  return { matched: true, line };
20811
21110
  }
20812
21111
  });
21112
+ function assertTimeout2(timeout) {
21113
+ if (timeout !== void 0 && (!Number.isFinite(timeout) || timeout < 0)) {
21114
+ throw new UserError("Timeout must be a finite non-negative number.");
21115
+ }
21116
+ }
20813
21117
 
20814
21118
  // src/commands/wait-for-exit.ts
20815
21119
  var params16 = S.Object({
20816
- session: S.Optional(S.String({ short: "s", description: "Session name" })),
20817
- timeout: S.Optional(S.Number({ short: "t", description: "Maximum wait time in milliseconds" }))
21120
+ session: S.Optional(
21121
+ S.String({ short: "s", description: "Session name", minLength: 1, pattern: "\\S" })
21122
+ ),
21123
+ timeout: S.Optional(
21124
+ S.Number({ short: "t", description: "Maximum wait time in milliseconds", minimum: 0 })
21125
+ )
20818
21126
  });
20819
21127
  var waitForExit2 = defineCommand({
20820
21128
  name: "wait-for-exit",
@@ -20822,7 +21130,13 @@ var waitForExit2 = defineCommand({
20822
21130
  scope: ["cli", "mcp", "sdk"],
20823
21131
  params: params16,
20824
21132
  handler: async ({ params: params17, env, terminalPilotRuntime }) => {
20825
- const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(params17.session, env);
21133
+ if (params17.timeout !== void 0 && (!Number.isFinite(params17.timeout) || params17.timeout < 0)) {
21134
+ throw new UserError("Timeout must be a finite non-negative number.");
21135
+ }
21136
+ const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(
21137
+ params17.session,
21138
+ env
21139
+ );
20826
21140
  const exitCode = await namedSession.session.waitForExit(
20827
21141
  params17.timeout === void 0 ? void 0 : { timeout: params17.timeout }
20828
21142
  );