terminal-commands 0.2.0 → 0.2.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/agent.js CHANGED
@@ -35857,19 +35857,33 @@ function assertActive(signal) {
35857
35857
  );
35858
35858
  }
35859
35859
  }
35860
- async function authorizeToolCall(tool, args, allowDestructive, approve, signal) {
35860
+ async function authorizeToolCall(tool, args, allowDestructive, approve, signal, progress) {
35861
+ const notify = (phase) => {
35862
+ try {
35863
+ progress?.(phase);
35864
+ } catch {
35865
+ }
35866
+ };
35861
35867
  assertActive(signal);
35862
35868
  if (!destructiveTools.has(tool)) return;
35863
35869
  if (!allowDestructive) {
35870
+ notify("denied");
35864
35871
  throw new Error(
35865
35872
  "This action requires local approval. Commands and writes are disabled unless explicitly enabled."
35866
35873
  );
35867
35874
  }
35868
- if (!approve || !await approve(tool, args, signal)) {
35875
+ if (!approve) {
35876
+ notify("denied");
35877
+ throw new Error("The action was not approved on the connected machine.");
35878
+ }
35879
+ notify("awaiting_approval");
35880
+ if (!await approve(tool, args, signal)) {
35869
35881
  assertActive(signal);
35882
+ notify("denied");
35870
35883
  throw new Error("The action was not approved on the connected machine.");
35871
35884
  }
35872
35885
  assertActive(signal);
35886
+ notify("approved");
35873
35887
  }
35874
35888
  async function connectOnce(options, acknowledged) {
35875
35889
  const { config: config3, signal } = options;
@@ -35880,7 +35894,7 @@ async function connectOnce(options, acknowledged) {
35880
35894
  }
35881
35895
  const client = new Client({
35882
35896
  name: "terminal-commands-cli",
35883
- version: "0.2.0"
35897
+ version: "0.2.1"
35884
35898
  });
35885
35899
  let disposeSocket;
35886
35900
  try {
@@ -35902,6 +35916,7 @@ async function connectOnce(options, acknowledged) {
35902
35916
  });
35903
35917
  disposeSocket = () => socket.terminate();
35904
35918
  const pending = /* @__PURE__ */ new Map();
35919
+ let requestProgressEnabled = false;
35905
35920
  const forwarder = new ProcessEventForwarder(
35906
35921
  async (name, args) => client.callTool({ name, arguments: args }),
35907
35922
  (message) => {
@@ -35952,6 +35967,7 @@ async function connectOnce(options, acknowledged) {
35952
35967
  return;
35953
35968
  }
35954
35969
  if (message && typeof message === "object" && "type" in message && message.type === "ready") {
35970
+ requestProgressEnabled = message.requestProgressVersion === 1;
35955
35971
  void forwarder.recover().catch(
35956
35972
  (error62) => options.log?.(
35957
35973
  "Could not recover local process streams: " + (error62 instanceof Error ? error62.message : "unknown error")
@@ -35963,7 +35979,15 @@ async function connectOnce(options, acknowledged) {
35963
35979
  options.log?.("Ignoring a malformed gateway message.");
35964
35980
  return;
35965
35981
  }
35966
- void handleMessage(options, client, socket, raw, pending, forwarder);
35982
+ void handleMessage(
35983
+ options,
35984
+ client,
35985
+ socket,
35986
+ raw,
35987
+ pending,
35988
+ forwarder,
35989
+ requestProgressEnabled
35990
+ );
35967
35991
  });
35968
35992
  socket.on("close", () => {
35969
35993
  forwarder.close();
@@ -35978,7 +36002,7 @@ async function connectOnce(options, acknowledged) {
35978
36002
  await client.close().catch(() => void 0);
35979
36003
  }
35980
36004
  }
35981
- async function handleMessage(options, client, socket, raw, pending, forwarder) {
36005
+ async function handleMessage(options, client, socket, raw, pending, forwarder, requestProgressEnabled) {
35982
36006
  let requestId;
35983
36007
  let controller2;
35984
36008
  let deadlineTimer;
@@ -36015,12 +36039,37 @@ async function handleMessage(options, client, socket, raw, pending, forwarder) {
36015
36039
  () => controller2?.abort(),
36016
36040
  Math.max(0, deadlineAt - Date.now())
36017
36041
  );
36042
+ let progressSequence = 0;
36043
+ const progress = (phase) => {
36044
+ if (!requestProgressEnabled || parsed.data.tool !== "start_process" || socket.readyState !== wrapper_default.OPEN)
36045
+ return;
36046
+ if (socket.bufferedAmount > 512e3) {
36047
+ socket.close(1013, "Request progress backpressure");
36048
+ return;
36049
+ }
36050
+ try {
36051
+ socket.send(
36052
+ JSON.stringify({
36053
+ type: "request_progress",
36054
+ requestId,
36055
+ sequence: ++progressSequence,
36056
+ phase,
36057
+ ...phase === "approved" ? {
36058
+ approvalMode: options.config.MACHINE_TERMINAL_AUTO_APPROVE === "1" ? "automatic" : "manual"
36059
+ } : {}
36060
+ })
36061
+ );
36062
+ } catch {
36063
+ }
36064
+ };
36065
+ progress("received");
36018
36066
  await authorizeToolCall(
36019
36067
  parsed.data.tool,
36020
36068
  parsed.data.arguments,
36021
36069
  options.config.MACHINE_TERMINAL_AGENT_ALLOW_DESTRUCTIVE === "1",
36022
36070
  options.approve,
36023
- controller2.signal
36071
+ controller2.signal,
36072
+ progress
36024
36073
  );
36025
36074
  assertActive(controller2.signal);
36026
36075
  const result = await client.callTool({
package/dist/cli.js CHANGED
@@ -35866,19 +35866,33 @@ function assertActive(signal) {
35866
35866
  );
35867
35867
  }
35868
35868
  }
35869
- async function authorizeToolCall(tool, args, allowDestructive, approve, signal) {
35869
+ async function authorizeToolCall(tool, args, allowDestructive, approve, signal, progress) {
35870
+ const notify = (phase) => {
35871
+ try {
35872
+ progress?.(phase);
35873
+ } catch {
35874
+ }
35875
+ };
35870
35876
  assertActive(signal);
35871
35877
  if (!destructiveTools.has(tool)) return;
35872
35878
  if (!allowDestructive) {
35879
+ notify("denied");
35873
35880
  throw new Error(
35874
35881
  "This action requires local approval. Commands and writes are disabled unless explicitly enabled."
35875
35882
  );
35876
35883
  }
35877
- if (!approve || !await approve(tool, args, signal)) {
35884
+ if (!approve) {
35885
+ notify("denied");
35886
+ throw new Error("The action was not approved on the connected machine.");
35887
+ }
35888
+ notify("awaiting_approval");
35889
+ if (!await approve(tool, args, signal)) {
35878
35890
  assertActive(signal);
35891
+ notify("denied");
35879
35892
  throw new Error("The action was not approved on the connected machine.");
35880
35893
  }
35881
35894
  assertActive(signal);
35895
+ notify("approved");
35882
35896
  }
35883
35897
  async function connectOnce(options, acknowledged) {
35884
35898
  const { config: config2, signal } = options;
@@ -35889,7 +35903,7 @@ async function connectOnce(options, acknowledged) {
35889
35903
  }
35890
35904
  const client = new Client({
35891
35905
  name: "terminal-commands-cli",
35892
- version: "0.2.0"
35906
+ version: "0.2.1"
35893
35907
  });
35894
35908
  let disposeSocket;
35895
35909
  try {
@@ -35911,6 +35925,7 @@ async function connectOnce(options, acknowledged) {
35911
35925
  });
35912
35926
  disposeSocket = () => socket.terminate();
35913
35927
  const pending = /* @__PURE__ */ new Map();
35928
+ let requestProgressEnabled = false;
35914
35929
  const forwarder = new ProcessEventForwarder(
35915
35930
  async (name, args) => client.callTool({ name, arguments: args }),
35916
35931
  (message) => {
@@ -35961,6 +35976,7 @@ async function connectOnce(options, acknowledged) {
35961
35976
  return;
35962
35977
  }
35963
35978
  if (message && typeof message === "object" && "type" in message && message.type === "ready") {
35979
+ requestProgressEnabled = message.requestProgressVersion === 1;
35964
35980
  void forwarder.recover().catch(
35965
35981
  (error62) => options.log?.(
35966
35982
  "Could not recover local process streams: " + (error62 instanceof Error ? error62.message : "unknown error")
@@ -35972,7 +35988,15 @@ async function connectOnce(options, acknowledged) {
35972
35988
  options.log?.("Ignoring a malformed gateway message.");
35973
35989
  return;
35974
35990
  }
35975
- void handleMessage(options, client, socket, raw, pending, forwarder);
35991
+ void handleMessage(
35992
+ options,
35993
+ client,
35994
+ socket,
35995
+ raw,
35996
+ pending,
35997
+ forwarder,
35998
+ requestProgressEnabled
35999
+ );
35976
36000
  });
35977
36001
  socket.on("close", () => {
35978
36002
  forwarder.close();
@@ -35987,7 +36011,7 @@ async function connectOnce(options, acknowledged) {
35987
36011
  await client.close().catch(() => void 0);
35988
36012
  }
35989
36013
  }
35990
- async function handleMessage(options, client, socket, raw, pending, forwarder) {
36014
+ async function handleMessage(options, client, socket, raw, pending, forwarder, requestProgressEnabled) {
35991
36015
  let requestId;
35992
36016
  let controller;
35993
36017
  let deadlineTimer;
@@ -36024,12 +36048,37 @@ async function handleMessage(options, client, socket, raw, pending, forwarder) {
36024
36048
  () => controller?.abort(),
36025
36049
  Math.max(0, deadlineAt - Date.now())
36026
36050
  );
36051
+ let progressSequence = 0;
36052
+ const progress = (phase) => {
36053
+ if (!requestProgressEnabled || parsed.data.tool !== "start_process" || socket.readyState !== wrapper_default.OPEN)
36054
+ return;
36055
+ if (socket.bufferedAmount > 512e3) {
36056
+ socket.close(1013, "Request progress backpressure");
36057
+ return;
36058
+ }
36059
+ try {
36060
+ socket.send(
36061
+ JSON.stringify({
36062
+ type: "request_progress",
36063
+ requestId,
36064
+ sequence: ++progressSequence,
36065
+ phase,
36066
+ ...phase === "approved" ? {
36067
+ approvalMode: options.config.MACHINE_TERMINAL_AUTO_APPROVE === "1" ? "automatic" : "manual"
36068
+ } : {}
36069
+ })
36070
+ );
36071
+ } catch {
36072
+ }
36073
+ };
36074
+ progress("received");
36027
36075
  await authorizeToolCall(
36028
36076
  parsed.data.tool,
36029
36077
  parsed.data.arguments,
36030
36078
  options.config.MACHINE_TERMINAL_AGENT_ALLOW_DESTRUCTIVE === "1",
36031
36079
  options.approve,
36032
- controller.signal
36080
+ controller.signal,
36081
+ progress
36033
36082
  );
36034
36083
  assertActive(controller.signal);
36035
36084
  const result = await client.callTool({
package/dist/index.js CHANGED
@@ -63373,7 +63373,7 @@ function createServer(options = {}) {
63373
63373
  }
63374
63374
  };
63375
63375
  const server = new McpServer(
63376
- { name: "terminal-commands", version: "0.2.0" },
63376
+ { name: "terminal-commands", version: "0.2.1" },
63377
63377
  {
63378
63378
  instructions: "This server controls the user's machine. Prefer dedicated file tools over commands. Every command and write can modify or expose local data and must receive user approval. Never request secrets or bypass configured roots and safety controls."
63379
63379
  }
@@ -63749,7 +63749,7 @@ app.get("/health", (request, response) => {
63749
63749
  response.status(available ? 200 : 503).json({
63750
63750
  status: available ? "ok" : "filesystem_unavailable",
63751
63751
  server: "terminal-commands",
63752
- version: "0.2.0",
63752
+ version: "0.2.1",
63753
63753
  ...proof ? { agentProof: proof } : {}
63754
63754
  });
63755
63755
  });
package/dist/stdio.js CHANGED
@@ -37280,7 +37280,7 @@ function createServer(options = {}) {
37280
37280
  }
37281
37281
  };
37282
37282
  const server2 = new McpServer(
37283
- { name: "terminal-commands", version: "0.2.0" },
37283
+ { name: "terminal-commands", version: "0.2.1" },
37284
37284
  {
37285
37285
  instructions: "This server controls the user's machine. Prefer dedicated file tools over commands. Every command and write can modify or expose local data and must receive user approval. Never request secrets or bypass configured roots and safety controls."
37286
37286
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "terminal-commands",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "A cross-platform, approval-gated terminal companion for ChatGPT, Claude, Codex, and any MCP-compatible AI client.",