@ellery/terminal-mcp 0.1.1

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 (73) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +207 -0
  3. package/dist/client.d.ts +5 -0
  4. package/dist/client.d.ts.map +1 -0
  5. package/dist/client.js +185 -0
  6. package/dist/client.js.map +1 -0
  7. package/dist/index.d.ts +3 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +192 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/prompts/index.d.ts +3 -0
  12. package/dist/prompts/index.d.ts.map +1 -0
  13. package/dist/prompts/index.js +79 -0
  14. package/dist/prompts/index.js.map +1 -0
  15. package/dist/server.d.ts +28 -0
  16. package/dist/server.d.ts.map +1 -0
  17. package/dist/server.js +58 -0
  18. package/dist/server.js.map +1 -0
  19. package/dist/terminal/index.d.ts +4 -0
  20. package/dist/terminal/index.d.ts.map +1 -0
  21. package/dist/terminal/index.js +3 -0
  22. package/dist/terminal/index.js.map +1 -0
  23. package/dist/terminal/manager.d.ts +54 -0
  24. package/dist/terminal/manager.d.ts.map +1 -0
  25. package/dist/terminal/manager.js +79 -0
  26. package/dist/terminal/manager.js.map +1 -0
  27. package/dist/terminal/session.d.ts +85 -0
  28. package/dist/terminal/session.d.ts.map +1 -0
  29. package/dist/terminal/session.js +246 -0
  30. package/dist/terminal/session.js.map +1 -0
  31. package/dist/tools/getContent.d.ts +32 -0
  32. package/dist/tools/getContent.d.ts.map +1 -0
  33. package/dist/tools/getContent.js +38 -0
  34. package/dist/tools/getContent.js.map +1 -0
  35. package/dist/tools/index.d.ts +4 -0
  36. package/dist/tools/index.d.ts.map +1 -0
  37. package/dist/tools/index.js +43 -0
  38. package/dist/tools/index.js.map +1 -0
  39. package/dist/tools/screenshot.d.ts +20 -0
  40. package/dist/tools/screenshot.d.ts.map +1 -0
  41. package/dist/tools/screenshot.js +28 -0
  42. package/dist/tools/screenshot.js.map +1 -0
  43. package/dist/tools/sendKey.d.ts +31 -0
  44. package/dist/tools/sendKey.d.ts.map +1 -0
  45. package/dist/tools/sendKey.js +38 -0
  46. package/dist/tools/sendKey.js.map +1 -0
  47. package/dist/tools/type.d.ts +31 -0
  48. package/dist/tools/type.d.ts.map +1 -0
  49. package/dist/tools/type.js +31 -0
  50. package/dist/tools/type.js.map +1 -0
  51. package/dist/transport/index.d.ts +2 -0
  52. package/dist/transport/index.d.ts.map +1 -0
  53. package/dist/transport/index.js +2 -0
  54. package/dist/transport/index.js.map +1 -0
  55. package/dist/transport/socket.d.ts +30 -0
  56. package/dist/transport/socket.d.ts.map +1 -0
  57. package/dist/transport/socket.js +168 -0
  58. package/dist/transport/socket.js.map +1 -0
  59. package/dist/ui/index.d.ts +24 -0
  60. package/dist/ui/index.d.ts.map +1 -0
  61. package/dist/ui/index.js +124 -0
  62. package/dist/ui/index.js.map +1 -0
  63. package/dist/utils/keys.d.ts +16 -0
  64. package/dist/utils/keys.d.ts.map +1 -0
  65. package/dist/utils/keys.js +98 -0
  66. package/dist/utils/keys.js.map +1 -0
  67. package/dist/utils/stats.d.ts +46 -0
  68. package/dist/utils/stats.d.ts.map +1 -0
  69. package/dist/utils/stats.js +89 -0
  70. package/dist/utils/stats.js.map +1 -0
  71. package/logo.png +0 -0
  72. package/package.json +47 -0
  73. package/tsconfig.json +18 -0
@@ -0,0 +1,124 @@
1
+ const VERSION = "0.1.0";
2
+ // Custom color #31cae1 as 24-bit ANSI escape (RGB: 49, 202, 225)
3
+ const BRAND_COLOR = "\x1b[38;2;49;202;225m";
4
+ // Pink accent color for MCP (RGB: 255, 105, 180 - hot pink)
5
+ const PINK_COLOR = "\x1b[38;2;255;105;180m";
6
+ // Bright yellow for borders (RGB: 255, 255, 0)
7
+ const YELLOW_COLOR = "\x1b[38;2;255;255;0m";
8
+ // White for text content
9
+ const WHITE_COLOR = "\x1b[38;2;255;255;255m";
10
+ const RESET = "\x1b[0m";
11
+ // ANSI Shadow style figlet logo for "TERMINAL" + "MCP" stacked
12
+ const LOGO = `
13
+ ████████╗███████╗██████╗ ███╗ ███╗██╗███╗ ██╗ █████╗ ██╗
14
+ ╚══██╔══╝██╔════╝██╔══██╗████╗ ████║██║████╗ ██║██╔══██╗██║
15
+ ██║ █████╗ ██████╔╝██╔████╔██║██║██╔██╗ ██║███████║██║
16
+ ██║ ██╔══╝ ██╔══██╗██║╚██╔╝██║██║██║╚██╗██║██╔══██║██║
17
+ ██║ ███████╗██║ ██║██║ ╚═╝ ██║██║██║ ╚████║██║ ██║███████╗
18
+ ╚═╝ ╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝╚═╝ ╚═══╝╚═╝ ╚═╝╚══════╝
19
+ ███╗ ███╗ ██████╗██████╗
20
+ ████╗ ████║██╔════╝██╔══██╗
21
+ ██╔████╔██║██║ ██████╔╝
22
+ ██║╚██╔╝██║██║ ██╔═══╝
23
+ ██║ ╚═╝ ██║╚██████╗██║
24
+ ╚═╝ ╚═╝ ╚═════╝╚═╝
25
+ `.trim();
26
+ /**
27
+ * Print the startup banner to stderr (so it doesn't interfere with shell output)
28
+ */
29
+ export function printBanner(options) {
30
+ // Build the logo with box around it
31
+ const logoLines = LOGO.split("\n");
32
+ // Find the widest logo line to determine box width
33
+ const maxLogoWidth = Math.max(...logoLines.map((l) => l.length));
34
+ const boxWidth = maxLogoWidth + 4; // 2 chars padding on each side
35
+ const horizontalLine = "─".repeat(boxWidth);
36
+ const emptyLine = YELLOW_COLOR + "│" + " ".repeat(boxWidth) + "│";
37
+ // Center the logo as a block (same left padding for all lines)
38
+ // First 6 lines are TERMINAL (blue), last 6 lines are MCP (pink)
39
+ const centeredLogo = logoLines.map((line, index) => {
40
+ const rightPad = boxWidth - 2 - line.length;
41
+ const color = index < 6 ? BRAND_COLOR : PINK_COLOR;
42
+ return YELLOW_COLOR + "│ " + color + line + " ".repeat(rightPad) + " " + YELLOW_COLOR + "│";
43
+ });
44
+ const banner = `
45
+ ${YELLOW_COLOR}╭${horizontalLine}╮
46
+ ${centeredLogo.join("\n")}
47
+ ${YELLOW_COLOR}├${horizontalLine}┤
48
+ ${YELLOW_COLOR}│${WHITE_COLOR} Socket: ${padRight(options.socketPath, boxWidth - 11)}${YELLOW_COLOR}│
49
+ ${YELLOW_COLOR}│${WHITE_COLOR} Terminal: ${padRight(`${options.cols}x${options.rows}`, 12)}Shell: ${padRight(options.shell, boxWidth - 30)}${YELLOW_COLOR}│
50
+ ${emptyLine}
51
+ ${YELLOW_COLOR}│${WHITE_COLOR} AI can now observe this terminal via MCP.${" ".repeat(boxWidth - 44)}${YELLOW_COLOR}│
52
+ ${YELLOW_COLOR}│${WHITE_COLOR} Type /info for configuration help.${" ".repeat(boxWidth - 37)}${YELLOW_COLOR}│
53
+ ${YELLOW_COLOR}│${WHITE_COLOR}${" ".repeat(boxWidth - 7)}v${VERSION} ${YELLOW_COLOR}│
54
+ ${YELLOW_COLOR}╰${horizontalLine}╯${RESET}
55
+ `;
56
+ process.stderr.write(banner);
57
+ }
58
+ /**
59
+ * Generate the /info output
60
+ */
61
+ export function getInfoOutput(socketPath, cols, rows, shell, stats) {
62
+ const summary = stats.getSummary();
63
+ const toolCallsStr = Object.keys(summary.toolCalls).length > 0
64
+ ? Object.entries(summary.toolCalls)
65
+ .map(([tool, count]) => ` ${tool}: ${count}`)
66
+ .join("\n")
67
+ : " (none yet)";
68
+ return `
69
+ ${YELLOW_COLOR}╭─────────────────────────────────────────────────────────────╮
70
+ │${WHITE_COLOR} 📡 TERMINAL-MCP INFO ${YELLOW_COLOR}│
71
+ ├─────────────────────────────────────────────────────────────┤${RESET}
72
+
73
+ ${WHITE_COLOR}\x1b[1mSession Info:\x1b[0m${WHITE_COLOR}
74
+ Socket: ${socketPath}
75
+ Terminal: ${cols}x${rows}
76
+ Shell: ${shell}
77
+ Uptime: ${summary.uptime}
78
+ Tool calls: ${summary.totalCalls}
79
+ ${toolCallsStr}
80
+
81
+ \x1b[1mMCP Configuration:\x1b[0m${WHITE_COLOR}
82
+ Add this to your MCP client configuration:
83
+
84
+ ${YELLOW_COLOR}{
85
+ "mcpServers": {
86
+ "terminal": {
87
+ "command": "terminal-mcp"
88
+ }
89
+ }
90
+ }${WHITE_COLOR}
91
+
92
+ Then restart your MCP client to load the server.
93
+
94
+ \x1b[1mAvailable Tools:\x1b[0m${WHITE_COLOR}
95
+ • getContent - Read terminal buffer (visibleOnly=true for current screen)
96
+ • takeScreenshot - Get visible screen + cursor position
97
+ • type - Send text input
98
+ • sendKey - Send special keys (enter, ctrl+c, etc.)
99
+
100
+ ${YELLOW_COLOR}╰─────────────────────────────────────────────────────────────╯${RESET}
101
+ `;
102
+ }
103
+ /**
104
+ * Print the /info output
105
+ */
106
+ export function printInfo(socketPath, cols, rows, shell, stats) {
107
+ process.stdout.write(getInfoOutput(socketPath, cols, rows, shell, stats));
108
+ }
109
+ /**
110
+ * Pad a string to the right with spaces
111
+ */
112
+ function padRight(str, length) {
113
+ if (str.length >= length) {
114
+ return str.substring(0, length - 1) + " ";
115
+ }
116
+ return str + " ".repeat(length - str.length);
117
+ }
118
+ /**
119
+ * Check if input is the /info command
120
+ */
121
+ export function isInfoCommand(input) {
122
+ return input.trim() === "/info";
123
+ }
124
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ui/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Key code mappings for terminal special keys
3
+ * Maps human-readable key names to their ANSI escape sequences
4
+ */
5
+ export declare const KEY_SEQUENCES: Record<string, string>;
6
+ /**
7
+ * Get the escape sequence for a key name
8
+ * @param key - The key name (e.g., "Enter", "Ctrl+C", "ArrowUp")
9
+ * @returns The escape sequence or null if not found
10
+ */
11
+ export declare function getKeySequence(key: string): string | null;
12
+ /**
13
+ * Get all available key names
14
+ */
15
+ export declare function getAvailableKeys(): string[];
16
+ //# sourceMappingURL=keys.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keys.d.ts","sourceRoot":"","sources":["../../src/utils/keys.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAsEhD,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAkBzD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,EAAE,CAE3C"}
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Key code mappings for terminal special keys
3
+ * Maps human-readable key names to their ANSI escape sequences
4
+ */
5
+ export const KEY_SEQUENCES = {
6
+ // Control keys
7
+ "Enter": "\r",
8
+ "Tab": "\t",
9
+ "Escape": "\x1b",
10
+ "Backspace": "\x7f",
11
+ "Delete": "\x1b[3~",
12
+ // Arrow keys
13
+ "ArrowUp": "\x1b[A",
14
+ "ArrowDown": "\x1b[B",
15
+ "ArrowRight": "\x1b[C",
16
+ "ArrowLeft": "\x1b[D",
17
+ // Navigation keys
18
+ "Home": "\x1b[H",
19
+ "End": "\x1b[F",
20
+ "PageUp": "\x1b[5~",
21
+ "PageDown": "\x1b[6~",
22
+ "Insert": "\x1b[2~",
23
+ // Function keys
24
+ "F1": "\x1bOP",
25
+ "F2": "\x1bOQ",
26
+ "F3": "\x1bOR",
27
+ "F4": "\x1bOS",
28
+ "F5": "\x1b[15~",
29
+ "F6": "\x1b[17~",
30
+ "F7": "\x1b[18~",
31
+ "F8": "\x1b[19~",
32
+ "F9": "\x1b[20~",
33
+ "F10": "\x1b[21~",
34
+ "F11": "\x1b[23~",
35
+ "F12": "\x1b[24~",
36
+ // Ctrl combinations
37
+ "Ctrl+A": "\x01",
38
+ "Ctrl+B": "\x02",
39
+ "Ctrl+C": "\x03",
40
+ "Ctrl+D": "\x04",
41
+ "Ctrl+E": "\x05",
42
+ "Ctrl+F": "\x06",
43
+ "Ctrl+G": "\x07",
44
+ "Ctrl+H": "\x08",
45
+ "Ctrl+I": "\x09",
46
+ "Ctrl+J": "\x0a",
47
+ "Ctrl+K": "\x0b",
48
+ "Ctrl+L": "\x0c",
49
+ "Ctrl+M": "\x0d",
50
+ "Ctrl+N": "\x0e",
51
+ "Ctrl+O": "\x0f",
52
+ "Ctrl+P": "\x10",
53
+ "Ctrl+Q": "\x11",
54
+ "Ctrl+R": "\x12",
55
+ "Ctrl+S": "\x13",
56
+ "Ctrl+T": "\x14",
57
+ "Ctrl+U": "\x15",
58
+ "Ctrl+V": "\x16",
59
+ "Ctrl+W": "\x17",
60
+ "Ctrl+X": "\x18",
61
+ "Ctrl+Y": "\x19",
62
+ "Ctrl+Z": "\x1a",
63
+ "Ctrl+[": "\x1b",
64
+ "Ctrl+\\": "\x1c",
65
+ "Ctrl+]": "\x1d",
66
+ "Ctrl+^": "\x1e",
67
+ "Ctrl+_": "\x1f",
68
+ // Common shortcuts
69
+ "Ctrl+Space": "\x00",
70
+ };
71
+ /**
72
+ * Get the escape sequence for a key name
73
+ * @param key - The key name (e.g., "Enter", "Ctrl+C", "ArrowUp")
74
+ * @returns The escape sequence or null if not found
75
+ */
76
+ export function getKeySequence(key) {
77
+ // Normalize key name
78
+ const normalized = key.trim();
79
+ // Check direct match
80
+ if (KEY_SEQUENCES[normalized]) {
81
+ return KEY_SEQUENCES[normalized];
82
+ }
83
+ // Check case-insensitive match
84
+ const lowerKey = normalized.toLowerCase();
85
+ for (const [name, seq] of Object.entries(KEY_SEQUENCES)) {
86
+ if (name.toLowerCase() === lowerKey) {
87
+ return seq;
88
+ }
89
+ }
90
+ return null;
91
+ }
92
+ /**
93
+ * Get all available key names
94
+ */
95
+ export function getAvailableKeys() {
96
+ return Object.keys(KEY_SEQUENCES);
97
+ }
98
+ //# sourceMappingURL=keys.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keys.js","sourceRoot":"","sources":["../../src/utils/keys.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,CAAC,MAAM,aAAa,GAA2B;IACnD,eAAe;IACf,OAAO,EAAE,IAAI;IACb,KAAK,EAAE,IAAI;IACX,QAAQ,EAAE,MAAM;IAChB,WAAW,EAAE,MAAM;IACnB,QAAQ,EAAE,SAAS;IAEnB,aAAa;IACb,SAAS,EAAE,QAAQ;IACnB,WAAW,EAAE,QAAQ;IACrB,YAAY,EAAE,QAAQ;IACtB,WAAW,EAAE,QAAQ;IAErB,kBAAkB;IAClB,MAAM,EAAE,QAAQ;IAChB,KAAK,EAAE,QAAQ;IACf,QAAQ,EAAE,SAAS;IACnB,UAAU,EAAE,SAAS;IACrB,QAAQ,EAAE,SAAS;IAEnB,gBAAgB;IAChB,IAAI,EAAE,QAAQ;IACd,IAAI,EAAE,QAAQ;IACd,IAAI,EAAE,QAAQ;IACd,IAAI,EAAE,QAAQ;IACd,IAAI,EAAE,UAAU;IAChB,IAAI,EAAE,UAAU;IAChB,IAAI,EAAE,UAAU;IAChB,IAAI,EAAE,UAAU;IAChB,IAAI,EAAE,UAAU;IAChB,KAAK,EAAE,UAAU;IACjB,KAAK,EAAE,UAAU;IACjB,KAAK,EAAE,UAAU;IAEjB,oBAAoB;IACpB,QAAQ,EAAE,MAAM;IAChB,QAAQ,EAAE,MAAM;IAChB,QAAQ,EAAE,MAAM;IAChB,QAAQ,EAAE,MAAM;IAChB,QAAQ,EAAE,MAAM;IAChB,QAAQ,EAAE,MAAM;IAChB,QAAQ,EAAE,MAAM;IAChB,QAAQ,EAAE,MAAM;IAChB,QAAQ,EAAE,MAAM;IAChB,QAAQ,EAAE,MAAM;IAChB,QAAQ,EAAE,MAAM;IAChB,QAAQ,EAAE,MAAM;IAChB,QAAQ,EAAE,MAAM;IAChB,QAAQ,EAAE,MAAM;IAChB,QAAQ,EAAE,MAAM;IAChB,QAAQ,EAAE,MAAM;IAChB,QAAQ,EAAE,MAAM;IAChB,QAAQ,EAAE,MAAM;IAChB,QAAQ,EAAE,MAAM;IAChB,QAAQ,EAAE,MAAM;IAChB,QAAQ,EAAE,MAAM;IAChB,QAAQ,EAAE,MAAM;IAChB,QAAQ,EAAE,MAAM;IAChB,QAAQ,EAAE,MAAM;IAChB,QAAQ,EAAE,MAAM;IAChB,QAAQ,EAAE,MAAM;IAChB,QAAQ,EAAE,MAAM;IAChB,SAAS,EAAE,MAAM;IACjB,QAAQ,EAAE,MAAM;IAChB,QAAQ,EAAE,MAAM;IAChB,QAAQ,EAAE,MAAM;IAEhB,mBAAmB;IACnB,YAAY,EAAE,MAAM;CACrB,CAAC;AAEF;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,GAAW;IACxC,qBAAqB;IACrB,MAAM,UAAU,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IAE9B,qBAAqB;IACrB,IAAI,aAAa,CAAC,UAAU,CAAC,EAAE,CAAC;QAC9B,OAAO,aAAa,CAAC,UAAU,CAAC,CAAC;IACnC,CAAC;IAED,+BAA+B;IAC/B,MAAM,QAAQ,GAAG,UAAU,CAAC,WAAW,EAAE,CAAC;IAC1C,KAAK,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,EAAE,CAAC;QACxD,IAAI,IAAI,CAAC,WAAW,EAAE,KAAK,QAAQ,EAAE,CAAC;YACpC,OAAO,GAAG,CAAC;QACb,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB;IAC9B,OAAO,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;AACpC,CAAC"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Simple stats tracking for terminal MCP sessions
3
+ */
4
+ export declare class Stats {
5
+ private startTime;
6
+ private toolCalls;
7
+ private totalCalls;
8
+ constructor();
9
+ /**
10
+ * Record a tool call
11
+ */
12
+ recordToolCall(toolName: string): void;
13
+ /**
14
+ * Get uptime in seconds
15
+ */
16
+ getUptimeSeconds(): number;
17
+ /**
18
+ * Get formatted uptime string
19
+ */
20
+ getFormattedUptime(): string;
21
+ /**
22
+ * Get total tool calls
23
+ */
24
+ getTotalCalls(): number;
25
+ /**
26
+ * Get tool calls breakdown
27
+ */
28
+ getToolCallsBreakdown(): Map<string, number>;
29
+ /**
30
+ * Get stats summary
31
+ */
32
+ getSummary(): {
33
+ uptime: string;
34
+ totalCalls: number;
35
+ toolCalls: Record<string, number>;
36
+ };
37
+ }
38
+ /**
39
+ * Get or create the global stats instance
40
+ */
41
+ export declare function getStats(): Stats;
42
+ /**
43
+ * Reset stats (mainly for testing)
44
+ */
45
+ export declare function resetStats(): void;
46
+ //# sourceMappingURL=stats.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stats.d.ts","sourceRoot":"","sources":["../../src/utils/stats.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,KAAK;IAChB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,SAAS,CAAsB;IACvC,OAAO,CAAC,UAAU,CAAS;;IAQ3B;;OAEG;IACH,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAMtC;;OAEG;IACH,gBAAgB,IAAI,MAAM;IAI1B;;OAEG;IACH,kBAAkB,IAAI,MAAM;IAe5B;;OAEG;IACH,aAAa,IAAI,MAAM;IAIvB;;OAEG;IACH,qBAAqB,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC;IAI5C;;OAEG;IACH,UAAU,IAAI;QACZ,MAAM,EAAE,MAAM,CAAC;QACf,UAAU,EAAE,MAAM,CAAC;QACnB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KACnC;CAWF;AAKD;;GAEG;AACH,wBAAgB,QAAQ,IAAI,KAAK,CAKhC;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI,IAAI,CAEjC"}
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Simple stats tracking for terminal MCP sessions
3
+ */
4
+ export class Stats {
5
+ startTime;
6
+ toolCalls;
7
+ totalCalls;
8
+ constructor() {
9
+ this.startTime = Date.now();
10
+ this.toolCalls = new Map();
11
+ this.totalCalls = 0;
12
+ }
13
+ /**
14
+ * Record a tool call
15
+ */
16
+ recordToolCall(toolName) {
17
+ const current = this.toolCalls.get(toolName) || 0;
18
+ this.toolCalls.set(toolName, current + 1);
19
+ this.totalCalls++;
20
+ }
21
+ /**
22
+ * Get uptime in seconds
23
+ */
24
+ getUptimeSeconds() {
25
+ return Math.floor((Date.now() - this.startTime) / 1000);
26
+ }
27
+ /**
28
+ * Get formatted uptime string
29
+ */
30
+ getFormattedUptime() {
31
+ const seconds = this.getUptimeSeconds();
32
+ const hours = Math.floor(seconds / 3600);
33
+ const minutes = Math.floor((seconds % 3600) / 60);
34
+ const secs = seconds % 60;
35
+ if (hours > 0) {
36
+ return `${hours}h ${minutes}m ${secs}s`;
37
+ }
38
+ else if (minutes > 0) {
39
+ return `${minutes}m ${secs}s`;
40
+ }
41
+ else {
42
+ return `${secs}s`;
43
+ }
44
+ }
45
+ /**
46
+ * Get total tool calls
47
+ */
48
+ getTotalCalls() {
49
+ return this.totalCalls;
50
+ }
51
+ /**
52
+ * Get tool calls breakdown
53
+ */
54
+ getToolCallsBreakdown() {
55
+ return new Map(this.toolCalls);
56
+ }
57
+ /**
58
+ * Get stats summary
59
+ */
60
+ getSummary() {
61
+ const toolCalls = {};
62
+ for (const [tool, count] of this.toolCalls) {
63
+ toolCalls[tool] = count;
64
+ }
65
+ return {
66
+ uptime: this.getFormattedUptime(),
67
+ totalCalls: this.totalCalls,
68
+ toolCalls,
69
+ };
70
+ }
71
+ }
72
+ // Global stats instance
73
+ let globalStats = null;
74
+ /**
75
+ * Get or create the global stats instance
76
+ */
77
+ export function getStats() {
78
+ if (!globalStats) {
79
+ globalStats = new Stats();
80
+ }
81
+ return globalStats;
82
+ }
83
+ /**
84
+ * Reset stats (mainly for testing)
85
+ */
86
+ export function resetStats() {
87
+ globalStats = new Stats();
88
+ }
89
+ //# sourceMappingURL=stats.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stats.js","sourceRoot":"","sources":["../../src/utils/stats.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,OAAO,KAAK;IACR,SAAS,CAAS;IAClB,SAAS,CAAsB;IAC/B,UAAU,CAAS;IAE3B;QACE,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC5B,IAAI,CAAC,SAAS,GAAG,IAAI,GAAG,EAAE,CAAC;QAC3B,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC;IACtB,CAAC;IAED;;OAEG;IACH,cAAc,CAAC,QAAgB;QAC7B,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAClD,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,GAAG,CAAC,CAAC,CAAC;QAC1C,IAAI,CAAC,UAAU,EAAE,CAAC;IACpB,CAAC;IAED;;OAEG;IACH,gBAAgB;QACd,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,CAAC;IAC1D,CAAC;IAED;;OAEG;IACH,kBAAkB;QAChB,MAAM,OAAO,GAAG,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACxC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;QACzC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;QAClD,MAAM,IAAI,GAAG,OAAO,GAAG,EAAE,CAAC;QAE1B,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;YACd,OAAO,GAAG,KAAK,KAAK,OAAO,KAAK,IAAI,GAAG,CAAC;QAC1C,CAAC;aAAM,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;YACvB,OAAO,GAAG,OAAO,KAAK,IAAI,GAAG,CAAC;QAChC,CAAC;aAAM,CAAC;YACN,OAAO,GAAG,IAAI,GAAG,CAAC;QACpB,CAAC;IACH,CAAC;IAED;;OAEG;IACH,aAAa;QACX,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;IAED;;OAEG;IACH,qBAAqB;QACnB,OAAO,IAAI,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACjC,CAAC;IAED;;OAEG;IACH,UAAU;QAKR,MAAM,SAAS,GAA2B,EAAE,CAAC;QAC7C,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YAC3C,SAAS,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;QAC1B,CAAC;QACD,OAAO;YACL,MAAM,EAAE,IAAI,CAAC,kBAAkB,EAAE;YACjC,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,SAAS;SACV,CAAC;IACJ,CAAC;CACF;AAED,wBAAwB;AACxB,IAAI,WAAW,GAAiB,IAAI,CAAC;AAErC;;GAEG;AACH,MAAM,UAAU,QAAQ;IACtB,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,WAAW,GAAG,IAAI,KAAK,EAAE,CAAC;IAC5B,CAAC;IACD,OAAO,WAAW,CAAC;AACrB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU;IACxB,WAAW,GAAG,IAAI,KAAK,EAAE,CAAC;AAC5B,CAAC"}
package/logo.png ADDED
Binary file
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@ellery/terminal-mcp",
3
+ "version": "0.1.1",
4
+ "description": "A headless terminal emulator exposed via MCP for AI assistants",
5
+ "author": "Ellery Familia",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/elleryfamilia/terminal-mcp.git"
9
+ },
10
+ "bugs": {
11
+ "url": "https://github.com/elleryfamilia/terminal-mcp/issues"
12
+ },
13
+ "homepage": "https://github.com/elleryfamilia/terminal-mcp#readme",
14
+ "type": "module",
15
+ "main": "dist/index.js",
16
+ "bin": {
17
+ "terminal-mcp": "dist/index.js"
18
+ },
19
+ "scripts": {
20
+ "build": "tsc",
21
+ "dev": "tsx src/index.ts",
22
+ "prepare": "npm run build"
23
+ },
24
+ "dependencies": {
25
+ "@modelcontextprotocol/sdk": "^1.0.0",
26
+ "@xterm/headless": "^5.3.0",
27
+ "node-pty": "^0.10.1",
28
+ "zod": "^3.23.0"
29
+ },
30
+ "devDependencies": {
31
+ "@types/node": "^20.0.0",
32
+ "tsx": "^4.0.0",
33
+ "typescript": "^5.0.0"
34
+ },
35
+ "engines": {
36
+ "node": ">=18.0.0"
37
+ },
38
+ "keywords": [
39
+ "mcp",
40
+ "terminal",
41
+ "pty",
42
+ "xterm",
43
+ "ai",
44
+ "claude"
45
+ ],
46
+ "license": "MIT"
47
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,18 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "NodeNext",
5
+ "moduleResolution": "NodeNext",
6
+ "outDir": "dist",
7
+ "rootDir": "src",
8
+ "strict": true,
9
+ "esModuleInterop": true,
10
+ "skipLibCheck": true,
11
+ "forceConsistentCasingInFileNames": true,
12
+ "declaration": true,
13
+ "declarationMap": true,
14
+ "sourceMap": true
15
+ },
16
+ "include": ["src/**/*"],
17
+ "exclude": ["node_modules", "dist"]
18
+ }