@priyanshumit/macos-terminal-mcp 0.5.0 → 0.5.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/tools/new_tab.js +41 -25
- package/dist/tools/new_tab.js.map +1 -1
- package/package.json +1 -1
package/dist/tools/new_tab.js
CHANGED
|
@@ -2,36 +2,52 @@ import { OsascriptError, runJxa } from "../applescript.js";
|
|
|
2
2
|
import { appendAudit } from "../safety/audit.js";
|
|
3
3
|
import { isWriteToolsEnabled, writeToolsDisabledMessage } from "../safety/confirm.js";
|
|
4
4
|
export const NEW_TAB_SCRIPT = `
|
|
5
|
+
var app = Application.currentApplication();
|
|
6
|
+
app.includeStandardAdditions = true;
|
|
5
7
|
function safe(fn) { try { return fn(); } catch (e) { return null; } }
|
|
8
|
+
function snapshotTabs(terminal) {
|
|
9
|
+
// Returns { tty -> windowId } for every tab in every window.
|
|
10
|
+
const out = {};
|
|
11
|
+
const wins = terminal.windows();
|
|
12
|
+
for (let wi = 0; wi < wins.length; wi++) {
|
|
13
|
+
const winId = safe(function () { return wins[wi].id(); });
|
|
14
|
+
const tabs = wins[wi].tabs();
|
|
15
|
+
for (let ti = 0; ti < tabs.length; ti++) {
|
|
16
|
+
const t = safe(function () { return tabs[ti].tty(); });
|
|
17
|
+
if (t) out[t] = winId;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return out;
|
|
21
|
+
}
|
|
6
22
|
(function newTab() {
|
|
7
23
|
const terminal = Application("Terminal");
|
|
24
|
+
const systemEvents = Application("System Events");
|
|
8
25
|
terminal.activate();
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
if (safe(function () { return ts[j].tty(); }) === tty) {
|
|
27
|
-
windowId = safe(function () { return after[i].id(); });
|
|
28
|
-
break;
|
|
29
|
-
}
|
|
26
|
+
const before = snapshotTabs(terminal);
|
|
27
|
+
const wasEmpty = Object.keys(before).length === 0;
|
|
28
|
+
// Cmd+T opens a new tab in the front window; Cmd+N opens a new window when
|
|
29
|
+
// there are none.
|
|
30
|
+
systemEvents.keystroke(wasEmpty ? "n" : "t", { using: "command down" });
|
|
31
|
+
// Poll for the new tab's tty to appear. Each iteration waits 100ms, up to ~2s.
|
|
32
|
+
let newTty = null;
|
|
33
|
+
let newWindowId = null;
|
|
34
|
+
for (let attempt = 0; attempt < 20; attempt++) {
|
|
35
|
+
delay(0.1);
|
|
36
|
+
const after = snapshotTabs(terminal);
|
|
37
|
+
const keys = Object.keys(after);
|
|
38
|
+
for (let i = 0; i < keys.length; i++) {
|
|
39
|
+
if (!(keys[i] in before)) {
|
|
40
|
+
newTty = keys[i];
|
|
41
|
+
newWindowId = after[keys[i]];
|
|
42
|
+
break;
|
|
30
43
|
}
|
|
31
|
-
if (windowId !== null) break;
|
|
32
44
|
}
|
|
33
|
-
|
|
34
|
-
|
|
45
|
+
if (newTty !== null) break;
|
|
46
|
+
}
|
|
47
|
+
if (newTty === null) {
|
|
48
|
+
throw new Error("terminal_new_tab: no new tab appeared after Cmd+" + (wasEmpty ? "N" : "T") + ". Accessibility permission may be missing — grant via System Settings → Privacy & Security → Accessibility.");
|
|
49
|
+
}
|
|
50
|
+
return JSON.stringify({ tty: newTty, windowId: newWindowId });
|
|
35
51
|
})();
|
|
36
52
|
`;
|
|
37
53
|
export async function newTabHandler() {
|
|
@@ -64,7 +80,7 @@ export async function newTabHandler() {
|
|
|
64
80
|
}
|
|
65
81
|
export function register(server) {
|
|
66
82
|
server.registerTool("terminal_new_tab", {
|
|
67
|
-
description: "Open a new empty tab in Terminal.app (in the frontmost window, or a new window if none are open). Returns {tty, windowId} for the new tab. Use the returned tty in subsequent terminal_read / terminal_execute calls. NOTE: this tool does NOT execute any command in the new tab — to run a command, call terminal_execute against the returned tty. Requires WRITE_TOOLS_ENABLED=1 but does NOT pop a confirmation dialog (low blast radius — the user can close an unwanted tab).",
|
|
83
|
+
description: "Open a new empty tab in Terminal.app (in the frontmost window, or a new window if none are open). Returns {tty, windowId} for the new tab. Use the returned tty in subsequent terminal_read / terminal_execute calls. NOTE: this tool does NOT execute any command in the new tab — to run a command, call terminal_execute against the returned tty. Requires WRITE_TOOLS_ENABLED=1 but does NOT pop a confirmation dialog (low blast radius — the user can close an unwanted tab). Briefly steals focus to Terminal.app to deliver a Cmd+T keystroke, so also requires Accessibility permission (System Settings → Privacy & Security → Accessibility).",
|
|
68
84
|
}, newTabHandler);
|
|
69
85
|
}
|
|
70
86
|
//# sourceMappingURL=new_tab.js.map
|
|
@@ -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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgD7B,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.5.
|
|
3
|
+
"version": "0.5.1",
|
|
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": {
|