terminal-pilot 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/keys.js CHANGED
@@ -14,18 +14,24 @@ const NAMED_KEY_SEQUENCES = {
14
14
  PageDown: "\x1b[6~",
15
15
  Space: " "
16
16
  };
17
+ const NAMED_KEY_LOWER = new Map(Object.entries(NAMED_KEY_SEQUENCES).map(([k, v]) => [k.toLowerCase(), v]));
18
+ const VALID_KEYS_HINT = `Valid keys: ${Object.keys(NAMED_KEY_SEQUENCES).join(", ")}, Control+<letter>, Alt+<key>`;
19
+ function unknownKeyError(key) {
20
+ return new Error(`Unknown terminal key: ${key}. ${VALID_KEYS_HINT}`);
21
+ }
17
22
  export function keyToSequence(key) {
18
- const namedSequence = NAMED_KEY_SEQUENCES[key];
23
+ const lowerKey = key.toLowerCase();
24
+ const namedSequence = NAMED_KEY_LOWER.get(lowerKey);
19
25
  if (namedSequence !== undefined) {
20
26
  return namedSequence;
21
27
  }
22
- if (key.startsWith("Control+")) {
23
- return controlKeyToSequence(key);
28
+ if (lowerKey.startsWith("control+")) {
29
+ return controlKeyToSequence(key.slice("control+".length));
24
30
  }
25
- if (key.startsWith("Alt+")) {
26
- const nestedKey = key.slice("Alt+".length);
31
+ if (lowerKey.startsWith("alt+")) {
32
+ const nestedKey = key.slice("alt+".length);
27
33
  if (nestedKey.length === 0) {
28
- throw new Error(`Unknown terminal key: ${key}`);
34
+ throw unknownKeyError(key);
29
35
  }
30
36
  if (nestedKey.length === 1) {
31
37
  return "\x1b" + nestedKey;
@@ -34,20 +40,19 @@ export function keyToSequence(key) {
34
40
  return "\x1b" + keyToSequence(nestedKey);
35
41
  }
36
42
  catch {
37
- throw new Error(`Unknown terminal key: ${key}`);
43
+ throw unknownKeyError(key);
38
44
  }
39
45
  }
40
- throw new Error(`Unknown terminal key: ${key}`);
46
+ throw unknownKeyError(key);
41
47
  }
42
- function controlKeyToSequence(key) {
43
- const controlKey = key.slice("Control+".length);
48
+ function controlKeyToSequence(controlKey) {
44
49
  if (controlKey.length !== 1) {
45
- throw new Error(`Unknown terminal key: ${key}`);
50
+ throw unknownKeyError(`Control+${controlKey}`);
46
51
  }
47
52
  const uppercaseLetter = controlKey.toUpperCase();
48
53
  const charCode = uppercaseLetter.charCodeAt(0);
49
54
  if (charCode < 65 || charCode > 90) {
50
- throw new Error(`Unknown terminal key: ${key}`);
55
+ throw unknownKeyError(`Control+${controlKey}`);
51
56
  }
52
57
  return String.fromCharCode(charCode - 64);
53
58
  }
package/dist/mcp-tools.js CHANGED
@@ -71,10 +71,10 @@ export function terminalWaitForTool(agent) {
71
71
  async handler(input) {
72
72
  const session = agent.getSession(input.sessionId);
73
73
  const pattern = new RegExp(input.pattern);
74
- const output = input.timeout === undefined
74
+ const line = input.timeout === undefined
75
75
  ? await session.waitFor(pattern)
76
76
  : await session.waitFor(pattern, { timeout: input.timeout });
77
- return { matched: true, output };
77
+ return { matched: true, line };
78
78
  }
79
79
  };
80
80
  }
@@ -66,7 +66,7 @@ export class TerminalSession {
66
66
  }
67
67
  }
68
68
  async fill(text) {
69
- await this.send(text);
69
+ await this.send(text.replace(/\r?\n/g, "\r"));
70
70
  }
71
71
  async press(key) {
72
72
  await this.send(keyToSequence(key));
@@ -140,7 +140,9 @@ export class TerminalSession {
140
140
  async resize(cols, rows) {
141
141
  this.currentCols = cols;
142
142
  this.currentRows = rows;
143
- this.pty.resize(cols, rows);
143
+ if (this.exitCode === null) {
144
+ this.pty.resize(cols, rows);
145
+ }
144
146
  this.terminal.resize(cols, rows);
145
147
  }
146
148
  async close() {
@@ -252,13 +254,19 @@ function signalToExitCode(signal) {
252
254
  return 128 + signalNumber;
253
255
  }
254
256
  function matchPattern(buffer, pattern) {
255
- if (typeof pattern === "string") {
256
- return buffer.includes(pattern) ? pattern : null;
257
+ const clean = normalizeHistoryBuffer(stripAnsi(buffer));
258
+ for (const line of clean.split("\n")) {
259
+ if (typeof pattern === "string") {
260
+ if (line.includes(pattern))
261
+ return line;
262
+ }
263
+ else {
264
+ const flags = removeCharacter(pattern.flags, "g");
265
+ if (new RegExp(pattern.source, flags).test(line))
266
+ return line;
267
+ }
257
268
  }
258
- const flags = removeCharacter(pattern.flags, "g");
259
- const localPattern = new RegExp(pattern.source, flags);
260
- const match = localPattern.exec(buffer);
261
- return match?.[0] ?? null;
269
+ return null;
262
270
  }
263
271
  function removeCharacter(input, charToRemove) {
264
272
  let output = "";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "terminal-pilot",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "description": "Headless terminal session manager with MCP server support",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env tsx
2
- export {};
@@ -1,63 +0,0 @@
1
- #!/usr/bin/env tsx
2
- import readline from "node:readline";
3
- const options = ["Option 1", "Option 2", "Option 3"];
4
- const { stdin, stdout } = process;
5
- let selectedIndex = 0;
6
- let renderedLineCount = 0;
7
- let hasExited = false;
8
- readline.emitKeypressEvents(stdin);
9
- if (stdin.isTTY) {
10
- stdin.setRawMode(true);
11
- }
12
- stdin.resume();
13
- render();
14
- stdin.on("keypress", (_, key) => {
15
- if (key.ctrl && key.name === "c") {
16
- exitWithCode(130);
17
- return;
18
- }
19
- if (key.name === "up") {
20
- selectedIndex = (selectedIndex + options.length - 1) % options.length;
21
- render();
22
- return;
23
- }
24
- if (key.name === "down") {
25
- selectedIndex = (selectedIndex + 1) % options.length;
26
- render();
27
- return;
28
- }
29
- if (key.name === "return" || key.name === "enter") {
30
- cleanup();
31
- stdout.write(`You selected: ${options[selectedIndex]}\n`);
32
- process.exit(0);
33
- }
34
- });
35
- process.on("SIGINT", () => {
36
- exitWithCode(130);
37
- });
38
- function cleanup() {
39
- if (stdin.isTTY) {
40
- stdin.setRawMode(false);
41
- }
42
- stdin.pause();
43
- }
44
- function render() {
45
- if (renderedLineCount > 0) {
46
- readline.moveCursor(stdout, 0, -renderedLineCount);
47
- readline.clearScreenDown(stdout);
48
- }
49
- const lines = [
50
- "Select an option:",
51
- ...options.map((option, index) => `${index === selectedIndex ? ">" : " "} ${option}`)
52
- ];
53
- stdout.write(`${lines.join("\n")}\n`);
54
- renderedLineCount = lines.length;
55
- }
56
- function exitWithCode(code) {
57
- if (hasExited) {
58
- return;
59
- }
60
- hasExited = true;
61
- cleanup();
62
- process.exit(code);
63
- }
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env tsx
2
- export {};
@@ -1,22 +0,0 @@
1
- #!/usr/bin/env tsx
2
- import readline from "node:readline";
3
- const terminal = readline.createInterface({
4
- input: process.stdin,
5
- output: process.stdout
6
- });
7
- let hasGreeted = false;
8
- process.stdout.write("What is your name? ");
9
- terminal.on("line", (name) => {
10
- if (hasGreeted) {
11
- return;
12
- }
13
- hasGreeted = true;
14
- console.log(`Hello, ${name}!`);
15
- terminal.close();
16
- });
17
- terminal.on("close", () => {
18
- if (!hasGreeted) {
19
- console.log(`Hello, ${terminal.line}!`);
20
- }
21
- process.exit(0);
22
- });