@hasna/terminal 3.3.0 → 3.3.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.
- package/dist/mcp/install.js +15 -42
- package/dist/mcp/server.js +5 -5
- package/package.json +1 -1
- package/src/mcp/install.ts +15 -42
- package/src/mcp/server.ts +5 -5
package/dist/mcp/install.js
CHANGED
|
@@ -24,15 +24,15 @@ function installClaude(bin) {
|
|
|
24
24
|
return false;
|
|
25
25
|
}
|
|
26
26
|
try {
|
|
27
|
-
execSync(`claude mcp add --transport stdio --scope user
|
|
27
|
+
execSync(`claude mcp add --transport stdio --scope user terminal -- ${bin} mcp serve`, { stdio: ["pipe", "pipe", "pipe"] });
|
|
28
28
|
log("✓", "Claude Code");
|
|
29
29
|
return true;
|
|
30
30
|
}
|
|
31
31
|
catch {
|
|
32
32
|
// May already exist
|
|
33
33
|
try {
|
|
34
|
-
execSync(`claude mcp remove
|
|
35
|
-
execSync(`claude mcp add --transport stdio --scope user
|
|
34
|
+
execSync(`claude mcp remove terminal -s user`, { stdio: ["pipe", "pipe", "pipe"] });
|
|
35
|
+
execSync(`claude mcp add --transport stdio --scope user terminal -- ${bin} mcp serve`, { stdio: ["pipe", "pipe", "pipe"] });
|
|
36
36
|
log("✓", "Claude Code (updated)");
|
|
37
37
|
return true;
|
|
38
38
|
}
|
|
@@ -55,8 +55,8 @@ function installCodex(bin) {
|
|
|
55
55
|
mkdirSync(dir, { recursive: true });
|
|
56
56
|
let content = existsSync(configPath) ? readFileSync(configPath, "utf8") : "";
|
|
57
57
|
// Remove old entry if exists
|
|
58
|
-
content = content.replace(/\n?\[mcp_servers\.
|
|
59
|
-
content += `\n[mcp_servers.
|
|
58
|
+
content = content.replace(/\n?\[mcp_servers\.terminal\][^\[]*/g, "");
|
|
59
|
+
content += `\n[mcp_servers.terminal]\ncommand = "${bin}"\nargs = ["mcp", "serve"]\n`;
|
|
60
60
|
writeFileSync(configPath, content);
|
|
61
61
|
log("✓", "Codex");
|
|
62
62
|
return true;
|
|
@@ -86,7 +86,7 @@ function installGemini(bin) {
|
|
|
86
86
|
}
|
|
87
87
|
if (!config.mcpServers)
|
|
88
88
|
config.mcpServers = {};
|
|
89
|
-
config.mcpServers["
|
|
89
|
+
config.mcpServers["terminal"] = { command: bin, args: ["mcp", "serve"] };
|
|
90
90
|
writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
91
91
|
log("✓", "Gemini CLI");
|
|
92
92
|
return true;
|
|
@@ -101,7 +101,7 @@ function uninstallClaude() {
|
|
|
101
101
|
if (!hasClaude())
|
|
102
102
|
return false;
|
|
103
103
|
try {
|
|
104
|
-
execSync(`claude mcp remove
|
|
104
|
+
execSync(`claude mcp remove terminal -s user`, { stdio: ["pipe", "pipe", "pipe"] });
|
|
105
105
|
log("✓", "Removed from Claude Code");
|
|
106
106
|
return true;
|
|
107
107
|
}
|
|
@@ -115,9 +115,9 @@ function uninstallCodex() {
|
|
|
115
115
|
return false;
|
|
116
116
|
try {
|
|
117
117
|
let content = readFileSync(configPath, "utf8");
|
|
118
|
-
if (!content.includes("
|
|
118
|
+
if (!content.includes("terminal"))
|
|
119
119
|
return false;
|
|
120
|
-
content = content.replace(/\n?\[mcp_servers\.
|
|
120
|
+
content = content.replace(/\n?\[mcp_servers\.terminal\][^\[]*/g, "");
|
|
121
121
|
writeFileSync(configPath, content);
|
|
122
122
|
log("✓", "Removed from Codex");
|
|
123
123
|
return true;
|
|
@@ -132,9 +132,9 @@ function uninstallGemini() {
|
|
|
132
132
|
return false;
|
|
133
133
|
try {
|
|
134
134
|
const config = JSON.parse(readFileSync(configPath, "utf8"));
|
|
135
|
-
if (!config.mcpServers?.["
|
|
135
|
+
if (!config.mcpServers?.["terminal"])
|
|
136
136
|
return false;
|
|
137
|
-
delete config.mcpServers["
|
|
137
|
+
delete config.mcpServers["terminal"];
|
|
138
138
|
writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
139
139
|
log("✓", "Removed from Gemini CLI");
|
|
140
140
|
return true;
|
|
@@ -148,7 +148,7 @@ export function handleInstall(args) {
|
|
|
148
148
|
const flags = new Set(args);
|
|
149
149
|
// Uninstall
|
|
150
150
|
if (flags.has("uninstall") || flags.has("--uninstall")) {
|
|
151
|
-
console.log("\n Removing
|
|
151
|
+
console.log("\n Removing terminal MCP server...\n");
|
|
152
152
|
uninstallClaude();
|
|
153
153
|
uninstallCodex();
|
|
154
154
|
uninstallGemini();
|
|
@@ -170,14 +170,7 @@ export function handleInstall(args) {
|
|
|
170
170
|
}
|
|
171
171
|
// ── Default: install everything ─────────────────────────────────────────
|
|
172
172
|
const bin = which("terminal") ?? which("t") ?? "npx @hasna/terminal";
|
|
173
|
-
console.log(`
|
|
174
|
-
┌─────────────────────────────────────┐
|
|
175
|
-
│ open-terminal │
|
|
176
|
-
│ Smart terminal for AI agents │
|
|
177
|
-
└─────────────────────────────────────┘
|
|
178
|
-
|
|
179
|
-
Setting up MCP server for all agents...
|
|
180
|
-
`);
|
|
173
|
+
console.log(`\n terminal — setting up MCP...\n`);
|
|
181
174
|
let count = 0;
|
|
182
175
|
if (installClaude(bin))
|
|
183
176
|
count++;
|
|
@@ -186,30 +179,10 @@ export function handleInstall(args) {
|
|
|
186
179
|
if (installGemini(bin))
|
|
187
180
|
count++;
|
|
188
181
|
if (count === 0) {
|
|
189
|
-
console.log(`
|
|
190
|
-
No AI agents found. Install one first:
|
|
191
|
-
|
|
192
|
-
npm i -g @anthropic-ai/claude-code # Claude Code
|
|
193
|
-
npm i -g @openai/codex # Codex
|
|
194
|
-
npm i -g @anthropic-ai/gemini-cli # Gemini CLI
|
|
195
|
-
|
|
196
|
-
Then run: terminal install
|
|
197
|
-
`);
|
|
182
|
+
console.log(`\n No agents found. Install Claude Code, Codex, or Gemini CLI first.\n`);
|
|
198
183
|
}
|
|
199
184
|
else {
|
|
200
|
-
console.log(`
|
|
201
|
-
Done. ${count} agent${count > 1 ? "s" : ""} configured.
|
|
202
|
-
Restart your agent to start using open-terminal.
|
|
203
|
-
|
|
204
|
-
Your AI agent now has these tools:
|
|
205
|
-
execute_smart Run any command, get AI-summarized output
|
|
206
|
-
execute_diff Run command, see only what changed
|
|
207
|
-
search_content Smart grep with file grouping
|
|
208
|
-
search_files Find files by pattern
|
|
209
|
-
read_symbol Read a function by name (not whole file)
|
|
210
|
-
boot Full project context in one call
|
|
211
|
-
repo_state Git status + log + diff in one call
|
|
212
|
-
`);
|
|
185
|
+
console.log(`\n ${count} agent${count > 1 ? "s" : ""} ready. Restart to apply.\n`);
|
|
213
186
|
}
|
|
214
187
|
}
|
|
215
188
|
// Re-export individual installers for programmatic use
|
package/dist/mcp/server.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// MCP Server for
|
|
1
|
+
// MCP Server for terminal — exposes terminal capabilities to AI agents
|
|
2
2
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
3
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
4
|
import { z } from "zod";
|
|
@@ -56,7 +56,7 @@ function exec(command, cwd, timeout) {
|
|
|
56
56
|
// ── server ───────────────────────────────────────────────────────────────────
|
|
57
57
|
export function createServer() {
|
|
58
58
|
const server = new McpServer({
|
|
59
|
-
name: "
|
|
59
|
+
name: "terminal",
|
|
60
60
|
version: "0.2.0",
|
|
61
61
|
});
|
|
62
62
|
// ── execute: run a command, return structured result ──────────────────────
|
|
@@ -202,10 +202,10 @@ export function createServer() {
|
|
|
202
202
|
};
|
|
203
203
|
});
|
|
204
204
|
// ── status: show server info ──────────────────────────────────────────────
|
|
205
|
-
server.tool("status", "Get
|
|
205
|
+
server.tool("status", "Get terminal server status, capabilities, and available parsers.", async () => {
|
|
206
206
|
return {
|
|
207
207
|
content: [{ type: "text", text: JSON.stringify({
|
|
208
|
-
name: "
|
|
208
|
+
name: "terminal", version: "3.3.0", cwd: process.cwd(),
|
|
209
209
|
features: ["ai-output-processing", "token-compression", "noise-filtering", "diff-caching", "lazy-execution", "progressive-disclosure"],
|
|
210
210
|
}) }],
|
|
211
211
|
};
|
|
@@ -541,5 +541,5 @@ export async function startMcpServer() {
|
|
|
541
541
|
const server = createServer();
|
|
542
542
|
const transport = new StdioServerTransport();
|
|
543
543
|
await server.connect(transport);
|
|
544
|
-
console.error("
|
|
544
|
+
console.error("terminal MCP server running on stdio");
|
|
545
545
|
}
|
package/package.json
CHANGED
package/src/mcp/install.ts
CHANGED
|
@@ -23,14 +23,14 @@ function hasGemini(): boolean { return !!which("gemini"); }
|
|
|
23
23
|
function installClaude(bin: string): boolean {
|
|
24
24
|
if (!hasClaude()) { log("–", "Claude Code not found, skipping"); return false; }
|
|
25
25
|
try {
|
|
26
|
-
execSync(`claude mcp add --transport stdio --scope user
|
|
26
|
+
execSync(`claude mcp add --transport stdio --scope user terminal -- ${bin} mcp serve`, { stdio: ["pipe", "pipe", "pipe"] });
|
|
27
27
|
log("✓", "Claude Code");
|
|
28
28
|
return true;
|
|
29
29
|
} catch {
|
|
30
30
|
// May already exist
|
|
31
31
|
try {
|
|
32
|
-
execSync(`claude mcp remove
|
|
33
|
-
execSync(`claude mcp add --transport stdio --scope user
|
|
32
|
+
execSync(`claude mcp remove terminal -s user`, { stdio: ["pipe", "pipe", "pipe"] });
|
|
33
|
+
execSync(`claude mcp add --transport stdio --scope user terminal -- ${bin} mcp serve`, { stdio: ["pipe", "pipe", "pipe"] });
|
|
34
34
|
log("✓", "Claude Code (updated)");
|
|
35
35
|
return true;
|
|
36
36
|
} catch (e) {
|
|
@@ -50,8 +50,8 @@ function installCodex(bin: string): boolean {
|
|
|
50
50
|
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
51
51
|
let content = existsSync(configPath) ? readFileSync(configPath, "utf8") : "";
|
|
52
52
|
// Remove old entry if exists
|
|
53
|
-
content = content.replace(/\n?\[mcp_servers\.
|
|
54
|
-
content += `\n[mcp_servers.
|
|
53
|
+
content = content.replace(/\n?\[mcp_servers\.terminal\][^\[]*/g, "");
|
|
54
|
+
content += `\n[mcp_servers.terminal]\ncommand = "${bin}"\nargs = ["mcp", "serve"]\n`;
|
|
55
55
|
writeFileSync(configPath, content);
|
|
56
56
|
log("✓", "Codex");
|
|
57
57
|
return true;
|
|
@@ -74,7 +74,7 @@ function installGemini(bin: string): boolean {
|
|
|
74
74
|
try { config = JSON.parse(readFileSync(configPath, "utf8")); } catch {}
|
|
75
75
|
}
|
|
76
76
|
if (!config.mcpServers) config.mcpServers = {};
|
|
77
|
-
config.mcpServers["
|
|
77
|
+
config.mcpServers["terminal"] = { command: bin, args: ["mcp", "serve"] };
|
|
78
78
|
writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
79
79
|
log("✓", "Gemini CLI");
|
|
80
80
|
return true;
|
|
@@ -88,7 +88,7 @@ function installGemini(bin: string): boolean {
|
|
|
88
88
|
|
|
89
89
|
function uninstallClaude(): boolean {
|
|
90
90
|
if (!hasClaude()) return false;
|
|
91
|
-
try { execSync(`claude mcp remove
|
|
91
|
+
try { execSync(`claude mcp remove terminal -s user`, { stdio: ["pipe", "pipe", "pipe"] }); log("✓", "Removed from Claude Code"); return true; } catch { return false; }
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
function uninstallCodex(): boolean {
|
|
@@ -96,8 +96,8 @@ function uninstallCodex(): boolean {
|
|
|
96
96
|
if (!existsSync(configPath)) return false;
|
|
97
97
|
try {
|
|
98
98
|
let content = readFileSync(configPath, "utf8");
|
|
99
|
-
if (!content.includes("
|
|
100
|
-
content = content.replace(/\n?\[mcp_servers\.
|
|
99
|
+
if (!content.includes("terminal")) return false;
|
|
100
|
+
content = content.replace(/\n?\[mcp_servers\.terminal\][^\[]*/g, "");
|
|
101
101
|
writeFileSync(configPath, content);
|
|
102
102
|
log("✓", "Removed from Codex");
|
|
103
103
|
return true;
|
|
@@ -109,8 +109,8 @@ function uninstallGemini(): boolean {
|
|
|
109
109
|
if (!existsSync(configPath)) return false;
|
|
110
110
|
try {
|
|
111
111
|
const config = JSON.parse(readFileSync(configPath, "utf8"));
|
|
112
|
-
if (!config.mcpServers?.["
|
|
113
|
-
delete config.mcpServers["
|
|
112
|
+
if (!config.mcpServers?.["terminal"]) return false;
|
|
113
|
+
delete config.mcpServers["terminal"];
|
|
114
114
|
writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
115
115
|
log("✓", "Removed from Gemini CLI");
|
|
116
116
|
return true;
|
|
@@ -124,7 +124,7 @@ export function handleInstall(args: string[]): void {
|
|
|
124
124
|
|
|
125
125
|
// Uninstall
|
|
126
126
|
if (flags.has("uninstall") || flags.has("--uninstall")) {
|
|
127
|
-
console.log("\n Removing
|
|
127
|
+
console.log("\n Removing terminal MCP server...\n");
|
|
128
128
|
uninstallClaude();
|
|
129
129
|
uninstallCodex();
|
|
130
130
|
uninstallGemini();
|
|
@@ -147,14 +147,7 @@ export function handleInstall(args: string[]): void {
|
|
|
147
147
|
|
|
148
148
|
const bin = which("terminal") ?? which("t") ?? "npx @hasna/terminal";
|
|
149
149
|
|
|
150
|
-
console.log(`
|
|
151
|
-
┌─────────────────────────────────────┐
|
|
152
|
-
│ open-terminal │
|
|
153
|
-
│ Smart terminal for AI agents │
|
|
154
|
-
└─────────────────────────────────────┘
|
|
155
|
-
|
|
156
|
-
Setting up MCP server for all agents...
|
|
157
|
-
`);
|
|
150
|
+
console.log(`\n terminal — setting up MCP...\n`);
|
|
158
151
|
|
|
159
152
|
let count = 0;
|
|
160
153
|
if (installClaude(bin)) count++;
|
|
@@ -162,29 +155,9 @@ export function handleInstall(args: string[]): void {
|
|
|
162
155
|
if (installGemini(bin)) count++;
|
|
163
156
|
|
|
164
157
|
if (count === 0) {
|
|
165
|
-
console.log(`
|
|
166
|
-
No AI agents found. Install one first:
|
|
167
|
-
|
|
168
|
-
npm i -g @anthropic-ai/claude-code # Claude Code
|
|
169
|
-
npm i -g @openai/codex # Codex
|
|
170
|
-
npm i -g @anthropic-ai/gemini-cli # Gemini CLI
|
|
171
|
-
|
|
172
|
-
Then run: terminal install
|
|
173
|
-
`);
|
|
158
|
+
console.log(`\n No agents found. Install Claude Code, Codex, or Gemini CLI first.\n`);
|
|
174
159
|
} else {
|
|
175
|
-
console.log(`
|
|
176
|
-
Done. ${count} agent${count > 1 ? "s" : ""} configured.
|
|
177
|
-
Restart your agent to start using open-terminal.
|
|
178
|
-
|
|
179
|
-
Your AI agent now has these tools:
|
|
180
|
-
execute_smart Run any command, get AI-summarized output
|
|
181
|
-
execute_diff Run command, see only what changed
|
|
182
|
-
search_content Smart grep with file grouping
|
|
183
|
-
search_files Find files by pattern
|
|
184
|
-
read_symbol Read a function by name (not whole file)
|
|
185
|
-
boot Full project context in one call
|
|
186
|
-
repo_state Git status + log + diff in one call
|
|
187
|
-
`);
|
|
160
|
+
console.log(`\n ${count} agent${count > 1 ? "s" : ""} ready. Restart to apply.\n`);
|
|
188
161
|
}
|
|
189
162
|
}
|
|
190
163
|
|
package/src/mcp/server.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// MCP Server for
|
|
1
|
+
// MCP Server for terminal — exposes terminal capabilities to AI agents
|
|
2
2
|
|
|
3
3
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
4
4
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
@@ -61,7 +61,7 @@ function exec(command: string, cwd?: string, timeout?: number): Promise<{ exitCo
|
|
|
61
61
|
|
|
62
62
|
export function createServer(): McpServer {
|
|
63
63
|
const server = new McpServer({
|
|
64
|
-
name: "
|
|
64
|
+
name: "terminal",
|
|
65
65
|
version: "0.2.0",
|
|
66
66
|
});
|
|
67
67
|
|
|
@@ -251,11 +251,11 @@ export function createServer(): McpServer {
|
|
|
251
251
|
|
|
252
252
|
server.tool(
|
|
253
253
|
"status",
|
|
254
|
-
"Get
|
|
254
|
+
"Get terminal server status, capabilities, and available parsers.",
|
|
255
255
|
async () => {
|
|
256
256
|
return {
|
|
257
257
|
content: [{ type: "text" as const, text: JSON.stringify({
|
|
258
|
-
name: "
|
|
258
|
+
name: "terminal", version: "3.3.0", cwd: process.cwd(),
|
|
259
259
|
features: ["ai-output-processing", "token-compression", "noise-filtering", "diff-caching", "lazy-execution", "progressive-disclosure"],
|
|
260
260
|
}) }],
|
|
261
261
|
};
|
|
@@ -762,5 +762,5 @@ export async function startMcpServer(): Promise<void> {
|
|
|
762
762
|
const server = createServer();
|
|
763
763
|
const transport = new StdioServerTransport();
|
|
764
764
|
await server.connect(transport);
|
|
765
|
-
console.error("
|
|
765
|
+
console.error("terminal MCP server running on stdio");
|
|
766
766
|
}
|