@ellery/terminal-mcp 0.1.1 → 0.2.0
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/LICENSE +1 -1
- package/README.md +14 -33
- package/dist/index.js +23 -42
- package/dist/index.js.map +1 -1
- package/dist/terminal/session.d.ts +1 -0
- package/dist/terminal/session.d.ts.map +1 -1
- package/dist/terminal/session.js +29 -4
- package/dist/terminal/session.js.map +1 -1
- package/dist/tools/type.js +1 -1
- package/dist/tools/type.js.map +1 -1
- package/dist/ui/index.d.ts +2 -15
- package/dist/ui/index.d.ts.map +1 -1
- package/dist/ui/index.js +16 -62
- package/dist/ui/index.js.map +1 -1
- package/dist/utils/platform.d.ts +10 -0
- package/dist/utils/platform.d.ts.map +1 -0
- package/dist/utils/platform.js +22 -0
- package/dist/utils/platform.js.map +1 -0
- package/package.json +2 -2
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -3,10 +3,20 @@
|
|
|
3
3
|
</p>
|
|
4
4
|
|
|
5
5
|
<p align="center">
|
|
6
|
-
|
|
6
|
+
<strong>Let AI see and interact with your terminal.</strong>
|
|
7
7
|
</p>
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
<p align="center">
|
|
10
|
+
Terminal MCP gives LLMs a shared view of your terminal session. Perfect for debugging CLIs and TUI applications in real-time, or letting AI drive terminal-based tools autonomously.
|
|
11
|
+
</p>
|
|
12
|
+
|
|
13
|
+
## Install
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install -g @ellery/terminal-mcp
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Or via install script:
|
|
10
20
|
|
|
11
21
|
```bash
|
|
12
22
|
curl -fsSL https://raw.githubusercontent.com/elleryfamilia/terminal-mcp/main/install.sh | bash
|
|
@@ -19,13 +29,10 @@ curl -fsSL https://raw.githubusercontent.com/elleryfamilia/terminal-mcp/main/ins
|
|
|
19
29
|
- **MCP Protocol**: Implements Model Context Protocol for AI assistant integration
|
|
20
30
|
- **Simple API**: Four intuitive tools for complete terminal control
|
|
21
31
|
|
|
22
|
-
##
|
|
32
|
+
## Building from Source
|
|
23
33
|
|
|
24
34
|
```bash
|
|
25
|
-
# Install dependencies
|
|
26
35
|
npm install
|
|
27
|
-
|
|
28
|
-
# Build
|
|
29
36
|
npm run build
|
|
30
37
|
```
|
|
31
38
|
|
|
@@ -155,32 +162,6 @@ Terminal MCP Server (Node.js)
|
|
|
155
162
|
|
|
156
163
|
## Development
|
|
157
164
|
|
|
158
|
-
### Project Structure
|
|
159
|
-
|
|
160
|
-
```
|
|
161
|
-
terminal-mcp/
|
|
162
|
-
├── src/
|
|
163
|
-
│ ├── index.ts # Entry point with CLI
|
|
164
|
-
│ ├── server.ts # MCP server setup
|
|
165
|
-
│ ├── terminal/
|
|
166
|
-
│ │ ├── index.ts # Exports
|
|
167
|
-
│ │ ├── session.ts # PTY + xterm integration
|
|
168
|
-
│ │ └── manager.ts # Session lifecycle
|
|
169
|
-
│ ├── tools/
|
|
170
|
-
│ │ ├── index.ts # Tool registry
|
|
171
|
-
│ │ ├── type.ts # type tool
|
|
172
|
-
│ │ ├── sendKey.ts # sendKey tool
|
|
173
|
-
│ │ ├── getContent.ts # getContent tool
|
|
174
|
-
│ │ └── screenshot.ts # takeScreenshot tool
|
|
175
|
-
│ └── utils/
|
|
176
|
-
│ └── keys.ts # Key code mappings
|
|
177
|
-
├── docs/ # Documentation
|
|
178
|
-
├── package.json
|
|
179
|
-
└── tsconfig.json
|
|
180
|
-
```
|
|
181
|
-
|
|
182
|
-
### Building
|
|
183
|
-
|
|
184
165
|
```bash
|
|
185
166
|
npm run build # Compile TypeScript
|
|
186
167
|
npm run dev # Run with tsx (development)
|
|
@@ -200,7 +181,7 @@ See the [docs](./docs/) folder for detailed documentation:
|
|
|
200
181
|
## Requirements
|
|
201
182
|
|
|
202
183
|
- Node.js 18.0.0 or later
|
|
203
|
-
-
|
|
184
|
+
- Windows 10 version 1809 or later (for ConPTY support)
|
|
204
185
|
|
|
205
186
|
## License
|
|
206
187
|
|
package/dist/index.js
CHANGED
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import * as fs from "fs";
|
|
3
|
-
import * as path from "path";
|
|
4
|
-
import * as os from "os";
|
|
5
3
|
import { startMcpClientMode } from "./client.js";
|
|
6
4
|
import { TerminalManager } from "./terminal/index.js";
|
|
7
5
|
import { createToolProxyServer } from "./transport/index.js";
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
6
|
+
import { getBanner } from "./ui/index.js";
|
|
7
|
+
import { getDefaultSocketPath, getDefaultShell } from "./utils/platform.js";
|
|
10
8
|
// Default socket path
|
|
11
|
-
const DEFAULT_SOCKET_PATH =
|
|
9
|
+
const DEFAULT_SOCKET_PATH = getDefaultSocketPath();
|
|
12
10
|
// Parse command line arguments
|
|
13
11
|
const args = process.argv.slice(2);
|
|
14
12
|
const options = {};
|
|
@@ -62,7 +60,6 @@ Interactive Mode (run in your terminal):
|
|
|
62
60
|
terminal-mcp
|
|
63
61
|
|
|
64
62
|
This gives you an interactive shell. AI can observe/interact via MCP.
|
|
65
|
-
Type /info for the MCP configuration to add to your MCP client.
|
|
66
63
|
|
|
67
64
|
MCP Client Mode (add to your MCP client config):
|
|
68
65
|
{
|
|
@@ -89,26 +86,39 @@ async function main() {
|
|
|
89
86
|
}
|
|
90
87
|
}
|
|
91
88
|
async function startInteractiveMode(socketPath) {
|
|
92
|
-
// Initialize stats
|
|
93
|
-
resetStats();
|
|
94
89
|
// Get terminal size from environment or use defaults
|
|
95
90
|
const cols = options.cols ?? (process.stdout.columns || 120);
|
|
96
91
|
const rows = options.rows ?? (process.stdout.rows || 40);
|
|
97
|
-
const shell = options.shell ||
|
|
98
|
-
//
|
|
99
|
-
|
|
92
|
+
const shell = options.shell || getDefaultShell();
|
|
93
|
+
// Generate startup banner
|
|
94
|
+
const startupBanner = getBanner({ socketPath, cols, rows, shell });
|
|
100
95
|
// Create terminal manager (prompt customization handled in session.ts)
|
|
101
96
|
const manager = new TerminalManager({
|
|
102
97
|
cols,
|
|
103
98
|
rows,
|
|
104
99
|
shell: options.shell,
|
|
100
|
+
startupBanner,
|
|
105
101
|
});
|
|
106
102
|
// Get the session and set up interactive I/O
|
|
107
103
|
const session = manager.getSession();
|
|
104
|
+
// Track if we've shown the banner (for Windows, show after shell init)
|
|
105
|
+
let bannerShown = false;
|
|
106
|
+
const isWindows = process.platform === "win32";
|
|
108
107
|
// Pipe PTY output to stdout
|
|
109
108
|
session.onData((data) => {
|
|
110
109
|
process.stdout.write(data);
|
|
110
|
+
// On Windows, show banner after first prompt appears
|
|
111
|
+
if (isWindows && !bannerShown && data.includes("⚡")) {
|
|
112
|
+
bannerShown = true;
|
|
113
|
+
process.stdout.write("\n" + startupBanner + "\n");
|
|
114
|
+
// Send Enter to get a fresh prompt
|
|
115
|
+
session.write("\r");
|
|
116
|
+
}
|
|
111
117
|
});
|
|
118
|
+
// On non-Windows, banner is shown via shell rc file
|
|
119
|
+
if (!isWindows) {
|
|
120
|
+
bannerShown = true;
|
|
121
|
+
}
|
|
112
122
|
// Handle PTY exit
|
|
113
123
|
session.onExit((code) => {
|
|
114
124
|
console.log(`\n[terminal-mcp] Shell exited with code ${code}`);
|
|
@@ -120,38 +130,9 @@ async function startInteractiveMode(socketPath) {
|
|
|
120
130
|
process.stdin.setRawMode(true);
|
|
121
131
|
}
|
|
122
132
|
process.stdin.resume();
|
|
123
|
-
//
|
|
124
|
-
let inputBuffer = "";
|
|
125
|
-
// Pipe stdin to PTY, with /info command detection
|
|
133
|
+
// Pipe stdin directly to PTY
|
|
126
134
|
process.stdin.on("data", (data) => {
|
|
127
|
-
|
|
128
|
-
// Check for /info command (detect when user types /info and presses enter)
|
|
129
|
-
// In raw mode, we need to buffer input to detect the command
|
|
130
|
-
for (const char of str) {
|
|
131
|
-
if (char === "\r" || char === "\n") {
|
|
132
|
-
// Check if buffer is /info command
|
|
133
|
-
if (isInfoCommand(inputBuffer)) {
|
|
134
|
-
// Print info and clear the line
|
|
135
|
-
process.stdout.write("\r\n");
|
|
136
|
-
printInfo(socketPath, cols, rows, shell, getStats());
|
|
137
|
-
inputBuffer = "";
|
|
138
|
-
// Write newline to shell to maintain prompt
|
|
139
|
-
session.write("\n");
|
|
140
|
-
continue;
|
|
141
|
-
}
|
|
142
|
-
inputBuffer = "";
|
|
143
|
-
session.write(char);
|
|
144
|
-
}
|
|
145
|
-
else if (char === "\x7f" || char === "\b") {
|
|
146
|
-
// Backspace
|
|
147
|
-
inputBuffer = inputBuffer.slice(0, -1);
|
|
148
|
-
session.write(char);
|
|
149
|
-
}
|
|
150
|
-
else {
|
|
151
|
-
inputBuffer += char;
|
|
152
|
-
session.write(char);
|
|
153
|
-
}
|
|
154
|
-
}
|
|
135
|
+
session.write(data.toString());
|
|
155
136
|
});
|
|
156
137
|
// Handle terminal resize
|
|
157
138
|
process.stdout.on("resize", () => {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/terminal/session.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/terminal/session.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,sBAAsB;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE;QACN,CAAC,EAAE,MAAM,CAAC;QACV,CAAC,EAAE,MAAM,CAAC;KACX,CAAC;IACF,UAAU,EAAE;QACV,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;CACH;AAED;;;GAGG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,UAAU,CAAW;IAC7B,OAAO,CAAC,QAAQ,CAAgC;IAChD,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,aAAa,CAAqC;IAC1D,OAAO,CAAC,aAAa,CAAqC;IAE1D,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,OAAO,CAAuB;IAEtC;;;OAGG;IACH,OAAO,CAAC,gBAAgB;gBA6EZ,OAAO,GAAE,sBAA2B;IA6ChD;;OAEG;IACH,MAAM,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI;IAI9C;;OAEG;IACH,MAAM,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI;IAI9C;;OAEG;IACH,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAOzB;;OAEG;IACH,UAAU,IAAI,MAAM;IAwBpB;;OAEG;IACH,iBAAiB,IAAI,MAAM;IAmB3B;;OAEG;IACH,cAAc,IAAI,gBAAgB;IAoBlC;;OAEG;IACH,KAAK,IAAI,IAAI;IAOb;;OAEG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAQxC;;OAEG;IACH,QAAQ,IAAI,OAAO;IAInB;;OAEG;IACH,aAAa,IAAI;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE;IAO/C;;OAEG;IACH,OAAO,IAAI,IAAI;CAuBhB"}
|
package/dist/terminal/session.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import * as pty from "node-pty";
|
|
1
|
+
import * as pty from "@homebridge/node-pty-prebuilt-multiarch";
|
|
2
2
|
import * as fs from "fs";
|
|
3
3
|
import * as os from "os";
|
|
4
4
|
import * as path from "path";
|
|
5
5
|
import xtermHeadless from "@xterm/headless";
|
|
6
6
|
const { Terminal } = xtermHeadless;
|
|
7
|
+
import { getDefaultShell } from "../utils/platform.js";
|
|
7
8
|
// Custom prompt indicator for terminal-mcp
|
|
8
9
|
const PROMPT_INDICATOR = "⚡";
|
|
9
10
|
/**
|
|
@@ -22,19 +23,27 @@ export class TerminalSession {
|
|
|
22
23
|
* Set up shell-specific prompt customization
|
|
23
24
|
* Returns args to pass to shell and env modifications
|
|
24
25
|
*/
|
|
25
|
-
setupShellPrompt(shellName, extraEnv) {
|
|
26
|
+
setupShellPrompt(shellName, extraEnv, startupBanner) {
|
|
26
27
|
const env = {
|
|
27
28
|
TERMINAL_MCP: "1",
|
|
28
29
|
...extraEnv,
|
|
29
30
|
};
|
|
31
|
+
// Escape banner for use in shell scripts
|
|
32
|
+
const escapeBannerForShell = (banner) => {
|
|
33
|
+
// Escape single quotes and backslashes for shell
|
|
34
|
+
return banner.replace(/'/g, "'\\''");
|
|
35
|
+
};
|
|
30
36
|
if (shellName === "bash" || shellName === "sh") {
|
|
31
37
|
// Create temp rcfile that sources user's .bashrc then sets our prompt
|
|
32
38
|
const homeDir = os.homedir();
|
|
39
|
+
const bannerCmd = startupBanner ? `printf '%s\\n' '${escapeBannerForShell(startupBanner)}'` : "";
|
|
33
40
|
const bashrcContent = `
|
|
34
41
|
# Source user's bashrc if it exists
|
|
35
42
|
[ -f "${homeDir}/.bashrc" ] && source "${homeDir}/.bashrc"
|
|
36
43
|
# Set terminal-mcp prompt
|
|
37
44
|
PS1="${PROMPT_INDICATOR} \\$ "
|
|
45
|
+
# Print startup banner
|
|
46
|
+
${bannerCmd}
|
|
38
47
|
`;
|
|
39
48
|
this.rcFile = path.join(os.tmpdir(), `terminal-mcp-bashrc-${process.pid}`);
|
|
40
49
|
fs.writeFileSync(this.rcFile, bashrcContent);
|
|
@@ -45,6 +54,7 @@ PS1="${PROMPT_INDICATOR} \\$ "
|
|
|
45
54
|
const homeDir = os.homedir();
|
|
46
55
|
this.zdotdir = path.join(os.tmpdir(), `terminal-mcp-zsh-${process.pid}`);
|
|
47
56
|
fs.mkdirSync(this.zdotdir, { recursive: true });
|
|
57
|
+
const bannerCmd = startupBanner ? `printf '%s\\n' '${escapeBannerForShell(startupBanner)}'` : "";
|
|
48
58
|
const zshrcContent = `
|
|
49
59
|
# Reset ZDOTDIR so nested zsh uses normal config
|
|
50
60
|
export ZDOTDIR="${homeDir}"
|
|
@@ -52,11 +62,26 @@ export ZDOTDIR="${homeDir}"
|
|
|
52
62
|
[ -f "${homeDir}/.zshrc" ] && source "${homeDir}/.zshrc"
|
|
53
63
|
# Set terminal-mcp prompt
|
|
54
64
|
PROMPT="${PROMPT_INDICATOR} %# "
|
|
65
|
+
# Print startup banner
|
|
66
|
+
${bannerCmd}
|
|
55
67
|
`;
|
|
56
68
|
fs.writeFileSync(path.join(this.zdotdir, ".zshrc"), zshrcContent);
|
|
57
69
|
env.ZDOTDIR = this.zdotdir;
|
|
58
70
|
return { args: [], env };
|
|
59
71
|
}
|
|
72
|
+
// PowerShell (pwsh is PowerShell Core, powershell is Windows PowerShell)
|
|
73
|
+
if (shellName === "powershell" ||
|
|
74
|
+
shellName === "powershell.exe" ||
|
|
75
|
+
shellName === "pwsh" ||
|
|
76
|
+
shellName === "pwsh.exe") {
|
|
77
|
+
env.TERMINAL_MCP_PROMPT = "1";
|
|
78
|
+
return { args: ["-NoLogo"], env };
|
|
79
|
+
}
|
|
80
|
+
// Windows cmd.exe
|
|
81
|
+
if (shellName === "cmd" || shellName === "cmd.exe") {
|
|
82
|
+
env.PROMPT = `${PROMPT_INDICATOR} $P$G`;
|
|
83
|
+
return { args: [], env };
|
|
84
|
+
}
|
|
60
85
|
// For other shells, just set env vars and hope for the best
|
|
61
86
|
env.PS1 = `${PROMPT_INDICATOR} $ `;
|
|
62
87
|
return { args: [], env };
|
|
@@ -64,7 +89,7 @@ PROMPT="${PROMPT_INDICATOR} %# "
|
|
|
64
89
|
constructor(options = {}) {
|
|
65
90
|
const cols = options.cols ?? 120;
|
|
66
91
|
const rows = options.rows ?? 40;
|
|
67
|
-
const shell = options.shell ??
|
|
92
|
+
const shell = options.shell ?? getDefaultShell();
|
|
68
93
|
// Create headless terminal emulator
|
|
69
94
|
this.terminal = new Terminal({
|
|
70
95
|
cols,
|
|
@@ -74,7 +99,7 @@ PROMPT="${PROMPT_INDICATOR} %# "
|
|
|
74
99
|
});
|
|
75
100
|
// Determine shell type and set up custom prompt
|
|
76
101
|
const shellName = path.basename(shell);
|
|
77
|
-
const { args, env } = this.setupShellPrompt(shellName, options.env);
|
|
102
|
+
const { args, env } = this.setupShellPrompt(shellName, options.env, options.startupBanner);
|
|
78
103
|
// Spawn PTY process
|
|
79
104
|
this.ptyProcess = pty.spawn(shell, args, {
|
|
80
105
|
name: "xterm-256color",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/terminal/session.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/terminal/session.ts"],"names":[],"mappings":"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"}
|
package/dist/tools/type.js
CHANGED
|
@@ -4,7 +4,7 @@ export const typeSchema = z.object({
|
|
|
4
4
|
});
|
|
5
5
|
export const typeTool = {
|
|
6
6
|
name: "type",
|
|
7
|
-
description: "Send text input to the terminal. Text is written exactly as provided - no Enter key is sent automatically. To execute a command, use type() followed by sendKey('Enter'). Example workflow: type('ls -la') → sendKey('Enter') → getContent()",
|
|
7
|
+
description: "Send text input to the terminal. Text is written exactly as provided - no Enter key is sent automatically. To execute a command, use type() followed by sendKey('Enter'). Example workflow: type('ls -la') → sendKey('Enter') → getContent(). IMPORTANT: In zsh, avoid '!' inside double quotes as it triggers history expansion - use single quotes instead (e.g., echo 'Hello!' not echo \"Hello!\").",
|
|
8
8
|
inputSchema: {
|
|
9
9
|
type: "object",
|
|
10
10
|
properties: {
|
package/dist/tools/type.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"type.js","sourceRoot":"","sources":["../../src/tools/type.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAC,MAAM,CAAC;IACjC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,oCAAoC,CAAC;CAChE,CAAC,CAAC;AAIH,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,IAAI,EAAE,MAAM;IACZ,WAAW,EAAE,
|
|
1
|
+
{"version":3,"file":"type.js","sourceRoot":"","sources":["../../src/tools/type.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAC,MAAM,CAAC;IACjC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,oCAAoC,CAAC;CAChE,CAAC,CAAC;AAIH,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,IAAI,EAAE,MAAM;IACZ,WAAW,EAAE,yYAAyY;IACtZ,WAAW,EAAE;QACX,IAAI,EAAE,QAAiB;QACvB,UAAU,EAAE;YACV,IAAI,EAAE;gBACJ,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,oCAAoC;aAClD;SACF;QACD,QAAQ,EAAE,CAAC,MAAM,CAAC;KACnB;CACF,CAAC;AAEF,MAAM,UAAU,UAAU,CAAC,OAAwB,EAAE,IAAa;IAChE,MAAM,MAAM,GAAG,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACtC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAE3B,OAAO;QACL,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,SAAS,MAAM,CAAC,IAAI,CAAC,MAAM,2BAA2B;aAC7D;SACF;KACF,CAAC;AACJ,CAAC"}
|
package/dist/ui/index.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { Stats } from "../utils/stats.js";
|
|
2
1
|
export interface BannerOptions {
|
|
3
2
|
socketPath: string;
|
|
4
3
|
cols: number;
|
|
@@ -6,19 +5,7 @@ export interface BannerOptions {
|
|
|
6
5
|
shell: string;
|
|
7
6
|
}
|
|
8
7
|
/**
|
|
9
|
-
*
|
|
8
|
+
* Generate the startup banner string
|
|
10
9
|
*/
|
|
11
|
-
export declare function
|
|
12
|
-
/**
|
|
13
|
-
* Generate the /info output
|
|
14
|
-
*/
|
|
15
|
-
export declare function getInfoOutput(socketPath: string, cols: number, rows: number, shell: string, stats: Stats): string;
|
|
16
|
-
/**
|
|
17
|
-
* Print the /info output
|
|
18
|
-
*/
|
|
19
|
-
export declare function printInfo(socketPath: string, cols: number, rows: number, shell: string, stats: Stats): void;
|
|
20
|
-
/**
|
|
21
|
-
* Check if input is the /info command
|
|
22
|
-
*/
|
|
23
|
-
export declare function isInfoCommand(input: string): boolean;
|
|
10
|
+
export declare function getBanner(options: BannerOptions): string;
|
|
24
11
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/ui/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ui/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ui/index.ts"],"names":[],"mappings":"AA6BA,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,aAAa,GAAG,MAAM,CA4CxD"}
|
package/dist/ui/index.js
CHANGED
|
@@ -24,16 +24,15 @@ const LOGO = `
|
|
|
24
24
|
╚═╝ ╚═╝ ╚═════╝╚═╝
|
|
25
25
|
`.trim();
|
|
26
26
|
/**
|
|
27
|
-
*
|
|
27
|
+
* Generate the startup banner string
|
|
28
28
|
*/
|
|
29
|
-
export function
|
|
29
|
+
export function getBanner(options) {
|
|
30
30
|
// Build the logo with box around it
|
|
31
31
|
const logoLines = LOGO.split("\n");
|
|
32
32
|
// Find the widest logo line to determine box width
|
|
33
33
|
const maxLogoWidth = Math.max(...logoLines.map((l) => l.length));
|
|
34
34
|
const boxWidth = maxLogoWidth + 4; // 2 chars padding on each side
|
|
35
35
|
const horizontalLine = "─".repeat(boxWidth);
|
|
36
|
-
const emptyLine = YELLOW_COLOR + "│" + " ".repeat(boxWidth) + "│";
|
|
37
36
|
// Center the logo as a block (same left padding for all lines)
|
|
38
37
|
// First 6 lines are TERMINAL (blue), last 6 lines are MCP (pink)
|
|
39
38
|
const centeredLogo = logoLines.map((line, index) => {
|
|
@@ -41,71 +40,32 @@ export function printBanner(options) {
|
|
|
41
40
|
const color = index < 6 ? BRAND_COLOR : PINK_COLOR;
|
|
42
41
|
return YELLOW_COLOR + "│ " + color + line + " ".repeat(rightPad) + " " + YELLOW_COLOR + "│";
|
|
43
42
|
});
|
|
44
|
-
const
|
|
43
|
+
const mcpConfig = `{
|
|
44
|
+
"mcpServers": {
|
|
45
|
+
"terminal": {
|
|
46
|
+
"command": "terminal-mcp"
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}`;
|
|
50
|
+
return `
|
|
45
51
|
${YELLOW_COLOR}╭${horizontalLine}╮
|
|
46
52
|
${centeredLogo.join("\n")}
|
|
47
53
|
${YELLOW_COLOR}├${horizontalLine}┤
|
|
48
54
|
${YELLOW_COLOR}│${WHITE_COLOR} Socket: ${padRight(options.socketPath, boxWidth - 11)}${YELLOW_COLOR}│
|
|
49
55
|
${YELLOW_COLOR}│${WHITE_COLOR} Terminal: ${padRight(`${options.cols}x${options.rows}`, 12)}Shell: ${padRight(options.shell, boxWidth - 30)}${YELLOW_COLOR}│
|
|
50
|
-
${
|
|
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}│
|
|
56
|
+
${YELLOW_COLOR}│${WHITE_COLOR} Tools: type, sendKey, getContent, takeScreenshot, clear${" ".repeat(boxWidth - 58)}${YELLOW_COLOR}│
|
|
53
57
|
${YELLOW_COLOR}│${WHITE_COLOR}${" ".repeat(boxWidth - 7)}v${VERSION} ${YELLOW_COLOR}│
|
|
54
58
|
${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
59
|
|
|
84
|
-
|
|
85
|
-
"mcpServers": {
|
|
86
|
-
"terminal": {
|
|
87
|
-
"command": "terminal-mcp"
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
}${WHITE_COLOR}
|
|
91
|
-
|
|
92
|
-
Then restart your MCP client to load the server.
|
|
60
|
+
${WHITE_COLOR}MCP Configuration (add to your MCP client):${RESET}
|
|
93
61
|
|
|
94
|
-
|
|
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.)
|
|
62
|
+
${mcpConfig}
|
|
99
63
|
|
|
100
|
-
${YELLOW_COLOR}
|
|
64
|
+
${YELLOW_COLOR}╭${horizontalLine}╮
|
|
65
|
+
│${WHITE_COLOR} Restart your MCP client to connect.${" ".repeat(boxWidth - 38)}${YELLOW_COLOR}│
|
|
66
|
+
╰${horizontalLine}╯${RESET}
|
|
101
67
|
`;
|
|
102
68
|
}
|
|
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
69
|
/**
|
|
110
70
|
* Pad a string to the right with spaces
|
|
111
71
|
*/
|
|
@@ -115,10 +75,4 @@ function padRight(str, length) {
|
|
|
115
75
|
}
|
|
116
76
|
return str + " ".repeat(length - str.length);
|
|
117
77
|
}
|
|
118
|
-
/**
|
|
119
|
-
* Check if input is the /info command
|
|
120
|
-
*/
|
|
121
|
-
export function isInfoCommand(input) {
|
|
122
|
-
return input.trim() === "/info";
|
|
123
|
-
}
|
|
124
78
|
//# sourceMappingURL=index.js.map
|
package/dist/ui/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ui/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ui/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get the default IPC path for cross-platform communication.
|
|
3
|
+
* Uses named pipes on Windows, Unix sockets elsewhere.
|
|
4
|
+
*/
|
|
5
|
+
export declare function getDefaultSocketPath(): string;
|
|
6
|
+
/**
|
|
7
|
+
* Get the default shell for the current platform.
|
|
8
|
+
*/
|
|
9
|
+
export declare function getDefaultShell(): string;
|
|
10
|
+
//# sourceMappingURL=platform.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform.d.ts","sourceRoot":"","sources":["../../src/utils/platform.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAK7C;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,MAAM,CAKxC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import * as path from "path";
|
|
2
|
+
import * as os from "os";
|
|
3
|
+
/**
|
|
4
|
+
* Get the default IPC path for cross-platform communication.
|
|
5
|
+
* Uses named pipes on Windows, Unix sockets elsewhere.
|
|
6
|
+
*/
|
|
7
|
+
export function getDefaultSocketPath() {
|
|
8
|
+
if (process.platform === "win32") {
|
|
9
|
+
return "\\\\.\\pipe\\terminal-mcp";
|
|
10
|
+
}
|
|
11
|
+
return path.join(os.tmpdir(), "terminal-mcp.sock");
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Get the default shell for the current platform.
|
|
15
|
+
*/
|
|
16
|
+
export function getDefaultShell() {
|
|
17
|
+
if (process.platform === "win32") {
|
|
18
|
+
return process.env.COMSPEC || "cmd.exe";
|
|
19
|
+
}
|
|
20
|
+
return process.env.SHELL || "/bin/bash";
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=platform.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform.js","sourceRoot":"","sources":["../../src/utils/platform.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AAEzB;;;GAGG;AACH,MAAM,UAAU,oBAAoB;IAClC,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACjC,OAAO,2BAA2B,CAAC;IACrC,CAAC;IACD,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,mBAAmB,CAAC,CAAC;AACrD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe;IAC7B,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACjC,OAAO,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,SAAS,CAAC;IAC1C,CAAC;IACD,OAAO,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,WAAW,CAAC;AAC1C,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ellery/terminal-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "A headless terminal emulator exposed via MCP for AI assistants",
|
|
5
5
|
"author": "Ellery Familia",
|
|
6
6
|
"repository": {
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
26
26
|
"@xterm/headless": "^5.3.0",
|
|
27
|
-
"node-pty": "^0.
|
|
27
|
+
"@homebridge/node-pty-prebuilt-multiarch": "^0.13.1",
|
|
28
28
|
"zod": "^3.23.0"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|