@priyanshumit/macos-terminal-mcp 0.3.0 → 0.5.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/README.md CHANGED
@@ -1,10 +1,20 @@
1
- # macos-terminal-mcp
1
+ <p align="center">
2
+ <img src="./assets/logo.png" alt="macos-terminal-mcp" width="200" height="200" />
3
+ </p>
4
+
5
+ <h1 align="center">macos-terminal-mcp</h1>
6
+
7
+ <p align="center">
8
+ <a href="https://www.npmjs.com/package/@priyanshumit/macos-terminal-mcp"><img src="https://img.shields.io/npm/v/@priyanshumit/macos-terminal-mcp.svg" alt="npm version"></a>
9
+ <a href="https://github.com/priyanshumit/macos-terminal-mcp/actions/workflows/ci.yml"><img src="https://github.com/priyanshumit/macos-terminal-mcp/actions/workflows/ci.yml/badge.svg" alt="CI status"></a>
10
+ <a href="./LICENSE"><img src="https://img.shields.io/npm/l/@priyanshumit/macos-terminal-mcp.svg" alt="MIT license"></a>
11
+ </p>
2
12
 
3
13
  A local MCP server that lets AI agents inspect and drive your macOS Terminal.app tabs — list windows, read scrollback, execute commands, and clear buffers, all gated by a three-tier safety model plus per-call user confirmation for any write operation.
4
14
 
5
15
  ## What it does
6
16
 
7
- Eleven MCP tools across three categories:
17
+ Twelve MCP tools across three categories:
8
18
 
9
19
  ### Terminal interaction
10
20
 
@@ -12,8 +22,9 @@ Eleven MCP tools across three categories:
12
22
  |---|---|---|
13
23
  | `terminal_list` | read | Enumerate every open Terminal.app tab with tty, title, busy state, and foreground processes. |
14
24
  | `terminal_read` | read | Return the full buffer + scrollback of a specific tab, identified by tty. |
15
- | `terminal_execute` | **write** | Type a command into a specific tab and press Enter. Evaluated against the safety policy; runs auto/confirms/refuses depending on level. |
25
+ | `terminal_execute` | **write** | Type a command into a specific tab and press Enter. Refuses if the target tab is busy unless `force=true`. `dry_run=true` returns the safety verdict without any side effects. |
16
26
  | `terminal_clear` | **write** | Wipe scrollback of a specific tab via Cmd+K. Briefly steals focus. |
27
+ | `terminal_new_tab` | **write** | Open a new empty tab in Terminal.app and return its tty for follow-up calls. No dialog — low blast radius (user can close the tab). |
17
28
 
18
29
  ### Safety policy management
19
30
 
@@ -3,11 +3,13 @@ export class OsascriptError extends Error {
3
3
  stderr;
4
4
  code;
5
5
  timedOut;
6
- constructor(message, stderr, code, timedOut = false) {
6
+ aborted;
7
+ constructor(message, stderr, code, timedOut = false, aborted = false) {
7
8
  super(message);
8
9
  this.stderr = stderr;
9
10
  this.code = code;
10
11
  this.timedOut = timedOut;
12
+ this.aborted = aborted;
11
13
  this.name = "OsascriptError";
12
14
  }
13
15
  }
@@ -15,12 +17,30 @@ const DEFAULT_TIMEOUT_MS = 30_000;
15
17
  export function runJxa(script, options = {}) {
16
18
  const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
17
19
  return new Promise((resolve, reject) => {
20
+ // Fast-path: already-aborted signal — don't even spawn.
21
+ if (options.signal?.aborted) {
22
+ reject(new OsascriptError("osascript aborted before launch", "", -1, false, true));
23
+ return;
24
+ }
18
25
  const proc = spawn("osascript", ["-l", "JavaScript"], {
19
26
  stdio: ["pipe", "pipe", "pipe"],
20
27
  });
21
28
  let stdout = "";
22
29
  let stderr = "";
23
30
  let settled = false;
31
+ const onAbort = () => {
32
+ if (settled)
33
+ return;
34
+ settled = true;
35
+ try {
36
+ proc.kill("SIGKILL");
37
+ }
38
+ catch {
39
+ /* ignore */
40
+ }
41
+ clearTimeout(timer);
42
+ reject(new OsascriptError("osascript aborted", stderr.trim(), -1, false, true));
43
+ };
24
44
  const timer = setTimeout(() => {
25
45
  if (settled)
26
46
  return;
@@ -31,8 +51,12 @@ export function runJxa(script, options = {}) {
31
51
  catch {
32
52
  /* ignore */
33
53
  }
54
+ options.signal?.removeEventListener("abort", onAbort);
34
55
  reject(new OsascriptError(`osascript timed out after ${timeoutMs}ms`, stderr.trim(), -1, true));
35
56
  }, timeoutMs);
57
+ if (options.signal) {
58
+ options.signal.addEventListener("abort", onAbort, { once: true });
59
+ }
36
60
  proc.stdout.on("data", (chunk) => {
37
61
  stdout += chunk.toString("utf8");
38
62
  });
@@ -44,6 +68,7 @@ export function runJxa(script, options = {}) {
44
68
  return;
45
69
  settled = true;
46
70
  clearTimeout(timer);
71
+ options.signal?.removeEventListener("abort", onAbort);
47
72
  reject(err);
48
73
  });
49
74
  proc.on("close", (code) => {
@@ -51,6 +76,7 @@ export function runJxa(script, options = {}) {
51
76
  return;
52
77
  settled = true;
53
78
  clearTimeout(timer);
79
+ options.signal?.removeEventListener("abort", onAbort);
54
80
  if (code === 0) {
55
81
  resolve(stdout.replace(/\n$/, ""));
56
82
  }
@@ -1 +1 @@
1
- {"version":3,"file":"applescript.js","sourceRoot":"","sources":["../src/applescript.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"applescript.js","sourceRoot":"","sources":["../src/applescript.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { appendFile, mkdir } from "node:fs/promises";
1
+ import { appendFile, chmod, mkdir } from "node:fs/promises";
2
2
  import { homedir } from "node:os";
3
3
  import { dirname, join } from "node:path";
4
4
  function resolveDefaultPath() {
@@ -11,17 +11,31 @@ const COMMAND_TRUNCATE = 1000;
11
11
  function truncate(s, max) {
12
12
  return s.length > max ? `${s.slice(0, max)}…[+${s.length - max}]` : s;
13
13
  }
14
+ /**
15
+ * Append a JSONL audit entry. Best-effort — failures are logged to stderr but do
16
+ * not throw. Timestamp is always server-generated; callers cannot override it.
17
+ *
18
+ * Directory created with mode 0o700, file with mode 0o600. If the file already
19
+ * exists with wider permissions (e.g. from an older version), it is tightened
20
+ * to 0o600 on every write (no-op once already restricted).
21
+ */
14
22
  export async function appendAudit(entry, path = AUDIT_LOG_PATH) {
23
+ // Spread entry first, then always overwrite timestamp last so any type-cast
24
+ // bypass that smuggles a "timestamp" field in entry still loses to the
25
+ // server-generated value.
15
26
  const record = {
16
- timestamp: entry.timestamp ?? new Date().toISOString(),
17
27
  ...entry,
28
+ timestamp: new Date().toISOString(),
18
29
  };
19
30
  if (record.command !== undefined) {
20
31
  record.command = truncate(record.command, COMMAND_TRUNCATE);
21
32
  }
22
33
  try {
23
- await mkdir(dirname(path), { recursive: true });
24
- await appendFile(path, `${JSON.stringify(record)}\n`, "utf8");
34
+ await mkdir(dirname(path), { recursive: true, mode: 0o700 });
35
+ // Best-effort tighten of any pre-existing file permissions. Ignored if file
36
+ // doesn't yet exist (next appendFile creates it with mode 0o600 below).
37
+ await chmod(path, 0o600).catch(() => undefined);
38
+ await appendFile(path, `${JSON.stringify(record)}\n`, { encoding: "utf8", mode: 0o600 });
25
39
  }
26
40
  catch (err) {
27
41
  process.stderr.write(`[macos-terminal-mcp] audit log write failed: ${err.message}\n`);
@@ -1 +1 @@
1
- {"version":3,"file":"audit.js","sourceRoot":"","sources":["../../src/safety/audit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAmB1C,SAAS,kBAAkB;IACzB,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;IACvC,MAAM,IAAI,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC9E,OAAO,IAAI,CAAC,IAAI,EAAE,oBAAoB,EAAE,WAAW,CAAC,CAAC;AACvD,CAAC;AAED,MAAM,CAAC,MAAM,cAAc,GAAG,kBAAkB,EAAE,CAAC;AAEnD,MAAM,gBAAgB,GAAG,IAAI,CAAC;AAE9B,SAAS,QAAQ,CAAC,CAAS,EAAE,GAAW;IACtC,OAAO,CAAC,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,MAAM,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AACxE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,KAA6D,EAC7D,OAAe,cAAc;IAE7B,MAAM,MAAM,GAAe;QACzB,SAAS,EAAE,KAAK,CAAC,SAAS,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACtD,GAAG,KAAK;KACT,CAAC;IACF,IAAI,MAAM,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QACjC,MAAM,CAAC,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,OAAO,EAAE,gBAAgB,CAAC,CAAC;IAC9D,CAAC;IACD,IAAI,CAAC;QACH,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAChD,MAAM,UAAU,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAChE,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,gDAAiD,GAAa,CAAC,OAAO,IAAI,CAC3E,CAAC;IACJ,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"audit.js","sourceRoot":"","sources":["../../src/safety/audit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC5D,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAmB1C,SAAS,kBAAkB;IACzB,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;IACvC,MAAM,IAAI,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC9E,OAAO,IAAI,CAAC,IAAI,EAAE,oBAAoB,EAAE,WAAW,CAAC,CAAC;AACvD,CAAC;AAED,MAAM,CAAC,MAAM,cAAc,GAAG,kBAAkB,EAAE,CAAC;AAEnD,MAAM,gBAAgB,GAAG,IAAI,CAAC;AAE9B,SAAS,QAAQ,CAAC,CAAS,EAAE,GAAW;IACtC,OAAO,CAAC,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,MAAM,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AACxE,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,KAAoC,EACpC,OAAe,cAAc;IAE7B,4EAA4E;IAC5E,uEAAuE;IACvE,0BAA0B;IAC1B,MAAM,MAAM,GAAe;QACzB,GAAG,KAAK;QACR,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACpC,CAAC;IACF,IAAI,MAAM,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QACjC,MAAM,CAAC,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,OAAO,EAAE,gBAAgB,CAAC,CAAC;IAC9D,CAAC;IACD,IAAI,CAAC;QACH,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QAC7D,4EAA4E;QAC5E,wEAAwE;QACxE,MAAM,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QAChD,MAAM,UAAU,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC3F,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,gDAAiD,GAAa,CAAC,OAAO,IAAI,CAC3E,CAAC;IACJ,CAAC;AACH,CAAC"}
@@ -1,4 +1,4 @@
1
- import { runJxa } from "../applescript.js";
1
+ import { OsascriptError, runJxa } from "../applescript.js";
2
2
  export function isWriteToolsEnabled() {
3
3
  return process.env.WRITE_TOOLS_ENABLED === "1";
4
4
  }
@@ -32,8 +32,37 @@ app.includeStandardAdditions = true;
32
32
  `;
33
33
  // Outer osascript timeout is dialog timeout + 10s buffer so the dialog's own
34
34
  // givingUpAfter has a chance to fire before the spawn-level kill engages.
35
- const result = await runJxa(script, { timeoutMs: (timeoutSec + 10) * 1000 });
36
- return result.trim() === "ALLOW";
35
+ try {
36
+ const result = await runJxa(script, {
37
+ timeoutMs: (timeoutSec + 10) * 1000,
38
+ signal: req.signal,
39
+ });
40
+ return result.trim() === "ALLOW";
41
+ }
42
+ catch (err) {
43
+ // Aborted via signal — treat as denial. Caller is responsible for its own
44
+ // out-of-band approval path (e.g. queue resolution); we just dismiss the dialog.
45
+ if (err instanceof OsascriptError && err.aborted) {
46
+ return false;
47
+ }
48
+ throw err;
49
+ }
50
+ }
51
+ /**
52
+ * Strip C0 control characters (including newlines, tabs, CR) from AI-supplied
53
+ * strings before embedding them in confirmation dialog message templates.
54
+ *
55
+ * Without this, a model can inject fake structured fields like "Queue id: ..."
56
+ * or "Approval: GRANTED" inside a dialog's text by including newlines in its
57
+ * command/description, visually impersonating system-rendered content.
58
+ */
59
+ // Pattern is constructed via new RegExp(string) to avoid embedding literal
60
+ // control bytes in the source file (which Biome flags and which is also hard
61
+ // to audit visually). Matches C0 control characters (U+0000–U+001F) plus DEL.
62
+ // biome-ignore lint/complexity/useRegexLiterals: regex-literal form trips noControlCharactersInRegex on the same character class (escape sequences vs bytes both flagged). RegExp(string) avoids the false positive without obscuring intent.
63
+ const CONTROL_CHARS_RE = new RegExp("[\u0000-\u001F\u007F]", "g");
64
+ export function sanitizeAiText(s) {
65
+ return s.replace(CONTROL_CHARS_RE, " ");
37
66
  }
38
67
  export function writeToolsDisabledMessage(toolName) {
39
68
  return (`${toolName} is disabled. Write tools (terminal_execute, terminal_clear, safety_*) ` +
@@ -1 +1 @@
1
- {"version":3,"file":"confirm.js","sourceRoot":"","sources":["../../src/safety/confirm.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAE3C,MAAM,UAAU,mBAAmB;IACjC,OAAO,OAAO,CAAC,GAAG,CAAC,mBAAmB,KAAK,GAAG,CAAC;AACjD,CAAC;AAWD,MAAM,0BAA0B,GAAG,GAAG,CAAC;AAEvC,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,GAAmB;IACvD,MAAM,KAAK,GAAG,GAAG,CAAC,UAAU,IAAI,OAAO,CAAC;IACxC,MAAM,IAAI,GAAG,GAAG,CAAC,SAAS,IAAI,MAAM,CAAC;IACrC,MAAM,UAAU,GAAG,GAAG,CAAC,cAAc,IAAI,0BAA0B,CAAC;IACpE,MAAM,MAAM,GAAG;;;;;;QAMT,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC;;oBAEf,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;yBACzC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;wBACrB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;qBACvB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC;;yBAErB,UAAU;;;;uCAII,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;;;;;CAK3D,CAAC;IACA,6EAA6E;IAC7E,0EAA0E;IAC1E,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,CAAC,UAAU,GAAG,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC;IAC7E,OAAO,MAAM,CAAC,IAAI,EAAE,KAAK,OAAO,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,QAAgB;IACxD,OAAO,CACL,GAAG,QAAQ,yEAAyE;QACpF,qEAAqE;QACrE,4EAA4E;QAC5E,0CAA0C,CAC3C,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"confirm.js","sourceRoot":"","sources":["../../src/safety/confirm.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAE3D,MAAM,UAAU,mBAAmB;IACjC,OAAO,OAAO,CAAC,GAAG,CAAC,mBAAmB,KAAK,GAAG,CAAC;AACjD,CAAC;AAaD,MAAM,0BAA0B,GAAG,GAAG,CAAC;AAEvC,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,GAAmB;IACvD,MAAM,KAAK,GAAG,GAAG,CAAC,UAAU,IAAI,OAAO,CAAC;IACxC,MAAM,IAAI,GAAG,GAAG,CAAC,SAAS,IAAI,MAAM,CAAC;IACrC,MAAM,UAAU,GAAG,GAAG,CAAC,cAAc,IAAI,0BAA0B,CAAC;IACpE,MAAM,MAAM,GAAG;;;;;;QAMT,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC;;oBAEf,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;yBACzC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;wBACrB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;qBACvB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC;;yBAErB,UAAU;;;;uCAII,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;;;;;CAK3D,CAAC;IACA,6EAA6E;IAC7E,0EAA0E;IAC1E,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,EAAE;YAClC,SAAS,EAAE,CAAC,UAAU,GAAG,EAAE,CAAC,GAAG,IAAI;YACnC,MAAM,EAAE,GAAG,CAAC,MAAM;SACnB,CAAC,CAAC;QACH,OAAO,MAAM,CAAC,IAAI,EAAE,KAAK,OAAO,CAAC;IACnC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,0EAA0E;QAC1E,iFAAiF;QACjF,IAAI,GAAG,YAAY,cAAc,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC;YACjD,OAAO,KAAK,CAAC;QACf,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,2EAA2E;AAC3E,6EAA6E;AAC7E,8EAA8E;AAC9E,8OAA8O;AAC9O,MAAM,gBAAgB,GAAG,IAAI,MAAM,CAAC,uBAAuB,EAAE,GAAG,CAAC,CAAC;AAElE,MAAM,UAAU,cAAc,CAAC,CAAS;IACtC,OAAO,CAAC,CAAC,OAAO,CAAC,gBAAgB,EAAE,GAAG,CAAC,CAAC;AAC1C,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,QAAgB;IACxD,OAAO,CACL,GAAG,QAAQ,yEAAyE;QACpF,qEAAqE;QACrE,4EAA4E;QAC5E,0CAA0C,CAC3C,CAAC;AACJ,CAAC"}
@@ -1,6 +1,27 @@
1
1
  import { mkdir, readFile, writeFile } from "node:fs/promises";
2
2
  import { homedir } from "node:os";
3
3
  import { dirname, join } from "node:path";
4
+ import safeRegex from "safe-regex";
5
+ /**
6
+ * Reason a pattern is rejected, or null if the pattern is valid + safe.
7
+ * "Safe" here means: does not contain catastrophic-backtracking constructs
8
+ * (e.g. (a+)+b, (\w+)+!) that would let a single pattern DoS the server.
9
+ */
10
+ export function regexErrorReason(pattern) {
11
+ try {
12
+ new RegExp(pattern);
13
+ }
14
+ catch (e) {
15
+ return `not a valid regex: ${e.message}`;
16
+ }
17
+ if (!safeRegex(pattern)) {
18
+ return "contains a ReDoS-prone construct (nested quantifiers, overlapping repeats, or ambiguous alternations)";
19
+ }
20
+ return null;
21
+ }
22
+ export function isSafePattern(pattern) {
23
+ return regexErrorReason(pattern) === null;
24
+ }
4
25
  export const SAFETY_CONFIG_PATH = join(homedir(), ".config", "macos-terminal-mcp", "safety.json");
5
26
  const DEFAULT_PATTERNS = [
6
27
  // FORBIDDEN — never run, even with confirmation. The user must run these in a terminal themselves.
@@ -98,14 +119,21 @@ export async function saveSafetyConfig(config, path = SAFETY_CONFIG_PATH) {
98
119
  export function defaultPatterns() {
99
120
  return DEFAULT_PATTERNS.map((p) => ({ ...p }));
100
121
  }
122
+ function filterSafePatterns(patterns) {
123
+ return patterns.filter((e) => {
124
+ if (isSafePattern(e.pattern))
125
+ return true;
126
+ process.stderr.write(`[macos-terminal-mcp] dropping unsafe pattern from config: ${JSON.stringify(e.pattern)} (${regexErrorReason(e.pattern) ?? "unknown"})\n`);
127
+ return false;
128
+ });
129
+ }
101
130
  export function normalizeConfig(raw) {
102
131
  if (!raw || typeof raw !== "object")
103
132
  return { patterns: DEFAULT_PATTERNS };
104
133
  const o = raw;
105
134
  if (Array.isArray(o.patterns)) {
106
- return {
107
- patterns: o.patterns.filter((e) => isValidEntry(e)),
108
- };
135
+ const valid = o.patterns.filter((e) => isValidEntry(e));
136
+ return { patterns: filterSafePatterns(valid) };
109
137
  }
110
138
  // Migrate v1 schema {allowlist: [], denylist: []} → v2 {patterns: [...]}
111
139
  if (Array.isArray(o.allowlist) || Array.isArray(o.denylist)) {
@@ -132,7 +160,8 @@ export function normalizeConfig(raw) {
132
160
  }
133
161
  }
134
162
  }
135
- return { patterns: patterns.length > 0 ? patterns : DEFAULT_PATTERNS };
163
+ const filtered = filterSafePatterns(patterns);
164
+ return { patterns: filtered.length > 0 ? filtered : DEFAULT_PATTERNS };
136
165
  }
137
166
  return { patterns: DEFAULT_PATTERNS };
138
167
  }
@@ -150,9 +179,13 @@ const LEVEL_RANK = {
150
179
  forbidden: 2,
151
180
  };
152
181
  export function evaluateCommand(command, config) {
182
+ // Normalize via NFKC so fullwidth/compatibility Unicode characters fold to
183
+ // their ASCII equivalents. Closes the rm -rf homoglyph bypass — a model
184
+ // submitting Unicode lookalikes can't sneak past patterns using \b assertions.
185
+ const normalized = command.normalize("NFKC");
153
186
  let result = null;
154
187
  for (const entry of config.patterns) {
155
- if (!testPattern(entry.pattern, command))
188
+ if (!testPattern(entry.pattern, normalized))
156
189
  continue;
157
190
  if (!result || LEVEL_RANK[entry.level] > LEVEL_RANK[result.level]) {
158
191
  result = {
@@ -1 +1 @@
1
- {"version":3,"file":"patterns.js","sourceRoot":"","sources":["../../src/safety/patterns.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"patterns.js","sourceRoot":"","sources":["../../src/safety/patterns.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import { z } from "zod";
2
2
  import { OsascriptError, runJxa } from "../applescript.js";
3
3
  import { appendAudit } from "../safety/audit.js";
4
- import { confirmWithUser, isWriteToolsEnabled, writeToolsDisabledMessage, } from "../safety/confirm.js";
4
+ import { confirmWithUser, isWriteToolsEnabled, sanitizeAiText, writeToolsDisabledMessage, } from "../safety/confirm.js";
5
5
  import { evaluateCommand, loadSafetyConfig } from "../safety/patterns.js";
6
6
  import { enqueue, resolvePending } from "../safety/queue.js";
7
7
  export function buildExecuteScript(tty, command) {
@@ -25,10 +25,30 @@ function safe(fn) { try { return fn(); } catch (e) { return null; } }
25
25
  })(${JSON.stringify(tty)}, ${JSON.stringify(command)});
26
26
  `;
27
27
  }
28
+ function buildBusyCheckScript(tty) {
29
+ return `
30
+ function safe(fn) { try { return fn(); } catch (e) { return null; } }
31
+ (function checkBusy(targetTty) {
32
+ const terminal = Application("Terminal");
33
+ const wins = terminal.windows();
34
+ for (let wi = 0; wi < wins.length; wi++) {
35
+ const w = wins[wi];
36
+ const tabs = w.tabs();
37
+ for (let ti = 0; ti < tabs.length; ti++) {
38
+ const t = tabs[ti];
39
+ if (safe(function () { return t.tty(); }) === targetTty) {
40
+ return safe(function () { return t.busy(); }) ? "busy" : "idle";
41
+ }
42
+ }
43
+ }
44
+ return "missing";
45
+ })(${JSON.stringify(tty)});
46
+ `;
47
+ }
28
48
  function truncate(s, max) {
29
49
  return s.length > max ? `${s.slice(0, max)}… [${s.length - max} chars elided]` : s;
30
50
  }
31
- export async function executeHandler({ tty, command }) {
51
+ export async function executeHandler({ tty, command, force = false, dry_run = false, }) {
32
52
  if (!isWriteToolsEnabled()) {
33
53
  return {
34
54
  content: [{ type: "text", text: writeToolsDisabledMessage("terminal_execute") }],
@@ -37,6 +57,27 @@ export async function executeHandler({ tty, command }) {
37
57
  }
38
58
  const config = await loadSafetyConfig();
39
59
  const verdict = evaluateCommand(command, config);
60
+ // dry_run short-circuits BEFORE any side effects (busy probe via JXA, audit
61
+ // log write, enqueue, dialog). Just compute and return what would happen.
62
+ if (dry_run) {
63
+ return {
64
+ content: [
65
+ {
66
+ type: "text",
67
+ text: JSON.stringify({
68
+ dry_run: true,
69
+ verdict: verdict.level,
70
+ matchedPattern: verdict.matchedPattern ?? null,
71
+ matchedDescription: verdict.matchedDescription ?? null,
72
+ wouldRefuse: verdict.level === "forbidden",
73
+ wouldPromptUser: verdict.level === "requires_approval",
74
+ wouldAutoRun: verdict.level === "safe",
75
+ note: "force/busy/permission checks are NOT evaluated in dry_run — only the safety policy verdict.",
76
+ }, null, 2),
77
+ },
78
+ ],
79
+ };
80
+ }
40
81
  if (verdict.level === "forbidden") {
41
82
  const descPart = verdict.matchedDescription ? ` (${verdict.matchedDescription})` : "";
42
83
  await appendAudit({
@@ -58,12 +99,60 @@ export async function executeHandler({ tty, command }) {
58
99
  isError: true,
59
100
  };
60
101
  }
102
+ // Busy-tab check (#33). do script types into the foreground process's stdin
103
+ // when the tab is busy, which is rarely what callers want — fail fast unless
104
+ // force=true is set explicitly.
105
+ if (!force) {
106
+ let busyStatus;
107
+ try {
108
+ busyStatus = (await runJxa(buildBusyCheckScript(tty))).trim();
109
+ }
110
+ catch (err) {
111
+ const message = err instanceof Error ? err.message : String(err);
112
+ return {
113
+ content: [
114
+ {
115
+ type: "text",
116
+ text: `terminal_execute failed to probe target tab busy state: ${message}`,
117
+ },
118
+ ],
119
+ isError: true,
120
+ };
121
+ }
122
+ if (busyStatus === "missing") {
123
+ return {
124
+ content: [{ type: "text", text: `No Terminal.app tab found with tty ${tty}.` }],
125
+ isError: true,
126
+ };
127
+ }
128
+ if (busyStatus === "busy") {
129
+ await appendAudit({
130
+ tool: "terminal_execute",
131
+ outcome: "refused",
132
+ tty,
133
+ command,
134
+ level: verdict.level,
135
+ matchedPattern: verdict.matchedPattern,
136
+ details: { reason: "target tab is busy" },
137
+ });
138
+ return {
139
+ content: [
140
+ {
141
+ type: "text",
142
+ text: `Refused: target tab ${tty} is busy with a running command. The command would be typed into the foreground process's stdin rather than executed. ` +
143
+ `Pass force=true if you genuinely want to send stdin, or wait for the running command to finish.`,
144
+ },
145
+ ],
146
+ isError: true,
147
+ };
148
+ }
149
+ }
61
150
  let resolutionSource = "auto";
62
151
  if (verdict.level === "requires_approval") {
63
152
  const descPart = verdict.matchedDescription
64
- ? `\nMatched: ${verdict.matchedPattern} (${verdict.matchedDescription})`
153
+ ? `\nMatched: ${sanitizeAiText(verdict.matchedPattern ?? "")} (${sanitizeAiText(verdict.matchedDescription)})`
65
154
  : verdict.matchedPattern
66
- ? `\nMatched pattern: ${verdict.matchedPattern}`
155
+ ? `\nMatched pattern: ${sanitizeAiText(verdict.matchedPattern)}`
67
156
  : "\nNo matching pattern — default policy requires approval.";
68
157
  const { id, promise } = enqueue({
69
158
  tty,
@@ -71,11 +160,23 @@ export async function executeHandler({ tty, command }) {
71
160
  matchedPattern: verdict.matchedPattern,
72
161
  matchedDescription: verdict.matchedDescription,
73
162
  });
74
- void confirmWithUser({
163
+ // If the queue resolves out-of-band (via pending_approve / pending_deny),
164
+ // abort the dialog so it disappears from the user's screen instead of
165
+ // dangling (reviewer #4).
166
+ const dialogAbort = new AbortController();
167
+ const dialogPromise = confirmWithUser({
75
168
  title: "macos-terminal-mcp · terminal_execute",
76
- message: `Run in ${tty}:\n\n${truncate(command, 800)}${descPart}\n\nQueue id: ${id}`,
77
- }).then((allowed) => resolvePending(id, allowed, "dialog"), () => undefined);
169
+ message: `Run in ${tty}:\n\n${sanitizeAiText(truncate(command, 800))}${descPart}\n\nQueue id: ${id}`,
170
+ signal: dialogAbort.signal,
171
+ });
172
+ void dialogPromise.then((allowed) => resolvePending(id, allowed, "dialog"), () => undefined);
78
173
  const result = await promise;
174
+ if (result.source !== "dialog") {
175
+ // Queue resolved first — dismiss the still-open dialog.
176
+ dialogAbort.abort();
177
+ // Let the dialog promise settle (rejected with aborted) before continuing.
178
+ await dialogPromise.catch(() => undefined);
179
+ }
79
180
  if (!result.approved) {
80
181
  const reasonPart = result.reason ? ` (${result.reason})` : "";
81
182
  await appendAudit({
@@ -105,6 +206,7 @@ export async function executeHandler({ tty, command }) {
105
206
  const path = verdict.level === "safe"
106
207
  ? `auto-run (safe pattern: ${verdict.matchedPattern})`
107
208
  : `approved via ${resolutionSource}`;
209
+ const forcedSuffix = force ? " [force=true]" : "";
108
210
  await appendAudit({
109
211
  tool: "terminal_execute",
110
212
  outcome: "success",
@@ -113,12 +215,13 @@ export async function executeHandler({ tty, command }) {
113
215
  level: verdict.level,
114
216
  matchedPattern: verdict.matchedPattern,
115
217
  source: verdict.level === "safe" ? "auto" : resolutionSource,
218
+ ...(force ? { details: { force: true } } : {}),
116
219
  });
117
220
  return {
118
221
  content: [
119
222
  {
120
223
  type: "text",
121
- text: `Executed in ${tty} [${path}]: ${truncate(command, 200)}`,
224
+ text: `Executed in ${tty} [${path}${forcedSuffix}]: ${truncate(command, 200)}`,
122
225
  },
123
226
  ],
124
227
  };
@@ -145,13 +248,21 @@ export async function executeHandler({ tty, command }) {
145
248
  }
146
249
  export function register(server) {
147
250
  server.registerTool("terminal_execute", {
148
- description: 'Run a shell command in a specific Terminal.app tab identified by its tty (e.g. "/dev/ttys003"). Behaves as if the command was typed by the user and Enter was pressed — output appears in the tab. Three-tier safety: "safe" patterns auto-run, "requires_approval" patterns trigger a native confirmation dialog, "forbidden" patterns are refused outright. Requires WRITE_TOOLS_ENABLED=1.',
251
+ description: 'Run a shell command in a specific Terminal.app tab identified by its tty (e.g. "/dev/ttys003"). Behaves as if the command was typed by the user and Enter was pressed — output appears in the tab. Three-tier safety: "safe" patterns auto-run, "requires_approval" patterns trigger a native confirmation dialog (with parallel async approval via pending_*), "forbidden" patterns are refused outright. Before any of that, the target tab is checked for busy state (a running foreground command) — busy tabs reject by default unless force=true is set. dry_run=true short-circuits before any side effects and returns just the verdict. Requires WRITE_TOOLS_ENABLED=1.',
149
252
  inputSchema: {
150
253
  tty: z
151
254
  .string()
152
255
  .regex(/^\/dev\/ttys[0-9]+$/)
153
256
  .describe('Target tab tty, e.g. "/dev/ttys003"'),
154
257
  command: z.string().min(1).max(8192).describe("Shell command to run in the target tab"),
258
+ force: z
259
+ .boolean()
260
+ .optional()
261
+ .describe("If true, bypass the busy-tab check. The command will be typed into the foreground process's stdin rather than executed. Default: false."),
262
+ dry_run: z
263
+ .boolean()
264
+ .optional()
265
+ .describe("If true, return the safety verdict and what WOULD happen without enqueueing, showing a dialog, or running anything. Useful for harnesses (or curious models) probing a call before allowing the real version."),
155
266
  },
156
267
  }, executeHandler);
157
268
  }
@@ -1 +1 @@
1
- {"version":3,"file":"execute.js","sourceRoot":"","sources":["../../src/tools/execute.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"execute.js","sourceRoot":"","sources":["../../src/tools/execute.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,70 @@
1
+ import { OsascriptError, runJxa } from "../applescript.js";
2
+ import { appendAudit } from "../safety/audit.js";
3
+ import { isWriteToolsEnabled, writeToolsDisabledMessage } from "../safety/confirm.js";
4
+ export const NEW_TAB_SCRIPT = `
5
+ function safe(fn) { try { return fn(); } catch (e) { return null; } }
6
+ (function newTab() {
7
+ const terminal = Application("Terminal");
8
+ terminal.activate();
9
+ const wins = terminal.windows();
10
+ // do script with empty command + no "in" → new window. With "in: front
11
+ // window" → new tab in that window. Prefer a new tab in the front window
12
+ // when one exists, otherwise let it create a new window.
13
+ let newTab;
14
+ if (wins.length > 0) {
15
+ newTab = terminal.doScript("", { in: wins[0] });
16
+ } else {
17
+ newTab = terminal.doScript("");
18
+ }
19
+ const tty = safe(function () { return newTab.tty(); }) || "";
20
+ let windowId = null;
21
+ try {
22
+ const after = terminal.windows();
23
+ for (let i = 0; i < after.length; i++) {
24
+ const ts = after[i].tabs();
25
+ for (let j = 0; j < ts.length; j++) {
26
+ if (safe(function () { return ts[j].tty(); }) === tty) {
27
+ windowId = safe(function () { return after[i].id(); });
28
+ break;
29
+ }
30
+ }
31
+ if (windowId !== null) break;
32
+ }
33
+ } catch (e) { /* best-effort */ }
34
+ return JSON.stringify({ tty, windowId });
35
+ })();
36
+ `;
37
+ export async function newTabHandler() {
38
+ if (!isWriteToolsEnabled()) {
39
+ return {
40
+ content: [{ type: "text", text: writeToolsDisabledMessage("terminal_new_tab") }],
41
+ isError: true,
42
+ };
43
+ }
44
+ try {
45
+ const json = await runJxa(NEW_TAB_SCRIPT);
46
+ await appendAudit({ tool: "terminal_new_tab", outcome: "success" });
47
+ return { content: [{ type: "text", text: json }] };
48
+ }
49
+ catch (err) {
50
+ const message = err instanceof Error ? err.message : String(err);
51
+ const hint = err instanceof OsascriptError && /not authorized/i.test(err.stderr)
52
+ ? "\nAutomation permission missing — System Settings → Privacy & Security → Automation."
53
+ : "";
54
+ await appendAudit({
55
+ tool: "terminal_new_tab",
56
+ outcome: "error",
57
+ errorMessage: message,
58
+ });
59
+ return {
60
+ content: [{ type: "text", text: `terminal_new_tab failed: ${message}${hint}` }],
61
+ isError: true,
62
+ };
63
+ }
64
+ }
65
+ export function register(server) {
66
+ 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).",
68
+ }, newTabHandler);
69
+ }
70
+ //# sourceMappingURL=new_tab.js.map
@@ -0,0 +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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgC7B,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,sdAAsd;KACzd,EACD,aAAa,CACd,CAAC;AACJ,CAAC"}
@@ -1,6 +1,6 @@
1
1
  import { z } from "zod";
2
2
  import { appendAudit } from "../safety/audit.js";
3
- import { confirmWithUser, isWriteToolsEnabled, writeToolsDisabledMessage, } from "../safety/confirm.js";
3
+ import { confirmWithUser, isWriteToolsEnabled, sanitizeAiText, writeToolsDisabledMessage, } from "../safety/confirm.js";
4
4
  import { getPending, listPending, resolvePending } from "../safety/queue.js";
5
5
  function asTextResult(text, isError = false) {
6
6
  return { content: [{ type: "text", text }], ...(isError ? { isError } : {}) };
@@ -35,15 +35,15 @@ function registerApprove(server) {
35
35
  return asTextResult(`No pending entry with id ${id} (expired, already resolved, or never existed).`, true);
36
36
  }
37
37
  const descPart = entry.matchedDescription
38
- ? `\nMatched: ${entry.matchedPattern} (${entry.matchedDescription})`
38
+ ? `\nMatched: ${sanitizeAiText(entry.matchedPattern ?? "")} (${sanitizeAiText(entry.matchedDescription)})`
39
39
  : entry.matchedPattern
40
- ? `\nMatched pattern: ${entry.matchedPattern}`
40
+ ? `\nMatched pattern: ${sanitizeAiText(entry.matchedPattern)}`
41
41
  : "";
42
42
  const allowed = await confirmWithUser({
43
43
  title: "macos-terminal-mcp · pending_approve",
44
44
  message: `Approve queued command?\n\n` +
45
45
  `Target: ${entry.tty}\n` +
46
- `Command: ${truncate(entry.command, 800)}${descPart}\n` +
46
+ `Command: ${sanitizeAiText(truncate(entry.command, 800))}${descPart}\n` +
47
47
  `Queue id: ${id}`,
48
48
  });
49
49
  if (!allowed) {
@@ -91,12 +91,12 @@ function registerDeny(server) {
91
91
  if (!entry) {
92
92
  return asTextResult(`No pending entry with id ${id} (expired, already resolved, or never existed).`, true);
93
93
  }
94
- const reasonPart = reason ? `\n\nReason: ${reason}` : "";
94
+ const reasonPart = reason ? `\n\nReason: ${sanitizeAiText(reason)}` : "";
95
95
  const allowed = await confirmWithUser({
96
96
  title: "macos-terminal-mcp · pending_deny",
97
97
  message: `Deny queued command?\n\n` +
98
98
  `Target: ${entry.tty}\n` +
99
- `Command: ${truncate(entry.command, 800)}\n` +
99
+ `Command: ${sanitizeAiText(truncate(entry.command, 800))}\n` +
100
100
  `Queue id: ${id}${reasonPart}`,
101
101
  });
102
102
  if (!allowed) {
@@ -1 +1 @@
1
- {"version":3,"file":"pending.js","sourceRoot":"","sources":["../../src/tools/pending.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"pending.js","sourceRoot":"","sources":["../../src/tools/pending.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  import * as clear from "./clear.js";
2
2
  import * as execute from "./execute.js";
3
3
  import * as list from "./list.js";
4
+ import * as newTab from "./new_tab.js";
4
5
  import * as pending from "./pending.js";
5
6
  import * as read from "./read.js";
6
7
  import * as safety from "./safety.js";
@@ -9,6 +10,7 @@ export function registerAll(server) {
9
10
  read.register(server);
10
11
  execute.register(server);
11
12
  clear.register(server);
13
+ newTab.register(server);
12
14
  safety.register(server);
13
15
  pending.register(server);
14
16
  }
@@ -1 +1 @@
1
- {"version":3,"file":"register.js","sourceRoot":"","sources":["../../src/tools/register.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,YAAY,CAAC;AACpC,OAAO,KAAK,OAAO,MAAM,cAAc,CAAC;AACxC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,OAAO,MAAM,cAAc,CAAC;AACxC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AAEtC,MAAM,UAAU,WAAW,CAAC,MAAiB;IAC3C,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IACtB,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IACtB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IACzB,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IACvB,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AAC3B,CAAC"}
1
+ {"version":3,"file":"register.js","sourceRoot":"","sources":["../../src/tools/register.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,YAAY,CAAC;AACpC,OAAO,KAAK,OAAO,MAAM,cAAc,CAAC;AACxC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,MAAM,MAAM,cAAc,CAAC;AACvC,OAAO,KAAK,OAAO,MAAM,cAAc,CAAC;AACxC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AAEtC,MAAM,UAAU,WAAW,CAAC,MAAiB;IAC3C,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IACtB,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IACtB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IACzB,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IACvB,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IACxB,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AAC3B,CAAC"}
@@ -1,17 +1,8 @@
1
1
  import { z } from "zod";
2
2
  import { appendAudit } from "../safety/audit.js";
3
- import { confirmWithUser, isWriteToolsEnabled, writeToolsDisabledMessage, } from "../safety/confirm.js";
4
- import { loadSafetyConfig, saveSafetyConfig, } from "../safety/patterns.js";
3
+ import { confirmWithUser, isWriteToolsEnabled, sanitizeAiText, writeToolsDisabledMessage, } from "../safety/confirm.js";
4
+ import { loadSafetyConfig, regexErrorReason, saveSafetyConfig, } from "../safety/patterns.js";
5
5
  const LEVEL_VALUES = ["safe", "requires_approval", "forbidden"];
6
- function isValidRegex(pattern) {
7
- try {
8
- new RegExp(pattern);
9
- return true;
10
- }
11
- catch {
12
- return false;
13
- }
14
- }
15
6
  function asTextResult(text, isError = false) {
16
7
  return { content: [{ type: "text", text }], ...(isError ? { isError } : {}) };
17
8
  }
@@ -54,19 +45,20 @@ function registerAdd(server) {
54
45
  if (!isWriteToolsEnabled()) {
55
46
  return asTextResult(writeToolsDisabledMessage("safety_add"), true);
56
47
  }
57
- if (!isValidRegex(pattern)) {
58
- return asTextResult(`Refused: "${pattern}" is not a valid regex.`, true);
48
+ const reason = regexErrorReason(pattern);
49
+ if (reason !== null) {
50
+ return asTextResult(`Refused: pattern ${JSON.stringify(pattern)} ${reason}.`, true);
59
51
  }
60
52
  const config = await loadSafetyConfig();
61
53
  const existing = config.patterns.find((p) => p.pattern === pattern);
62
54
  if (existing) {
63
55
  return asTextResult(`Pattern already exists with level "${existing.level}". Use safety_set_level to change it.`, true);
64
56
  }
65
- const descLine = description ? `\nDescription: ${description}` : "";
57
+ const descLine = description ? `\nDescription: ${sanitizeAiText(description)}` : "";
66
58
  const allowed = await confirmWithUser({
67
59
  title: "macos-terminal-mcp · safety_add",
68
60
  message: `Add safety pattern?\n\n` +
69
- `Pattern: ${pattern}\n` +
61
+ `Pattern: ${sanitizeAiText(pattern)}\n` +
70
62
  `Level: ${describeLevel(level)}` +
71
63
  descLine,
72
64
  });
@@ -80,8 +72,15 @@ function registerAdd(server) {
80
72
  });
81
73
  return asTextResult("User denied the safety policy change.", true);
82
74
  }
75
+ // Re-read after dialog approval — the 5-minute dialog window is long
76
+ // enough for another concurrent mutator to have changed the file. Apply
77
+ // our change to the freshest config we can read, not the pre-dialog snapshot.
78
+ const fresh = await loadSafetyConfig();
79
+ if (fresh.patterns.some((p) => p.pattern === pattern)) {
80
+ return asTextResult(`Pattern was added by another action while this dialog was open. Re-run safety_add if you still want to apply this change.`, true);
81
+ }
83
82
  const newEntry = { pattern, level, ...(description ? { description } : {}) };
84
- const updated = { patterns: [...config.patterns, newEntry] };
83
+ const updated = { patterns: [...fresh.patterns, newEntry] };
85
84
  await saveSafetyConfig(updated);
86
85
  await appendAudit({
87
86
  tool: "safety_add",
@@ -114,11 +113,13 @@ function registerRemove(server) {
114
113
  const warning = existing.level === "forbidden"
115
114
  ? "⚠ WARNING: this pattern is currently FORBIDDEN. Removing it weakens safety.\n\n"
116
115
  : "";
117
- const descLine = existing.description ? `\nDescription: ${existing.description}` : "";
116
+ const descLine = existing.description
117
+ ? `\nDescription: ${sanitizeAiText(existing.description)}`
118
+ : "";
118
119
  const allowed = await confirmWithUser({
119
120
  title: "macos-terminal-mcp · safety_remove",
120
121
  message: `${warning}Remove safety pattern?\n\n` +
121
- `Pattern: ${pattern}\n` +
122
+ `Pattern: ${sanitizeAiText(pattern)}\n` +
122
123
  `Current level: ${describeLevel(existing.level)}` +
123
124
  descLine,
124
125
  });
@@ -132,8 +133,13 @@ function registerRemove(server) {
132
133
  });
133
134
  return asTextResult("User denied the safety policy change.", true);
134
135
  }
136
+ // Re-read after dialog approval (see safety_add for rationale).
137
+ const fresh = await loadSafetyConfig();
138
+ if (!fresh.patterns.some((p) => p.pattern === pattern)) {
139
+ return asTextResult(`Pattern was already removed by another action while this dialog was open.`, true);
140
+ }
135
141
  const updated = {
136
- patterns: config.patterns.filter((p) => p.pattern !== pattern),
142
+ patterns: fresh.patterns.filter((p) => p.pattern !== pattern),
137
143
  };
138
144
  await saveSafetyConfig(updated);
139
145
  await appendAudit({
@@ -174,7 +180,7 @@ function registerSetLevel(server) {
174
180
  const allowed = await confirmWithUser({
175
181
  title: "macos-terminal-mcp · safety_set_level",
176
182
  message: `${warning}Change pattern level?\n\n` +
177
- `Pattern: ${pattern}\n` +
183
+ `Pattern: ${sanitizeAiText(pattern)}\n` +
178
184
  `From: ${describeLevel(existing.level)}\n` +
179
185
  `To: ${describeLevel(level)}`,
180
186
  });
@@ -189,8 +195,17 @@ function registerSetLevel(server) {
189
195
  });
190
196
  return asTextResult("User denied the safety policy change.", true);
191
197
  }
198
+ // Re-read after dialog approval (see safety_add for rationale).
199
+ const fresh = await loadSafetyConfig();
200
+ const freshExisting = fresh.patterns.find((p) => p.pattern === pattern);
201
+ if (!freshExisting) {
202
+ return asTextResult(`Pattern was removed by another action while this dialog was open.`, true);
203
+ }
204
+ if (freshExisting.level === level) {
205
+ return asTextResult(`Pattern is already at level ${level} (changed by another action while this dialog was open).`);
206
+ }
192
207
  const updated = {
193
- patterns: config.patterns.map((p) => (p.pattern === pattern ? { ...p, level } : p)),
208
+ patterns: fresh.patterns.map((p) => (p.pattern === pattern ? { ...p, level } : p)),
194
209
  };
195
210
  await saveSafetyConfig(updated);
196
211
  await appendAudit({
@@ -1 +1 @@
1
- {"version":3,"file":"safety.js","sourceRoot":"","sources":["../../src/tools/safety.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"safety.js","sourceRoot":"","sources":["../../src/tools/safety.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@priyanshumit/macos-terminal-mcp",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
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": {
@@ -25,6 +25,8 @@
25
25
  },
26
26
  "dependencies": {
27
27
  "@modelcontextprotocol/sdk": "^1.28.0",
28
+ "@types/safe-regex": "^1.1.6",
29
+ "safe-regex": "^2.1.1",
28
30
  "zod": "^3.23.0"
29
31
  },
30
32
  "devDependencies": {