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
package/dist/cli.js CHANGED
@@ -12502,10 +12502,15 @@ async function writeErrorReport(context) {
12502
12502
 
12503
12503
  // ../toolcraft/src/number-schema.ts
12504
12504
  function isValidNumberSchemaValue(value, schema) {
12505
- return typeof value === "number" && Number.isFinite(value) && (schema.jsonType !== "integer" || Number.isInteger(value));
12505
+ 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);
12506
12506
  }
12507
12507
  function getExpectedNumberDescription(schema) {
12508
- return schema.jsonType === "integer" ? "an integer" : "a number";
12508
+ const type2 = schema.jsonType === "integer" ? "an integer" : "a number";
12509
+ const bounds = [
12510
+ schema.minimum === void 0 ? void 0 : `greater than or equal to ${schema.minimum}`,
12511
+ schema.maximum === void 0 ? void 0 : `less than or equal to ${schema.maximum}`
12512
+ ].filter((bound) => bound !== void 0);
12513
+ return bounds.length === 0 ? type2 : `${type2} ${bounds.join(" and ")}`;
12509
12514
  }
12510
12515
 
12511
12516
  // ../toolcraft/src/renderer.ts
@@ -16475,6 +16480,10 @@ var TerminalBuffer = class {
16475
16480
  }
16476
16481
  _writePrintable(ch) {
16477
16482
  const width = this._cellWidth(ch);
16483
+ if (width === 0) {
16484
+ this._appendCombiningMark(ch);
16485
+ return;
16486
+ }
16478
16487
  if (this._autoWrap && this._pendingWrap) {
16479
16488
  this._cursorX = 0;
16480
16489
  this._newline();
@@ -16509,11 +16518,40 @@ var TerminalBuffer = class {
16509
16518
  _cellWidth(ch) {
16510
16519
  const codePoint = ch.codePointAt(0);
16511
16520
  if (codePoint === void 0) return 0;
16521
+ if (isCombiningCodePoint2(codePoint)) {
16522
+ return 0;
16523
+ }
16512
16524
  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) {
16513
16525
  return Math.min(2, this._cols);
16514
16526
  }
16515
16527
  return 1;
16516
16528
  }
16529
+ _appendCombiningMark(ch) {
16530
+ const target = this._findCombiningTarget();
16531
+ if (target === null) {
16532
+ return;
16533
+ }
16534
+ const cell = this._screen[target.y]?.[target.x];
16535
+ if (cell === null || cell === void 0) {
16536
+ return;
16537
+ }
16538
+ cell[1] += ch;
16539
+ }
16540
+ _findCombiningTarget() {
16541
+ const startX = this._pendingWrap ? this._cursorX : this._cursorX - 1;
16542
+ for (let y = this._cursorY; y >= 0; y -= 1) {
16543
+ const row = this._screen[y];
16544
+ if (row === void 0) {
16545
+ continue;
16546
+ }
16547
+ for (let x = y === this._cursorY ? startX : this._cols - 1; x >= 0; x -= 1) {
16548
+ if (row[x] !== null) {
16549
+ return { x, y };
16550
+ }
16551
+ }
16552
+ }
16553
+ return null;
16554
+ }
16517
16555
  _setChar(y, x, ch) {
16518
16556
  const row = this._screen[y];
16519
16557
  if (row && x >= 0 && x < this._cols) {
@@ -16654,7 +16692,8 @@ var TerminalBuffer = class {
16654
16692
  case "J":
16655
16693
  if (p0 === 0) {
16656
16694
  this._eraseLine(this._cursorY, this._cursorX, this._cols - 1);
16657
- for (let y = this._cursorY + 1; y < this._rows; y++) this._eraseLine(y, 0, this._cols - 1);
16695
+ for (let y = this._cursorY + 1; y < this._rows; y++)
16696
+ this._eraseLine(y, 0, this._cols - 1);
16658
16697
  } else if (p0 === 1) {
16659
16698
  for (let y = 0; y < this._cursorY; y++) this._eraseLine(y, 0, this._cols - 1);
16660
16699
  this._eraseLine(this._cursorY, 0, this._cursorX);
@@ -17019,6 +17058,9 @@ function createDefaultStyleState() {
17019
17058
  strikethrough: false
17020
17059
  };
17021
17060
  }
17061
+ function isCombiningCodePoint2(codePoint) {
17062
+ return codePoint >= 768 && codePoint <= 879 || codePoint >= 6832 && codePoint <= 6911 || codePoint >= 7616 && codePoint <= 7679 || codePoint >= 8400 && codePoint <= 8447 || codePoint >= 65056 && codePoint <= 65071;
17063
+ }
17022
17064
  function serializeStyleState(state) {
17023
17065
  const codes = [];
17024
17066
  if (state.bold) {
@@ -17072,6 +17114,8 @@ var NAMED_KEY_LOWER = new Map(
17072
17114
  Object.entries(NAMED_KEY_SEQUENCES).map(([k, v]) => [k.toLowerCase(), v])
17073
17115
  );
17074
17116
  var VALID_KEYS_HINT = `Valid keys: ${Object.keys(NAMED_KEY_SEQUENCES).join(", ")}, Control+<letter>, Alt+<key>`;
17117
+ var NAMED_KEY_PATTERN = Object.keys(NAMED_KEY_SEQUENCES).map(caseInsensitivePattern).join("|");
17118
+ var TERMINAL_KEY_PATTERN = `^(?:${NAMED_KEY_PATTERN}|.|[Cc][Oo][Nn][Tt][Rr][Oo][Ll]\\+[A-Za-z]|[Aa][Ll][Tt]\\+.+)$`;
17075
17119
  function unknownKeyError(key2) {
17076
17120
  return new Error(`Unknown terminal key: ${key2}. ${VALID_KEYS_HINT}`);
17077
17121
  }
@@ -17114,6 +17158,18 @@ function controlKeyToSequence(controlKey) {
17114
17158
  }
17115
17159
  return String.fromCharCode(charCode - 64);
17116
17160
  }
17161
+ function caseInsensitivePattern(value) {
17162
+ let pattern = "";
17163
+ for (const character of value) {
17164
+ const lower = character.toLowerCase();
17165
+ const upper = character.toUpperCase();
17166
+ pattern += lower === upper ? escapePatternCharacter(character) : `[${upper}${lower}]`;
17167
+ }
17168
+ return pattern;
17169
+ }
17170
+ function escapePatternCharacter(character) {
17171
+ return character.replace(/[\\^$.*+?()[\]{}|]/g, "\\$&");
17172
+ }
17117
17173
 
17118
17174
  // src/terminal-screen.ts
17119
17175
  var TerminalScreen = class {
@@ -17553,7 +17609,11 @@ function createTerminalPilotRuntime(options = {}) {
17553
17609
  const pendingNames = /* @__PURE__ */ new Set();
17554
17610
  let pilotPromise;
17555
17611
  function getRequestedName(name, env) {
17556
- return name ?? env?.get(SESSION_ENV_VAR);
17612
+ const requestedName = name ?? env?.get(SESSION_ENV_VAR);
17613
+ if (requestedName !== void 0 && requestedName.trim().length === 0) {
17614
+ throw new UserError("Session name must not be empty.");
17615
+ }
17616
+ return requestedName;
17557
17617
  }
17558
17618
  async function getPilot() {
17559
17619
  pilotPromise ??= launchPilot();
@@ -17589,7 +17649,9 @@ function createTerminalPilotRuntime(options = {}) {
17589
17649
  const sessionId = nameToId.get(name);
17590
17650
  if (sessionId === void 0) {
17591
17651
  const active = await listSessions2();
17592
- throw new UserError(`Session "${name}" was not found. ${formatAvailableSessions(active.map((entry) => entry.name))}`);
17652
+ throw new UserError(
17653
+ `Session "${name}" was not found. ${formatAvailableSessions(active.map((entry) => entry.name))}`
17654
+ );
17593
17655
  }
17594
17656
  const pilot = await getPilot();
17595
17657
  try {
@@ -17597,7 +17659,9 @@ function createTerminalPilotRuntime(options = {}) {
17597
17659
  } catch {
17598
17660
  forgetSession(name, sessionId);
17599
17661
  const active = await listSessions2();
17600
- throw new UserError(`Session "${name}" was not found. ${formatAvailableSessions(active.map((entry) => entry.name))}`);
17662
+ throw new UserError(
17663
+ `Session "${name}" was not found. ${formatAvailableSessions(active.map((entry) => entry.name))}`
17664
+ );
17601
17665
  }
17602
17666
  }
17603
17667
  async function listSessions2() {
@@ -17628,6 +17692,9 @@ function createTerminalPilotRuntime(options = {}) {
17628
17692
  }
17629
17693
  return {
17630
17694
  async createSession(params17, env) {
17695
+ if (params17.command.trim().length === 0) {
17696
+ throw new UserError("Command must not be empty.");
17697
+ }
17631
17698
  const requestedName = getRequestedName(params17.session, env) ?? nextSessionName();
17632
17699
  await discardExitedSessionName(requestedName);
17633
17700
  if (nameToId.has(requestedName) || pendingNames.has(requestedName)) {
@@ -17693,7 +17760,9 @@ function createTerminalPilotRuntime(options = {}) {
17693
17760
 
17694
17761
  // src/commands/close-session.ts
17695
17762
  var params = S.Object({
17696
- session: S.Optional(S.String({ short: "s", description: "Session name" }))
17763
+ session: S.Optional(
17764
+ S.String({ short: "s", description: "Session name", minLength: 1, pattern: "\\S" })
17765
+ )
17697
17766
  });
17698
17767
  var closeSession = defineCommand({
17699
17768
  name: "close-session",
@@ -17701,19 +17770,28 @@ var closeSession = defineCommand({
17701
17770
  scope: ["cli", "mcp", "sdk"],
17702
17771
  params,
17703
17772
  handler: async ({ params: params17, env, terminalPilotRuntime }) => {
17704
- const { exitCode } = await getTerminalPilotRuntime(terminalPilotRuntime).closeSession(params17.session, env);
17773
+ const { exitCode } = await getTerminalPilotRuntime(terminalPilotRuntime).closeSession(
17774
+ params17.session,
17775
+ env
17776
+ );
17705
17777
  return { exitCode };
17706
17778
  }
17707
17779
  });
17708
17780
 
17709
17781
  // src/commands/create-session.ts
17710
17782
  var params2 = S.Object({
17711
- command: S.String({ description: "Command to execute" }),
17783
+ command: S.String({ description: "Command to execute", minLength: 1, pattern: "\\S" }),
17712
17784
  args: S.Optional(S.Array(S.String(), { description: "Command arguments" })),
17713
- session: S.Optional(S.String({ short: "s", description: "Session name" })),
17785
+ session: S.Optional(
17786
+ S.String({ short: "s", description: "Session name", minLength: 1, pattern: "\\S" })
17787
+ ),
17714
17788
  cwd: S.Optional(S.String({ description: "Working directory" })),
17715
- cols: S.Optional(S.Number({ description: "Terminal width in columns" })),
17716
- rows: S.Optional(S.Number({ description: "Terminal height in rows" })),
17789
+ cols: S.Optional(
17790
+ S.Number({ description: "Terminal width in columns", jsonType: "integer", minimum: 1 })
17791
+ ),
17792
+ rows: S.Optional(
17793
+ S.Number({ description: "Terminal height in rows", jsonType: "integer", minimum: 1 })
17794
+ ),
17717
17795
  observe: S.Optional(S.Boolean({ description: "Mirror PTY output to stderr" }))
17718
17796
  });
17719
17797
  var createSession = defineCommand({
@@ -17723,7 +17801,10 @@ var createSession = defineCommand({
17723
17801
  positional: ["command", "args"],
17724
17802
  params: params2,
17725
17803
  handler: async ({ params: params17, env, terminalPilotRuntime }) => {
17726
- const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).createSession(params17, env);
17804
+ const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).createSession(
17805
+ params17,
17806
+ env
17807
+ );
17727
17808
  return { session: namedSession.name, pid: namedSession.session.pid };
17728
17809
  }
17729
17810
  });
@@ -17731,7 +17812,9 @@ var createSession = defineCommand({
17731
17812
  // src/commands/fill.ts
17732
17813
  var params3 = S.Object({
17733
17814
  text: S.String({ description: "Text to write to the session" }),
17734
- session: S.Optional(S.String({ short: "s", description: "Session name" }))
17815
+ session: S.Optional(
17816
+ S.String({ short: "s", description: "Session name", minLength: 1, pattern: "\\S" })
17817
+ )
17735
17818
  });
17736
17819
  var fill = defineCommand({
17737
17820
  name: "fill",
@@ -17740,7 +17823,10 @@ var fill = defineCommand({
17740
17823
  positional: ["text"],
17741
17824
  params: params3,
17742
17825
  handler: async ({ params: params17, env, terminalPilotRuntime }) => {
17743
- const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(params17.session, env);
17826
+ const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(
17827
+ params17.session,
17828
+ env
17829
+ );
17744
17830
  await namedSession.session.fill(params17.text);
17745
17831
  return void 0;
17746
17832
  }
@@ -17748,7 +17834,9 @@ var fill = defineCommand({
17748
17834
 
17749
17835
  // src/commands/get-session.ts
17750
17836
  var params4 = S.Object({
17751
- session: S.Optional(S.String({ short: "s", description: "Session name" }))
17837
+ session: S.Optional(
17838
+ S.String({ short: "s", description: "Session name", minLength: 1, pattern: "\\S" })
17839
+ )
17752
17840
  });
17753
17841
  var getSession = defineCommand({
17754
17842
  name: "get-session",
@@ -17756,7 +17844,10 @@ var getSession = defineCommand({
17756
17844
  scope: ["cli", "mcp", "sdk"],
17757
17845
  params: params4,
17758
17846
  handler: async ({ params: params17, env, terminalPilotRuntime }) => {
17759
- const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(params17.session, env);
17847
+ const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(
17848
+ params17.session,
17849
+ env
17850
+ );
17760
17851
  return {
17761
17852
  session: namedSession.name,
17762
17853
  pid: namedSession.session.pid,
@@ -17784,7 +17875,7 @@ var claudeCodeAgent = {
17784
17875
  CLAUDE_CODE_ENABLE_TELEMETRY: "1"
17785
17876
  }
17786
17877
  },
17787
- configPath: "~/.claude/settings.json",
17878
+ configPath: "~/.claude.json",
17788
17879
  branding: {
17789
17880
  colors: {
17790
17881
  dark: "#C15F3C",
@@ -17799,7 +17890,12 @@ var claudeDesktopAgent = {
17799
17890
  name: "claude-desktop",
17800
17891
  label: "Claude Desktop",
17801
17892
  summary: "Anthropic's official desktop application for Claude",
17802
- configPath: "~/.claude/settings.json",
17893
+ configPath: "~/.config/Claude/claude_desktop_config.json",
17894
+ configPaths: {
17895
+ darwin: "~/Library/Application Support/Claude/claude_desktop_config.json",
17896
+ linux: "~/.config/Claude/claude_desktop_config.json",
17897
+ win32: "~/AppData/Roaming/Claude/claude_desktop_config.json"
17898
+ },
17803
17899
  branding: {
17804
17900
  colors: {
17805
17901
  dark: "#D97757",
@@ -17843,7 +17939,7 @@ var cursorAgent = {
17843
17939
  label: "Cursor",
17844
17940
  summary: "Cursor's CLI coding agent.",
17845
17941
  binaryName: "cursor-agent",
17846
- configPath: "~/.cursor/cli-config.json",
17942
+ configPath: "~/.cursor/mcp.json",
17847
17943
  branding: {
17848
17944
  colors: {
17849
17945
  dark: "#FFFFFF",
@@ -17883,7 +17979,7 @@ var openCodeAgent = {
17883
17979
  OPENCODE_CONFIG_CONTENT: '{"experimental":{"openTelemetry":true}}'
17884
17980
  }
17885
17981
  },
17886
- configPath: "~/.config/opencode/config.json",
17982
+ configPath: "~/.config/opencode/opencode.json",
17887
17983
  branding: {
17888
17984
  colors: {
17889
17985
  dark: "#4A4F55",
@@ -17901,7 +17997,7 @@ var kimiAgent = {
17901
17997
  aliases: ["kimi-cli"],
17902
17998
  binaryName: "kimi",
17903
17999
  apiShapes: ["openai-chat-completions"],
17904
- configPath: "~/.kimi/config.toml",
18000
+ configPath: "~/.kimi/mcp.json",
17905
18001
  branding: {
17906
18002
  colors: {
17907
18003
  dark: "#7B68EE",
@@ -19601,8 +19697,10 @@ var listSessions = defineCommand({
19601
19697
 
19602
19698
  // src/commands/press-key.ts
19603
19699
  var params7 = S.Object({
19604
- key: S.String({ description: "Named key to press" }),
19605
- session: S.Optional(S.String({ short: "s", description: "Session name" }))
19700
+ key: S.String({ description: "Named key to press", pattern: TERMINAL_KEY_PATTERN }),
19701
+ session: S.Optional(
19702
+ S.String({ short: "s", description: "Session name", minLength: 1, pattern: "\\S" })
19703
+ )
19606
19704
  });
19607
19705
  var pressKey = defineCommand({
19608
19706
  name: "press-key",
@@ -19611,16 +19709,36 @@ var pressKey = defineCommand({
19611
19709
  positional: ["key"],
19612
19710
  params: params7,
19613
19711
  handler: async ({ params: params17, env, terminalPilotRuntime }) => {
19614
- const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(params17.session, env);
19712
+ assertTerminalKey(params17.key);
19713
+ const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(
19714
+ params17.session,
19715
+ env
19716
+ );
19615
19717
  await namedSession.session.press(params17.key);
19616
19718
  return void 0;
19617
19719
  }
19618
19720
  });
19721
+ function assertTerminalKey(key2) {
19722
+ try {
19723
+ keyToSequence(key2);
19724
+ } catch (error3) {
19725
+ throw new UserError(error3 instanceof Error ? error3.message : String(error3));
19726
+ }
19727
+ }
19619
19728
 
19620
19729
  // src/commands/read-history.ts
19621
19730
  var params8 = S.Object({
19622
- session: S.Optional(S.String({ short: "s", description: "Session name" })),
19623
- last: S.Optional(S.Number({ short: "n", description: "Return only the last N lines" }))
19731
+ session: S.Optional(
19732
+ S.String({ short: "s", description: "Session name", minLength: 1, pattern: "\\S" })
19733
+ ),
19734
+ last: S.Optional(
19735
+ S.Number({
19736
+ short: "n",
19737
+ description: "Return only the last N lines",
19738
+ jsonType: "integer",
19739
+ minimum: 0
19740
+ })
19741
+ )
19624
19742
  });
19625
19743
  var readHistory = defineCommand({
19626
19744
  name: "read-history",
@@ -19628,7 +19746,10 @@ var readHistory = defineCommand({
19628
19746
  scope: ["cli", "mcp", "sdk"],
19629
19747
  params: params8,
19630
19748
  handler: async ({ params: params17, env, terminalPilotRuntime }) => {
19631
- const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(params17.session, env);
19749
+ const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(
19750
+ params17.session,
19751
+ env
19752
+ );
19632
19753
  const lines = await namedSession.session.history({ last: params17.last });
19633
19754
  return { lines, exitCode: namedSession.session.exitCode };
19634
19755
  }
@@ -19636,7 +19757,9 @@ var readHistory = defineCommand({
19636
19757
 
19637
19758
  // src/commands/read-screen.ts
19638
19759
  var params9 = S.Object({
19639
- session: S.Optional(S.String({ short: "s", description: "Session name" }))
19760
+ session: S.Optional(
19761
+ S.String({ short: "s", description: "Session name", minLength: 1, pattern: "\\S" })
19762
+ )
19640
19763
  });
19641
19764
  var readScreen = defineCommand({
19642
19765
  name: "read-screen",
@@ -19644,7 +19767,10 @@ var readScreen = defineCommand({
19644
19767
  scope: ["cli", "mcp", "sdk"],
19645
19768
  params: params9,
19646
19769
  handler: async ({ params: params17, env, terminalPilotRuntime }) => {
19647
- const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(params17.session, env);
19770
+ const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(
19771
+ params17.session,
19772
+ env
19773
+ );
19648
19774
  const screen = await namedSession.session.screen();
19649
19775
  return {
19650
19776
  lines: [...screen.lines],
@@ -19657,9 +19783,11 @@ var readScreen = defineCommand({
19657
19783
 
19658
19784
  // src/commands/resize.ts
19659
19785
  var params10 = S.Object({
19660
- cols: S.Number({ description: "Terminal width in columns" }),
19661
- rows: S.Number({ description: "Terminal height in rows" }),
19662
- session: S.Optional(S.String({ short: "s", description: "Session name" }))
19786
+ cols: S.Number({ description: "Terminal width in columns", jsonType: "integer", minimum: 1 }),
19787
+ rows: S.Number({ description: "Terminal height in rows", jsonType: "integer", minimum: 1 }),
19788
+ session: S.Optional(
19789
+ S.String({ short: "s", description: "Session name", minLength: 1, pattern: "\\S" })
19790
+ )
19663
19791
  });
19664
19792
  var resize = defineCommand({
19665
19793
  name: "resize",
@@ -19667,7 +19795,10 @@ var resize = defineCommand({
19667
19795
  scope: ["cli", "mcp", "sdk"],
19668
19796
  params: params10,
19669
19797
  handler: async ({ params: params17, env, terminalPilotRuntime }) => {
19670
- const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(params17.session, env);
19798
+ const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(
19799
+ params17.session,
19800
+ env
19801
+ );
19671
19802
  await namedSession.session.resize(params17.cols, params17.rows);
19672
19803
  return void 0;
19673
19804
  }
@@ -19679,6 +19810,9 @@ import { rename as rename4, rm, writeFile as writeFile6 } from "node:fs/promises
19679
19810
 
19680
19811
  // ../terminal-png/src/ansi-parser.ts
19681
19812
  var ESC2 = "\x1B";
19813
+ var TAB_WIDTH = 8;
19814
+ var MAX_TERMINAL_ROWS = 1e3;
19815
+ var MAX_TERMINAL_COLUMNS = 1e3;
19682
19816
  function createDefaultStyle() {
19683
19817
  return {
19684
19818
  fg: null,
@@ -19963,10 +20097,34 @@ function positionParameter(params17, index, fallback) {
19963
20097
  const value = toInteger(params17.split(";")[index]);
19964
20098
  return value === null || value < 1 ? fallback : value;
19965
20099
  }
20100
+ function modeParameter(params17, fallback) {
20101
+ const value = toInteger(params17.split(";")[0]);
20102
+ return value === null ? fallback : value;
20103
+ }
20104
+ function displayWidth3(text4) {
20105
+ if (text4 === " ") {
20106
+ return TAB_WIDTH;
20107
+ }
20108
+ const codePoint = text4.codePointAt(0);
20109
+ if (codePoint === void 0) {
20110
+ return 0;
20111
+ }
20112
+ 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) {
20113
+ return 2;
20114
+ }
20115
+ return 1;
20116
+ }
20117
+ function hasRenderableCell(line) {
20118
+ return (line ?? []).some((cell) => cell !== void 0 && cell.text.length > 0);
20119
+ }
19966
20120
  function buildRuns(lines, lineBreakStyles) {
19967
20121
  const runs = [];
19968
20122
  const defaultStyle = createDefaultStyle();
19969
- for (let row = 0; row < lines.length; row += 1) {
20123
+ let lastRow = lines.length - 1;
20124
+ while (lastRow > 0 && !hasRenderableCell(lines[lastRow]) && lineBreakStyles[lastRow - 1] === void 0) {
20125
+ lastRow -= 1;
20126
+ }
20127
+ for (let row = 0; row <= lastRow; row += 1) {
19970
20128
  const line = lines[row] ?? [];
19971
20129
  let lastCell = line.length - 1;
19972
20130
  while (lastCell >= 0 && line[lastCell] === void 0) {
@@ -19976,7 +20134,7 @@ function buildRuns(lines, lineBreakStyles) {
19976
20134
  const cell = line[column] ?? { text: " ", style: defaultStyle };
19977
20135
  pushRun(runs, cell.style, cell.text);
19978
20136
  }
19979
- if (row < lines.length - 1) {
20137
+ if (row < lastRow) {
19980
20138
  pushRun(runs, lineBreakStyles[row] ?? defaultStyle, "\n");
19981
20139
  }
19982
20140
  }
@@ -19988,7 +20146,21 @@ function parseAnsi2(input) {
19988
20146
  let style = createDefaultStyle();
19989
20147
  let row = 0;
19990
20148
  let column = 0;
20149
+ let savedRow = 0;
20150
+ let savedColumn = 0;
19991
20151
  let index = 0;
20152
+ const clampRow = (nextRow) => {
20153
+ if (nextRow < 0) {
20154
+ return 0;
20155
+ }
20156
+ return Math.min(nextRow, MAX_TERMINAL_ROWS - 1);
20157
+ };
20158
+ const clampColumn = (nextColumn) => {
20159
+ if (nextColumn < 0) {
20160
+ return 0;
20161
+ }
20162
+ return Math.min(nextColumn, MAX_TERMINAL_COLUMNS - 1);
20163
+ };
19992
20164
  const ensureLine = () => {
19993
20165
  while (lines.length <= row) {
19994
20166
  lines.push([]);
@@ -19996,12 +20168,64 @@ function parseAnsi2(input) {
19996
20168
  };
19997
20169
  const moveDown = (keepColumn) => {
19998
20170
  lineBreakStyles[row] = cloneStyle(style);
19999
- row += 1;
20171
+ row = clampRow(row + 1);
20000
20172
  if (!keepColumn) {
20001
20173
  column = 0;
20002
20174
  }
20003
20175
  ensureLine();
20004
20176
  };
20177
+ const eraseLine = (mode) => {
20178
+ const line = lines[row] ?? [];
20179
+ if (mode === 1) {
20180
+ for (let cell = 0; cell <= column; cell += 1) {
20181
+ delete line[cell];
20182
+ }
20183
+ return;
20184
+ }
20185
+ if (mode === 2) {
20186
+ lines[row] = [];
20187
+ return;
20188
+ }
20189
+ line.splice(column);
20190
+ };
20191
+ const eraseDisplay = (mode) => {
20192
+ if (mode === 1) {
20193
+ for (let lineRow = 0; lineRow < row; lineRow += 1) {
20194
+ lines[lineRow] = [];
20195
+ }
20196
+ eraseLine(1);
20197
+ return;
20198
+ }
20199
+ if (mode === 2 || mode === 3) {
20200
+ lines.length = 0;
20201
+ lineBreakStyles.length = 0;
20202
+ ensureLine();
20203
+ return;
20204
+ }
20205
+ eraseLine(0);
20206
+ lines.splice(row + 1);
20207
+ lineBreakStyles.splice(row);
20208
+ };
20209
+ const saveCursor = () => {
20210
+ savedRow = row;
20211
+ savedColumn = column;
20212
+ };
20213
+ const restoreCursor = () => {
20214
+ row = clampRow(savedRow);
20215
+ column = clampColumn(savedColumn);
20216
+ ensureLine();
20217
+ };
20218
+ const writeText = (text4) => {
20219
+ const width = displayWidth3(text4);
20220
+ if (width === 0) {
20221
+ return;
20222
+ }
20223
+ lines[row][column] = { text: text4, style: cloneStyle(style) };
20224
+ for (let offset = 1; offset < width && column + offset < MAX_TERMINAL_COLUMNS; offset += 1) {
20225
+ lines[row][column + offset] = { text: "", style: cloneStyle(style) };
20226
+ }
20227
+ column = clampColumn(column + width);
20228
+ };
20005
20229
  while (index < input.length) {
20006
20230
  const char = input[index];
20007
20231
  if (char === "\n") {
@@ -20024,38 +20248,73 @@ function parseAnsi2(input) {
20024
20248
  index += 1;
20025
20249
  continue;
20026
20250
  }
20251
+ if (char === " ") {
20252
+ const nextTabStop = Math.min(
20253
+ Math.floor(column / TAB_WIDTH) * TAB_WIDTH + TAB_WIDTH,
20254
+ MAX_TERMINAL_COLUMNS
20255
+ );
20256
+ while (column < nextTabStop) {
20257
+ writeText(" ");
20258
+ }
20259
+ index += 1;
20260
+ continue;
20261
+ }
20027
20262
  if (char === ESC2 && input[index + 1] === "]") {
20028
20263
  index = parseOscEnd(input, index);
20029
20264
  continue;
20030
20265
  }
20266
+ if (char === ESC2 && input[index + 1] === "7") {
20267
+ saveCursor();
20268
+ index += 2;
20269
+ continue;
20270
+ }
20271
+ if (char === ESC2 && input[index + 1] === "8") {
20272
+ restoreCursor();
20273
+ index += 2;
20274
+ continue;
20275
+ }
20031
20276
  const csiPrefixLength = char === "\x9B" ? 1 : char === ESC2 && input[index + 1] === "[" ? 2 : null;
20032
20277
  if (csiPrefixLength !== null) {
20033
20278
  const sequence = parseCsi(input, index, csiPrefixLength);
20034
20279
  if (sequence.final === "m") {
20035
20280
  style = applySgr(style, sequence.params);
20036
20281
  } else if (sequence.final === "G") {
20037
- column = positionParameter(sequence.params, 0, 1) - 1;
20282
+ column = clampColumn(positionParameter(sequence.params, 0, 1) - 1);
20038
20283
  } else if (sequence.final === "C") {
20039
- column += positionParameter(sequence.params, 0, 1);
20284
+ column = clampColumn(column + positionParameter(sequence.params, 0, 1));
20040
20285
  } else if (sequence.final === "D") {
20041
20286
  column = Math.max(0, column - positionParameter(sequence.params, 0, 1));
20042
20287
  } else if (sequence.final === "A") {
20043
- row = Math.max(0, row - positionParameter(sequence.params, 0, 1));
20288
+ row = clampRow(row - positionParameter(sequence.params, 0, 1));
20044
20289
  } else if (sequence.final === "B") {
20045
- row += positionParameter(sequence.params, 0, 1);
20290
+ row = clampRow(row + positionParameter(sequence.params, 0, 1));
20291
+ ensureLine();
20292
+ } else if (sequence.final === "E") {
20293
+ row = clampRow(row + positionParameter(sequence.params, 0, 1));
20294
+ column = 0;
20046
20295
  ensureLine();
20296
+ } else if (sequence.final === "F") {
20297
+ row = clampRow(row - positionParameter(sequence.params, 0, 1));
20298
+ column = 0;
20047
20299
  } else if (sequence.final === "H" || sequence.final === "f") {
20048
- row = positionParameter(sequence.params, 0, 1) - 1;
20049
- column = positionParameter(sequence.params, 1, 1) - 1;
20300
+ row = clampRow(positionParameter(sequence.params, 0, 1) - 1);
20301
+ column = clampColumn(positionParameter(sequence.params, 1, 1) - 1);
20050
20302
  ensureLine();
20303
+ } else if (sequence.final === "K") {
20304
+ eraseLine(modeParameter(sequence.params, 0));
20305
+ } else if (sequence.final === "J") {
20306
+ eraseDisplay(modeParameter(sequence.params, 0));
20307
+ } else if (sequence.final === "s") {
20308
+ saveCursor();
20309
+ } else if (sequence.final === "u") {
20310
+ restoreCursor();
20051
20311
  }
20052
20312
  index = sequence.end;
20053
20313
  continue;
20054
20314
  }
20055
20315
  const codePoint = input.codePointAt(index);
20056
20316
  const text4 = codePoint === void 0 ? "" : String.fromCodePoint(codePoint);
20057
- lines[row][column] = { text: text4, style: cloneStyle(style) };
20058
- column += 1;
20317
+ writeText(text4);
20059
20318
  index += text4.length;
20060
20319
  }
20061
20320
  return buildRuns(lines, lineBreakStyles);
@@ -20463,11 +20722,11 @@ function splitIntoLines(runs) {
20463
20722
  }
20464
20723
  function measureLines(lines) {
20465
20724
  return Math.max(
20466
- ...lines.map((line) => displayWidth3(line.map((run) => run.text).join("")) * CHARACTER_WIDTH),
20725
+ ...lines.map((line) => displayWidth4(line.map((run) => run.text).join("")) * CHARACTER_WIDTH),
20467
20726
  0
20468
20727
  );
20469
20728
  }
20470
- function displayWidth3(text4, startColumn = 0) {
20729
+ function displayWidth4(text4, startColumn = 0) {
20471
20730
  const segmenter = new Intl.Segmenter();
20472
20731
  let column = startColumn;
20473
20732
  for (const { segment } of segmenter.segment(text4)) {
@@ -20529,7 +20788,7 @@ function renderBackgrounds(line, startX, y, height) {
20529
20788
  let column = 0;
20530
20789
  const rectangles = [];
20531
20790
  for (const run of line) {
20532
- const width = displayWidth3(run.text, column);
20791
+ const width = displayWidth4(run.text, column);
20533
20792
  const background = resolveBackgroundColor(run);
20534
20793
  if (background !== BACKGROUND && width > 0) {
20535
20794
  rectangles.push(`<rect x="${formatNumber(startX + column * CHARACTER_WIDTH)}" y="${formatNumber(y)}" width="${formatNumber(width * CHARACTER_WIDTH)}" height="${formatNumber(height)}" fill="${escapeXmlAttribute(background)}" />`);
@@ -20563,7 +20822,7 @@ function renderRun(run) {
20563
20822
  if (run.dim) {
20564
20823
  attributes.push('opacity="0.7"');
20565
20824
  }
20566
- const text4 = run.conceal ? " ".repeat(displayWidth3(run.text)) : run.text;
20825
+ const text4 = run.conceal ? " ".repeat(displayWidth4(run.text)) : run.text;
20567
20826
  return `<tspan ${attributes.join(" ")}>${escapeXmlText(text4)}</tspan>`;
20568
20827
  }
20569
20828
  function renderWindowControls() {
@@ -20612,13 +20871,16 @@ async function renderTerminalPng(ansiText, options = {}) {
20612
20871
  if (options.padding !== void 0 && (!Number.isInteger(options.padding) || options.padding < 0)) {
20613
20872
  throw new Error("Padding must be a non-negative integer.");
20614
20873
  }
20874
+ if (options.output !== void 0 && options.output.length === 0) {
20875
+ throw new Error("Output path must not be empty.");
20876
+ }
20615
20877
  const runs = parseAnsi2(ansiText);
20616
20878
  const svg = renderSvg(runs, {
20617
20879
  padding: options.padding,
20618
20880
  window: options.window
20619
20881
  });
20620
20882
  const png = renderPng(svg);
20621
- if (options.output) {
20883
+ if (options.output !== void 0) {
20622
20884
  const temporaryPath = `${options.output}.${randomUUID10()}.tmp`;
20623
20885
  let temporaryCreated = false;
20624
20886
  try {
@@ -20644,10 +20906,19 @@ function isAlreadyExistsError3(error3) {
20644
20906
 
20645
20907
  // src/commands/screenshot.ts
20646
20908
  var params11 = S.Object({
20647
- session: S.Optional(S.String({ short: "s", description: "Session name" })),
20909
+ session: S.Optional(
20910
+ S.String({ short: "s", description: "Session name", minLength: 1, pattern: "\\S" })
20911
+ ),
20648
20912
  output: S.String({ short: "o", description: "Path to the output PNG file" }),
20649
20913
  window: S.Optional(S.Boolean({ description: "Include terminal window chrome", default: true })),
20650
- padding: S.Optional(S.Number({ short: "p", description: "Padding around terminal content" }))
20914
+ padding: S.Optional(
20915
+ S.Number({
20916
+ short: "p",
20917
+ description: "Padding around terminal content",
20918
+ jsonType: "integer",
20919
+ minimum: 0
20920
+ })
20921
+ )
20651
20922
  });
20652
20923
  var screenshot = defineCommand({
20653
20924
  name: "screenshot",
@@ -20655,7 +20926,10 @@ var screenshot = defineCommand({
20655
20926
  scope: ["cli"],
20656
20927
  params: params11,
20657
20928
  handler: async ({ params: params17, env, terminalPilotRuntime }) => {
20658
- const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(params17.session, env);
20929
+ const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(
20930
+ params17.session,
20931
+ env
20932
+ );
20659
20933
  const screen = await namedSession.session.screen();
20660
20934
  await renderTerminalPng(screen.rawLines.join("\n"), {
20661
20935
  output: params17.output,
@@ -20669,7 +20943,9 @@ var screenshot = defineCommand({
20669
20943
  // src/commands/send-signal.ts
20670
20944
  var params12 = S.Object({
20671
20945
  signal: S.String({ description: "Signal to send to the session process" }),
20672
- session: S.Optional(S.String({ short: "s", description: "Session name" }))
20946
+ session: S.Optional(
20947
+ S.String({ short: "s", description: "Session name", minLength: 1, pattern: "\\S" })
20948
+ )
20673
20949
  });
20674
20950
  var sendSignal = defineCommand({
20675
20951
  name: "send-signal",
@@ -20678,7 +20954,10 @@ var sendSignal = defineCommand({
20678
20954
  positional: ["signal"],
20679
20955
  params: params12,
20680
20956
  handler: async ({ params: params17, env, terminalPilotRuntime }) => {
20681
- const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(params17.session, env);
20957
+ const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(
20958
+ params17.session,
20959
+ env
20960
+ );
20682
20961
  await namedSession.session.signal(params17.signal);
20683
20962
  return void 0;
20684
20963
  }
@@ -20687,7 +20966,9 @@ var sendSignal = defineCommand({
20687
20966
  // src/commands/type.ts
20688
20967
  var params13 = S.Object({
20689
20968
  text: S.String({ description: "Text to write to the session" }),
20690
- session: S.Optional(S.String({ short: "s", description: "Session name" }))
20969
+ session: S.Optional(
20970
+ S.String({ short: "s", description: "Session name", minLength: 1, pattern: "\\S" })
20971
+ )
20691
20972
  });
20692
20973
  var type = defineCommand({
20693
20974
  name: "type",
@@ -20696,7 +20977,10 @@ var type = defineCommand({
20696
20977
  positional: ["text"],
20697
20978
  params: params13,
20698
20979
  handler: async ({ params: params17, env, terminalPilotRuntime }) => {
20699
- const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(params17.session, env);
20980
+ const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(
20981
+ params17.session,
20982
+ env
20983
+ );
20700
20984
  await namedSession.session.type(params17.text);
20701
20985
  return void 0;
20702
20986
  }
@@ -20774,9 +21058,17 @@ async function folderExists(fs4, folderPath) {
20774
21058
 
20775
21059
  // src/commands/wait-for.ts
20776
21060
  var params15 = S.Object({
20777
- pattern: S.String({ description: "Regular expression pattern to wait for" }),
20778
- session: S.Optional(S.String({ short: "s", description: "Session name" })),
20779
- timeout: S.Optional(S.Number({ short: "t", description: "Maximum wait time in milliseconds" })),
21061
+ pattern: S.String({
21062
+ description: "Regular expression pattern to wait for",
21063
+ minLength: 1,
21064
+ pattern: "\\S"
21065
+ }),
21066
+ session: S.Optional(
21067
+ S.String({ short: "s", description: "Session name", minLength: 1, pattern: "\\S" })
21068
+ ),
21069
+ timeout: S.Optional(
21070
+ S.Number({ short: "t", description: "Maximum wait time in milliseconds", minimum: 0 })
21071
+ ),
20780
21072
  literal: S.Optional(
20781
21073
  S.Boolean({
20782
21074
  short: "l",
@@ -20791,17 +21083,33 @@ var waitFor = defineCommand({
20791
21083
  positional: ["pattern"],
20792
21084
  params: params15,
20793
21085
  handler: async ({ params: params17, env, terminalPilotRuntime }) => {
20794
- const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(params17.session, env);
21086
+ if (params17.pattern.trim().length === 0) {
21087
+ throw new UserError("Wait pattern must not be empty.");
21088
+ }
21089
+ assertTimeout2(params17.timeout);
21090
+ const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(
21091
+ params17.session,
21092
+ env
21093
+ );
20795
21094
  const pattern = params17.literal === true ? params17.pattern : new RegExp(params17.pattern);
20796
21095
  const line = params17.timeout === void 0 ? await namedSession.session.waitFor(pattern) : await namedSession.session.waitFor(pattern, { timeout: params17.timeout });
20797
21096
  return { matched: true, line };
20798
21097
  }
20799
21098
  });
21099
+ function assertTimeout2(timeout) {
21100
+ if (timeout !== void 0 && (!Number.isFinite(timeout) || timeout < 0)) {
21101
+ throw new UserError("Timeout must be a finite non-negative number.");
21102
+ }
21103
+ }
20800
21104
 
20801
21105
  // src/commands/wait-for-exit.ts
20802
21106
  var params16 = S.Object({
20803
- session: S.Optional(S.String({ short: "s", description: "Session name" })),
20804
- timeout: S.Optional(S.Number({ short: "t", description: "Maximum wait time in milliseconds" }))
21107
+ session: S.Optional(
21108
+ S.String({ short: "s", description: "Session name", minLength: 1, pattern: "\\S" })
21109
+ ),
21110
+ timeout: S.Optional(
21111
+ S.Number({ short: "t", description: "Maximum wait time in milliseconds", minimum: 0 })
21112
+ )
20805
21113
  });
20806
21114
  var waitForExit2 = defineCommand({
20807
21115
  name: "wait-for-exit",
@@ -20809,7 +21117,13 @@ var waitForExit2 = defineCommand({
20809
21117
  scope: ["cli", "mcp", "sdk"],
20810
21118
  params: params16,
20811
21119
  handler: async ({ params: params17, env, terminalPilotRuntime }) => {
20812
- const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(params17.session, env);
21120
+ if (params17.timeout !== void 0 && (!Number.isFinite(params17.timeout) || params17.timeout < 0)) {
21121
+ throw new UserError("Timeout must be a finite non-negative number.");
21122
+ }
21123
+ const namedSession = await getTerminalPilotRuntime(terminalPilotRuntime).resolveSession(
21124
+ params17.session,
21125
+ env
21126
+ );
20813
21127
  const exitCode = await namedSession.session.waitForExit(
20814
21128
  params17.timeout === void 0 ? void 0 : { timeout: params17.timeout }
20815
21129
  );