vscode-terminal-mcp 0.1.5 → 0.1.6

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/CHANGELOG.md ADDED
@@ -0,0 +1,45 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ ## [0.1.6] - 2026-03-19 18:18 PDT
6
+
7
+ ### Added
8
+ - Screenshots in README for marketplace (run, exec, permission dialog)
9
+ - Custom terminal tab names with date format (e.g., `MCP: BashTerm-26-03-19-17-30`)
10
+ - `name` parameter in `run` tool for custom terminal names
11
+ - Unique IPC socket per workspace to prevent conflicts between multiple VSCode instances
12
+ - Large output handling documentation
13
+ - Development workflow docs for extension cache workaround
14
+
15
+ ### Fixed
16
+ - Clean output format for all tools (`run`, `exec`, `read`, `list`, `close`, `input`) — no more raw JSON responses
17
+ - `waitForCompletion: false` not working (`z.coerce.boolean()` converted string `"false"` to `true`)
18
+ - Idle reaper killing sessions with running commands — reaper disabled, user closes sessions manually
19
+
20
+ ## [0.1.5] - 2026-03-18 14:50 PDT
21
+
22
+ ### Added
23
+ - npm publish with `bin` entry for `npx vscode-terminal-mcp` support
24
+ - Published to VSCode Marketplace and MCP Registry
25
+
26
+ ## [0.1.3] - 2026-03-18 11:00 PDT
27
+
28
+ ### Added
29
+ - `run` tool combining create + exec in one step
30
+ - Session reuse: `run` finds idle sessions before creating new ones
31
+ - Busy session detection: won't reuse sessions with running commands
32
+
33
+ ### Fixed
34
+ - First-command timing fix with shell initialization delay
35
+
36
+ ## [0.1.0] - 2026-03-18 10:00 PDT
37
+
38
+ ### Added
39
+ - Initial release
40
+ - Tools: `create`, `exec`, `read`, `input`, `list`, `close`
41
+ - Shell Integration API for output capture and exit code detection
42
+ - Circular output buffer with pagination support
43
+ - Subagent isolation with `agentId`
44
+ - Command blocklist security
45
+ - IPC bridge for MCP stdio-to-socket communication
package/CLAUDE.md ADDED
@@ -0,0 +1,84 @@
1
+ # Project: vscode-terminal-mcp
2
+
3
+ MCP server that runs commands in visible VSCode terminal tabs.
4
+
5
+ ## Release Process
6
+
7
+ When publishing a new version, follow these steps in order:
8
+
9
+ ### 1. Update version
10
+
11
+ ```bash
12
+ # In package.json, bump the version
13
+ # e.g., "version": "0.1.6" → "version": "0.1.7"
14
+ ```
15
+
16
+ ### 2. Update CHANGELOG.md
17
+
18
+ Add a new entry at the top with the new version and date:
19
+
20
+ ```markdown
21
+ ## [0.1.7] - YYYY-MM-DD
22
+
23
+ ### Added
24
+ - ...
25
+
26
+ ### Fixed
27
+ - ...
28
+ ```
29
+
30
+ ### 3. Update README.md
31
+
32
+ Replace the "Latest Changes" section with the new version's changes. Keep only the latest version in README — full history lives in CHANGELOG.md.
33
+
34
+ ### 4. Build and publish
35
+
36
+ ```bash
37
+ # Build
38
+ npm run build
39
+
40
+ # Publish to npm
41
+ npm publish --access public
42
+
43
+ # Package vsix
44
+ npx vsce package --allow-missing-repository
45
+
46
+ # Install locally for testing
47
+ cp dist/extension.js dist/mcp-entry.js ~/.vscode/extensions/sirlordt.vscode-terminal-mcp-<version>/dist/
48
+ ```
49
+
50
+ ### 5. Upload to VSCode Marketplace
51
+
52
+ 1. Go to https://marketplace.visualstudio.com/manage/publishers/sirlordt
53
+ 2. Click "..." next to Terminal MCP → "Update"
54
+ 3. Upload the `.vsix` file
55
+
56
+ ### 6. Commit and push
57
+
58
+ ```bash
59
+ git add -A
60
+ git commit -m "v0.1.7: <summary of changes>"
61
+ git push
62
+ ```
63
+
64
+ ## Extension Cache Workaround
65
+
66
+ VSCode aggressively caches extensions. When developing locally:
67
+
68
+ ```bash
69
+ # Quick update (after modifying source)
70
+ npm run build
71
+ cp dist/extension.js ~/.vscode/extensions/sirlordt.vscode-terminal-mcp-<version>/dist/extension.js
72
+ # Then "Developer: Reload Window"
73
+
74
+ # If reload doesn't pick up changes, close and reopen VSCode completely
75
+ ```
76
+
77
+ ## Terminal Execution
78
+
79
+ Prefer the BashTerm MCP tools (`run`, `exec`, `read`, etc.) over the built-in Bash tool for executing commands. BashTerm runs commands in visible VSCode terminal tabs where the user can see output in real time.
80
+
81
+ For commands that may take longer than 30 seconds or produce large output, use pull mode:
82
+ 1. Call `run` with `waitForCompletion: false`
83
+ 2. Call `read` with `offset: -10` to check progress
84
+ 3. Repeat until done
package/README.md CHANGED
@@ -84,6 +84,20 @@ After installation, try asking:
84
84
 
85
85
  You should see a new terminal tab open in VSCode with the command output.
86
86
 
87
+ ## Screenshots
88
+
89
+ ### Running a command with `run`
90
+
91
+ ![Run command output](docs/images/run_finished.png)
92
+
93
+ ### Permission dialog for `exec`
94
+
95
+ ![Exec permission dialog](docs/images/ask_exec_permission.png)
96
+
97
+ ### Exec result with clean output
98
+
99
+ ![Exec finished](docs/images/exec_finished.png)
100
+
87
101
  ## Tools
88
102
 
89
103
  ### Quick Execution
@@ -202,6 +216,76 @@ This prevents conversation timeouts and lets the user watch progress in the term
202
216
  | Session state | Each command is isolated | Persistent sessions with history |
203
217
  | Interactive commands | Not supported | Send input to prompts/REPLs |
204
218
 
219
+ ## Development: Updating the Extension
220
+
221
+ VSCode aggressively caches extensions in memory. When developing locally, `code --install-extension` and even "Developer: Reload Window" may **not** reload your changes. Use this workflow:
222
+
223
+ ### Quick update (no restart needed)
224
+
225
+ After modifying source files, build and copy directly into the installed extension directory:
226
+
227
+ ```bash
228
+ cd /path/to/vscode-terminal-mcp
229
+ npm run build
230
+ cp dist/extension.js ~/.vscode/extensions/sirlordt.vscode-terminal-mcp-<version>/dist/extension.js
231
+ ```
232
+
233
+ Then run **"Developer: Reload Window"** (`Ctrl+Shift+P`).
234
+
235
+ ### Full reinstall (when quick update doesn't work)
236
+
237
+ If VSCode still uses old code:
238
+
239
+ ```bash
240
+ # 1. Uninstall and remove all copies
241
+ code --uninstall-extension sirlordt.vscode-terminal-mcp
242
+ rm -rf ~/.vscode/extensions/sirlordt.vscode-terminal-mcp-*
243
+
244
+ # 2. Check for ghost entries with old publisher names
245
+ # Look in ~/.vscode/extensions/extensions.json for stale entries
246
+ # Remove any entries with old publisher IDs (e.g., "terminal-mcp.vscode-terminal-mcp")
247
+
248
+ # 3. Close VSCode completely (not just reload)
249
+
250
+ # 4. Rebuild and install
251
+ npm run build
252
+ npx vsce package --allow-missing-repository
253
+ code --install-extension vscode-terminal-mcp-<version>.vsix --force
254
+
255
+ # 5. Open VSCode
256
+ ```
257
+
258
+ ### Verify the correct version is loaded
259
+
260
+ ```bash
261
+ # Check which extension directories exist
262
+ ls ~/.vscode/extensions/ | grep terminal
263
+
264
+ # Verify your changes are in the installed extension
265
+ grep "YOUR_UNIQUE_STRING" ~/.vscode/extensions/sirlordt.vscode-terminal-mcp-*/dist/extension.js
266
+
267
+ # Compare checksums
268
+ md5sum dist/extension.js ~/.vscode/extensions/sirlordt.vscode-terminal-mcp-*/dist/extension.js
269
+ ```
270
+
271
+ ## Large Output Handling
272
+
273
+ When `read` returns output that exceeds the MCP client's token limit, the system automatically saves the full output to a temporary JSON file and returns the file path in the error message.
274
+
275
+ To extract the relevant content:
276
+
277
+ ```bash
278
+ # Get the last 50 lines (most relevant for status)
279
+ tail -50 /path/to/saved/file.txt
280
+
281
+ # Or parse the JSON to extract the text content
282
+ python3 -c "import json; data=json.load(open('/path/to/file.txt')); print(data[0]['text'][-2000:])"
283
+ ```
284
+
285
+ The file format is JSON: `[{"type": "text", "text": "..."}]`
286
+
287
+ This commonly happens with commands that produce heavy TUI output (progress bars, ANSI escape codes). Use smaller `offset` values (e.g., `offset: -20` instead of `offset: -100`) to reduce the captured output size.
288
+
205
289
  ## How It Works
206
290
 
207
291
  1. The **VSCode extension** activates and starts an IPC server on a Unix socket
@@ -209,6 +293,18 @@ This prevents conversation timeouts and lets the user watch progress in the term
209
293
  3. Commands execute in real VSCode terminals using the **Shell Integration API** for reliable output capture and exit code detection
210
294
  4. Output is stored in circular buffers with pagination support for efficient reading
211
295
 
296
+ ## Latest Changes (0.1.6)
297
+
298
+ - Screenshots in README for marketplace
299
+ - Clean output format for all tools — no more raw JSON
300
+ - Fixed `waitForCompletion: false` not working
301
+ - Disabled idle reaper — user closes sessions manually
302
+ - Unique IPC socket per workspace (multi-instance support)
303
+ - Custom terminal tab names with date format
304
+ - Large output handling documentation
305
+
306
+ See [CHANGELOG.md](CHANGELOG.md) for full history.
307
+
212
308
  ## License
213
309
 
214
310
  MIT
package/dist/extension.js CHANGED
@@ -5446,21 +5446,13 @@ async function handleTerminalCreate(params, sessionManager2) {
5446
5446
  shell: input.shell,
5447
5447
  agentId: input.agentId
5448
5448
  });
5449
+ const parts = [`Terminal created: ${sessionInfo.name}`, `session: ${sessionInfo.sessionId}`, `cwd: ${sessionInfo.cwd}`];
5450
+ if (sessionInfo.agentId) parts.push(`agent: ${sessionInfo.agentId}`);
5449
5451
  return {
5450
5452
  content: [
5451
5453
  {
5452
5454
  type: "text",
5453
- text: JSON.stringify(
5454
- {
5455
- status: "created",
5456
- sessionId: sessionInfo.sessionId,
5457
- name: sessionInfo.name,
5458
- cwd: sessionInfo.cwd,
5459
- agentId: sessionInfo.agentId
5460
- },
5461
- null,
5462
- 2
5463
- )
5455
+ text: parts.join(" | ")
5464
5456
  }
5465
5457
  ]
5466
5458
  };
@@ -5500,24 +5492,29 @@ async function handleTerminalExecute(params, sessionManager2) {
5500
5492
  timeoutMs,
5501
5493
  waitForCompletion
5502
5494
  );
5503
- const response = {
5504
- sessionId: input.sessionId,
5505
- commandId: result.commandId,
5506
- exitCode: result.exitCode,
5507
- timedOut: result.timedOut,
5508
- durationMs: result.durationMs,
5509
- output: result.output
5510
- };
5495
+ let cleanOutput = result.output.replace(/\x1b\[[0-9;]*[a-zA-Z]/g, "").replace(/\x1b\][^\x07]*\x07/g, "").replace(/\r\n/g, "\n").replace(/\r/g, "").trim();
5496
+ const lines = cleanOutput.split("\n");
5497
+ if (lines.length > 0 && lines[0].trim() === input.command.trim()) {
5498
+ lines.shift();
5499
+ cleanOutput = lines.join("\n").trim();
5500
+ }
5501
+ const statusParts = [`exit: ${result.exitCode ?? "n/a"}`, `${result.durationMs}ms`, input.sessionId];
5502
+ let text = `$ ${input.command}
5503
+ ${cleanOutput}
5504
+
5505
+ [${statusParts.join(" | ")}]`;
5511
5506
  if (result.timedOut) {
5512
- response.warning = `Command timed out after ${timeoutMs}ms. Output may be incomplete. The terminal session is still active.`;
5507
+ text += `
5508
+ [TIMED OUT after ${timeoutMs}ms - session still active, use read to get more output]`;
5513
5509
  }
5514
5510
  return {
5515
5511
  content: [
5516
5512
  {
5517
5513
  type: "text",
5518
- text: JSON.stringify(response, null, 2)
5514
+ text
5519
5515
  }
5520
- ]
5516
+ ],
5517
+ isError: result.exitCode !== null && result.exitCode !== 0
5521
5518
  };
5522
5519
  }
5523
5520
 
@@ -5537,7 +5534,11 @@ async function handleTerminalRun(params, sessionManager2) {
5537
5534
  }
5538
5535
  if (!sessionId) {
5539
5536
  const sessionInfo = sessionManager2.createSession({
5540
- name: input.name ?? `run-${Date.now()}`,
5537
+ name: input.name ?? (() => {
5538
+ const d = /* @__PURE__ */ new Date();
5539
+ const pad = (n) => String(n).padStart(2, "0");
5540
+ return `BashTerm-${pad(d.getFullYear() % 100)}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}-${pad(d.getHours())}-${pad(d.getMinutes())}`;
5541
+ })(),
5541
5542
  cwd: input.cwd,
5542
5543
  env: input.env,
5543
5544
  shell: input.shell,
@@ -5634,18 +5635,23 @@ async function handleTerminalReadOutput(params, sessionManager2) {
5634
5635
  async function handleTerminalList(params, sessionManager2) {
5635
5636
  const input = terminalListSchema.parse(params ?? {});
5636
5637
  const sessions = sessionManager2.listSessions(input.agentId);
5638
+ if (sessions.length === 0) {
5639
+ return {
5640
+ content: [{ type: "text", text: "No active sessions." }]
5641
+ };
5642
+ }
5643
+ const lines = sessions.map((s) => {
5644
+ const age = Math.round((Date.now() - s.createdAt) / 1e3);
5645
+ const parts = [s.sessionId, s.name, `cwd: ${s.cwd}`, `${age}s old`, `${s.outputLineCount} lines`];
5646
+ if (s.agentId) parts.push(`agent: ${s.agentId}`);
5647
+ return parts.join(" | ");
5648
+ });
5637
5649
  return {
5638
5650
  content: [
5639
5651
  {
5640
5652
  type: "text",
5641
- text: JSON.stringify(
5642
- {
5643
- count: sessions.length,
5644
- sessions
5645
- },
5646
- null,
5647
- 2
5648
- )
5653
+ text: `${sessions.length} active session(s):
5654
+ ${lines.join("\n")}`
5649
5655
  }
5650
5656
  ]
5651
5657
  };
@@ -5670,10 +5676,7 @@ async function handleTerminalClose(params, sessionManager2) {
5670
5676
  content: [
5671
5677
  {
5672
5678
  type: "text",
5673
- text: JSON.stringify({
5674
- status: "closed",
5675
- sessionId: input.sessionId
5676
- })
5679
+ text: `Session closed: ${input.sessionId}`
5677
5680
  }
5678
5681
  ]
5679
5682
  };
@@ -5699,12 +5702,7 @@ async function handleTerminalSendInput(params, sessionManager2) {
5699
5702
  content: [
5700
5703
  {
5701
5704
  type: "text",
5702
- text: JSON.stringify({
5703
- status: "sent",
5704
- sessionId: input.sessionId,
5705
- inputLength: input.input.length,
5706
- pressedEnter: input.pressEnter ?? true
5707
- })
5705
+ text: `Input sent to ${input.sessionId} (${input.input.length} chars${input.pressEnter ?? true ? " + Enter" : ""})`
5708
5706
  }
5709
5707
  ]
5710
5708
  };
@@ -6301,7 +6299,16 @@ var sessionManager;
6301
6299
  var statusBarItem;
6302
6300
  function getSocketPath() {
6303
6301
  const tmpDir = os.tmpdir();
6304
- return path.join(tmpDir, "vscode-terminal-mcp.sock");
6302
+ const crypto3 = require("crypto");
6303
+ const workspace4 = vscode4.workspace.workspaceFolders?.[0]?.uri.fsPath || "";
6304
+ const hash = crypto3.createHash("md5").update(workspace4).digest("hex").slice(0, 8);
6305
+ const socketPath = path.join(tmpDir, `vscode-terminal-mcp-${hash}.sock`);
6306
+ const discoveryPath = path.join(tmpDir, "vscode-terminal-mcp.discovery");
6307
+ try {
6308
+ fs.writeFileSync(discoveryPath, socketPath);
6309
+ } catch {
6310
+ }
6311
+ return socketPath;
6305
6312
  }
6306
6313
  function cleanupSocket(socketPath) {
6307
6314
  try {
package/dist/mcp-entry.js CHANGED
@@ -27,7 +27,20 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
27
27
  var net = __toESM(require("net"));
28
28
  var path = __toESM(require("path"));
29
29
  var os = __toESM(require("os"));
30
- var SOCKET_PATH = path.join(os.tmpdir(), "vscode-terminal-mcp.sock");
30
+ var fs = __toESM(require("fs"));
31
+ function getSocketPath() {
32
+ const tmpDir = os.tmpdir();
33
+ const discoveryPath = path.join(tmpDir, "vscode-terminal-mcp.discovery");
34
+ try {
35
+ const socketPath = fs.readFileSync(discoveryPath, "utf8").trim();
36
+ if (socketPath && fs.existsSync(socketPath)) {
37
+ return socketPath;
38
+ }
39
+ } catch {
40
+ }
41
+ return path.join(tmpDir, "vscode-terminal-mcp.sock");
42
+ }
43
+ var SOCKET_PATH = getSocketPath();
31
44
  var RECONNECT_DELAY_MS = 1e3;
32
45
  var MAX_RECONNECT_ATTEMPTS = 30;
33
46
  var StdioToIpcBridge = class {
Binary file
Binary file
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "vscode-terminal-mcp",
3
3
  "displayName": "Terminal MCP Server",
4
4
  "description": "MCP server that provides visible terminal sessions in VSCode for Claude Code and subagents",
5
- "version": "0.1.5",
5
+ "version": "0.1.6",
6
6
  "publisher": "sirlordt",
7
7
  "license": "MIT",
8
8
  "author": "sirlordt",