@remcp/runtime 0.2.28 → 0.2.30

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remcp/runtime",
3
- "version": "0.2.28",
3
+ "version": "0.2.30",
4
4
  "description": "First-party ReMCP local device runtime: file, search, terminal and process tools over MCP for computers paired with ReMCP.",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/src/config.mjs CHANGED
@@ -72,6 +72,19 @@ function dangerousMode(value, fallback = 'warn') {
72
72
  const allowedRoots = stringList(process.env.REMCP_RUNTIME_ALLOWED_ROOTS ?? file.allowedRoots)
73
73
  .map(root => path.resolve(expandHome(root)));
74
74
 
75
+ // "Everything is allowed" mode. It is deliberately *not* settable through MCP: a model that could
76
+ // widen its own reach would turn any prompt injection into root. The person at the computer turns it
77
+ // on (environment variable, runtime.json, or `remcp godmode on`), and the runtime then reports it in
78
+ // get_runtime_info so the model and the workspace can say so out loud.
79
+ //
80
+ // What it changes: no access-root confinement (allowedRoots becomes empty, which the path resolver
81
+ // already reads as "the whole filesystem"), the configured command blocklist is ignored, and the
82
+ // catastrophic-command guardrail is set to `allow`. What it does not change: the per-call size limits
83
+ // (maxWriteBytes, maxOutputBytes, line limits) — they bound one call, not what a person may do — and
84
+ // the fact that commands run as the user the agent runs as. To act as root, run the agent as root
85
+ // (`sudo remcp install --system`) or start it under sudo.
86
+ const unrestricted = booleanValue(process.env.REMCP_RUNTIME_UNRESTRICTED, booleanValue(file.unrestricted, false));
87
+
75
88
  // Telemetry is opt-out, matching the ReMCP client: it is on unless the user (or the
76
89
  // ReMCP agent that spawned this runtime) turns it off. It never sends file paths,
77
90
  // command strings, arguments, or tool output - only tool names, timings and outcomes.
@@ -85,9 +98,10 @@ const telemetryEnabled = telemetryDisabled
85
98
  const configuredOutputBytes = positiveNumber(process.env.REMCP_RUNTIME_MAX_OUTPUT_BYTES ?? file.maxOutputBytes, 2 * 1024 * 1024);
86
99
 
87
100
  export const runtimeConfig = Object.freeze({
88
- allowedRoots: Object.freeze(allowedRoots),
89
- blockedCommands: Object.freeze(stringList(process.env.REMCP_RUNTIME_BLOCKED_COMMANDS ?? file.blockedCommands)),
90
- dangerousCommands: dangerousMode(process.env.REMCP_RUNTIME_DANGEROUS_COMMANDS ?? file.dangerousCommands),
101
+ unrestricted,
102
+ allowedRoots: Object.freeze(unrestricted ? [] : allowedRoots),
103
+ blockedCommands: Object.freeze(unrestricted ? [] : stringList(process.env.REMCP_RUNTIME_BLOCKED_COMMANDS ?? file.blockedCommands)),
104
+ dangerousCommands: unrestricted ? 'allow' : dangerousMode(process.env.REMCP_RUNTIME_DANGEROUS_COMMANDS ?? file.dangerousCommands),
91
105
  maxOutputBytes: Math.min(configuredOutputBytes, HARD_OUTPUT_CEILING_BYTES),
92
106
  maxReadLines: positiveNumber(process.env.REMCP_RUNTIME_MAX_READ_LINES ?? file.maxReadLines, 4000),
93
107
  maxBufferedLines: positiveNumber(process.env.REMCP_RUNTIME_MAX_BUFFERED_LINES ?? file.maxBufferedLines, 100000),
package/src/policy.mjs CHANGED
@@ -66,6 +66,7 @@ function commandWord(segment) {
66
66
  }
67
67
 
68
68
  export function checkCommand(command) {
69
+ if (runtimeConfig.unrestricted) return { warned: false, mode: 'allow', unrestricted: true, findings: [] };
69
70
  const normalized = normalize(command);
70
71
  const parts = segments(normalized);
71
72
  const findings = [];
@@ -936,6 +936,13 @@ function screenshotAdvice(attempts, { platform = process.platform, env = process
936
936
  if (!env.DISPLAY && !wayland) {
937
937
  return `This computer has no graphical session (no DISPLAY and no Wayland display), so there is nothing to capture — servers and containers usually have none.`;
938
938
  }
939
+ // GNOME on Wayland is its own case: Mutter does not expose wlr-screencopy, so grim cannot capture
940
+ // it at all, and the shell's own D-Bus method answers `Screenshot is not allowed` to anything that
941
+ // is not the screenshot portal. The tool that does work is gnome-screenshot (it goes through the
942
+ // portal and asks the person once), so the message names that instead of sending people to grim.
943
+ if (wayland && /gnome/i.test(String(env.XDG_CURRENT_DESKTOP || ''))) {
944
+ return `Could not capture the screen on GNOME Wayland (${attempts.join('; ') || 'no capture command ran'}). Install the screenshot helper once — \`sudo apt install gnome-screenshot\` (or the equivalent for this distribution) — and approve the permission dialog it shows; GNOME blocks the shell's own screenshot API for background processes, and grim cannot read a GNOME session.`;
945
+ }
939
946
  if (wayland) {
940
947
  return `Could not capture the screen on Wayland (${attempts.join('; ') || 'no capture command ran'}). Install \`grim\` (Wayland's capture tool) — X11 tools such as scrot or ImageMagick import cannot read a Wayland session.`;
941
948
  }
@@ -14,6 +14,11 @@ export async function getRuntimeInfoTool() {
14
14
  version: VERSION,
15
15
  runtime: describeConfig(),
16
16
  policy: {
17
+ // Reported first because it changes how everything below should be read.
18
+ unrestricted: runtimeConfig.unrestricted,
19
+ ...(runtimeConfig.unrestricted
20
+ ? { unrestrictedNote: 'Unrestricted mode is on for this computer: any path and any command is allowed, and commands run as the user the agent runs as. Turn it off with `remcp godmode off` (or REMCP_RUNTIME_UNRESTRICTED=0) and restart the agent.' }
21
+ : {}),
17
22
  allowedRoots: [...runtimeConfig.allowedRoots],
18
23
  blockedCommands: [...runtimeConfig.blockedCommands],
19
24
  dangerousCommands: runtimeConfig.dangerousCommands,