@priyanshumit/macos-terminal-mcp 0.6.1 → 0.6.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/README.md +2 -2
- package/dist/tools/close_tab.js +17 -6
- package/dist/tools/close_tab.js.map +1 -1
- package/dist/tools/list.js +4 -1
- package/dist/tools/list.js.map +1 -1
- package/dist/tools/new_tab.js +7 -0
- package/dist/tools/new_tab.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -90,7 +90,7 @@ First time the MCP server controls Terminal.app, macOS will prompt for permissio
|
|
|
90
90
|
|
|
91
91
|
Click **OK**. The setting is remembered in **System Settings → Privacy & Security → Automation**.
|
|
92
92
|
|
|
93
|
-
`terminal_clear` additionally
|
|
93
|
+
`terminal_clear`, `terminal_new_tab`, and `terminal_close_tab` additionally require **Accessibility** permission — they use System Events to simulate Cmd+K, Cmd+T, and Cmd+W respectively. Grant under **System Settings → Privacy & Security → Accessibility**.
|
|
94
94
|
|
|
95
95
|
## Scrollback configuration
|
|
96
96
|
|
|
@@ -131,7 +131,7 @@ To enable write tools, add the env block:
|
|
|
131
131
|
}
|
|
132
132
|
```
|
|
133
133
|
|
|
134
|
-
Restart Claude Code. You should see the
|
|
134
|
+
Restart Claude Code. You should see the fifteen tools listed.
|
|
135
135
|
|
|
136
136
|
## Three-tier safety model
|
|
137
137
|
|
package/dist/tools/close_tab.js
CHANGED
|
@@ -4,13 +4,15 @@ import { appendAudit } from "../safety/audit.js";
|
|
|
4
4
|
import { isWriteToolsEnabled, writeToolsDisabledMessage } from "../safety/confirm.js";
|
|
5
5
|
export function buildCloseTabScript(tty, force) {
|
|
6
6
|
return `
|
|
7
|
+
var app = Application.currentApplication();
|
|
8
|
+
app.includeStandardAdditions = true;
|
|
7
9
|
function safe(fn) { try { return fn(); } catch (e) { return null; } }
|
|
8
10
|
(function closeTab(targetTty, force) {
|
|
9
11
|
const terminal = Application("Terminal");
|
|
10
12
|
const wins = terminal.windows();
|
|
11
13
|
for (let wi = 0; wi < wins.length; wi++) {
|
|
12
14
|
const w = wins[wi];
|
|
13
|
-
const tabs = w.tabs();
|
|
15
|
+
const tabs = safe(function () { return w.tabs(); }) || [];
|
|
14
16
|
for (let ti = 0; ti < tabs.length; ti++) {
|
|
15
17
|
const t = tabs[ti];
|
|
16
18
|
if (safe(function () { return t.tty(); }) === targetTty) {
|
|
@@ -18,11 +20,20 @@ function safe(fn) { try { return fn(); } catch (e) { return null; } }
|
|
|
18
20
|
if (busy && !force) {
|
|
19
21
|
return JSON.stringify({ status: "busy", tty: targetTty });
|
|
20
22
|
}
|
|
21
|
-
// Terminal.app's AppleScript dictionary does NOT expose "close" on
|
|
22
|
-
// objects
|
|
23
|
-
//
|
|
24
|
-
//
|
|
25
|
-
|
|
23
|
+
// Terminal.app's AppleScript dictionary does NOT expose "close" on
|
|
24
|
+
// tab objects. We previously called w.close() but that destroys the
|
|
25
|
+
// entire enclosing physical window, killing sibling tabs (verified
|
|
26
|
+
// live: a 3-tab window lost two tabs when closing one). The reliable
|
|
27
|
+
// way to close ONE specific tab mirrors the terminal_clear pattern:
|
|
28
|
+
// activate Terminal, make the target tab the key tab via frontmost +
|
|
29
|
+
// selected, settle, then send Cmd+W via System Events. Cmd+W on a
|
|
30
|
+
// selected tab closes only that tab.
|
|
31
|
+
terminal.activate();
|
|
32
|
+
try { Application("System Events").applicationProcesses["Terminal"].frontmost = true; } catch (e) { /* best-effort */ }
|
|
33
|
+
try { w.frontmost = true; } catch (e) { /* best-effort */ }
|
|
34
|
+
try { t.selected = true; } catch (e) { /* best-effort */ }
|
|
35
|
+
delay(0.3);
|
|
36
|
+
Application("System Events").keystroke("w", { using: "command down" });
|
|
26
37
|
return JSON.stringify({ status: "closed", tty: targetTty, killedRunningCommand: busy });
|
|
27
38
|
}
|
|
28
39
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"close_tab.js","sourceRoot":"","sources":["../../src/tools/close_tab.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,mBAAmB,EAAE,yBAAyB,EAAE,MAAM,sBAAsB,CAAC;AAEtF,MAAM,UAAU,mBAAmB,CAAC,GAAW,EAAE,KAAc;IAC7D,OAAO
|
|
1
|
+
{"version":3,"file":"close_tab.js","sourceRoot":"","sources":["../../src/tools/close_tab.ts"],"names":[],"mappings":"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"}
|
package/dist/tools/list.js
CHANGED
|
@@ -9,7 +9,10 @@ function safe(fn) {
|
|
|
9
9
|
const wins = terminal.windows();
|
|
10
10
|
for (let wi = 0; wi < wins.length; wi++) {
|
|
11
11
|
const w = wins[wi];
|
|
12
|
-
|
|
12
|
+
// Defensive: during in-progress window-close operations, w.tabs() can
|
|
13
|
+
// briefly return null instead of an empty array, which would crash this
|
|
14
|
+
// script. Treat null as no-tabs and move on.
|
|
15
|
+
const tabs = safe(function () { return w.tabs(); }) || [];
|
|
13
16
|
for (let ti = 0; ti < tabs.length; ti++) {
|
|
14
17
|
const t = tabs[ti];
|
|
15
18
|
result.push({
|
package/dist/tools/list.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list.js","sourceRoot":"","sources":["../../src/tools/list.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAE3D,MAAM,WAAW,GAAG
|
|
1
|
+
{"version":3,"file":"list.js","sourceRoot":"","sources":["../../src/tools/list.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAE3D,MAAM,WAAW,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8BnB,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,CAAC;QACvC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;IACrD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,GACR,GAAG,YAAY,cAAc,IAAI,iBAAiB,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC;YACjE,CAAC,CAAC,4LAA4L;YAC9L,CAAC,CAAC,EAAE,CAAC;QACT,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,yBAAyB,OAAO,GAAG,IAAI,EAAE,EAAE,CAAC;YAC5E,OAAO,EAAE,IAAI;SACd,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,MAAiB;IACxC,MAAM,CAAC,YAAY,CACjB,eAAe,EACf;QACE,WAAW,EACT,mVAAmV;QACrV,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE;KAC1D,EACD,WAAW,CACZ,CAAC;AACJ,CAAC"}
|
package/dist/tools/new_tab.js
CHANGED
|
@@ -44,6 +44,13 @@ function snapshotTabs(terminal) {
|
|
|
44
44
|
// before, ANY tab that exists now is the new one we owe the caller — return
|
|
45
45
|
// it directly. Don't ALSO send Cmd+T (which would create a second tab the
|
|
46
46
|
// caller didn't ask for; reported by user during v0.6.1 verification).
|
|
47
|
+
//
|
|
48
|
+
// Caveat: if macOS "Reopen windows when logging back in" is on, Terminal
|
|
49
|
+
// may restore multiple tabs from a prior session. In that case launchedKeys
|
|
50
|
+
// has >1 entry and we return whichever Object.keys lists first — which is
|
|
51
|
+
// an idle tty the caller can use, but not strictly "the one our activate()
|
|
52
|
+
// caused to exist." Acceptable since the tool's contract is "give me a
|
|
53
|
+
// fresh idle tty," not "give me the exact tty just spawned."
|
|
47
54
|
const afterLaunch = snapshotTabs(terminal);
|
|
48
55
|
const launchedKeys = Object.keys(afterLaunch);
|
|
49
56
|
if (launchedKeys.length > 0) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"new_tab.js","sourceRoot":"","sources":["../../src/tools/new_tab.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,mBAAmB,EAAE,yBAAyB,EAAE,MAAM,sBAAsB,CAAC;AAEtF,MAAM,CAAC,MAAM,cAAc,GAAG
|
|
1
|
+
{"version":3,"file":"new_tab.js","sourceRoot":"","sources":["../../src/tools/new_tab.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,mBAAmB,EAAE,yBAAyB,EAAE,MAAM,sBAAsB,CAAC;AAEtF,MAAM,CAAC,MAAM,cAAc,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsF7B,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,aAAa;IACjC,IAAI,CAAC,mBAAmB,EAAE,EAAE,CAAC;QAC3B,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,yBAAyB,CAAC,kBAAkB,CAAC,EAAE,CAAC;YAChF,OAAO,EAAE,IAAI;SACd,CAAC;IACJ,CAAC;IACD,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,CAAC;QAC1C,MAAM,WAAW,CAAC,EAAE,IAAI,EAAE,kBAAkB,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,CAAC;QACpE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;IACrD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,MAAM,IAAI,GACR,GAAG,YAAY,cAAc,IAAI,iBAAiB,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC;YACjE,CAAC,CAAC,sFAAsF;YACxF,CAAC,CAAC,EAAE,CAAC;QACT,MAAM,WAAW,CAAC;YAChB,IAAI,EAAE,kBAAkB;YACxB,OAAO,EAAE,OAAO;YAChB,YAAY,EAAE,OAAO;SACtB,CAAC,CAAC;QACH,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,4BAA4B,OAAO,GAAG,IAAI,EAAE,EAAE,CAAC;YAC/E,OAAO,EAAE,IAAI;SACd,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,MAAiB;IACxC,MAAM,CAAC,YAAY,CACjB,kBAAkB,EAClB;QACE,WAAW,EACT,2nBAA2nB;KAC9nB,EACD,aAAa,CACd,CAAC;AACJ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@priyanshumit/macos-terminal-mcp",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.2",
|
|
4
4
|
"description": "MCP server exposing macOS Terminal.app to AI agents via AppleScript / JXA. List windows, read scrollback, execute commands, clear buffers — with three-tier safety patterns and confirmation dialogs.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|