@remcp/remcp 0.2.186 → 0.2.187

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/remcp",
3
- "version": "0.2.186",
3
+ "version": "0.2.187",
4
4
  "description": "ReMCP device client: pair a computer with ReMCP and run the outbound-only agent that hosts the local MCP runtime.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -3,7 +3,7 @@ import { persistentServiceExpected, persistentServiceState, releasePairPresentAt
3
3
  export { servicePlatform, globalPrefix, globalCliPath, npmGlobalInstall, npmGlobalUpdate, npmGlobalUpdateForNode };
4
4
  export { persistentServiceExpected, persistentServiceState, releasePairPresentAtCli, installationVersionsAtCliPath, serviceInstallationInfo, currentInstallationInfo, rememberCurrentInstallation, syncKnownInstallations };
5
5
  // Installing, repairing and removing the background agent: one supervisor per platform, plus the
6
- // write-access tweaks a fresh install needs. Nothing here is reachable from a model or an MCP tool.
6
+ // write-access tweaks a fresh install needs. Service maintenance follows local OS permissions.
7
7
  import fs from 'node:fs';
8
8
  import path from 'node:path';
9
9
  import process from 'node:process';
@@ -209,10 +209,22 @@ export function ensureServiceIfRecorded(config) {
209
209
  }
210
210
  }
211
211
 
212
- export function restartPersistentServiceIfInstalled(config) {
212
+ export function deferredLinuxAgentRestartArgs(pid) {
213
+ if (!Number.isSafeInteger(pid) || pid <= 0) throw new Error('Invalid process identifier');
214
+ return ['--user', '--on-active=3s', `--unit=remcp-agent-settings-${pid}`,
215
+ 'systemctl', '--user', 'restart', 'remcp-agent.service'];
216
+ }
217
+
218
+ export function restartPersistentServiceIfInstalled(config, { deferLinux = false } = {}) {
213
219
  if (!persistentServiceExpected(config)) return null;
214
220
  const platform = servicePlatform();
215
221
  if (platform === 'linux' && fs.existsSync(linuxServiceFile)) {
222
+ // Only owner-confirmed remote policy changes defer their restart. Ordinary
223
+ // installs and updates preserve their existing synchronous supervisor contract.
224
+ if (deferLinux) {
225
+ run('systemd-run', deferredLinuxAgentRestartArgs(process.pid));
226
+ return 'remcp-agent.service (restart scheduled)';
227
+ }
216
228
  run('systemctl', ['--user', 'daemon-reload']);
217
229
  run('systemctl', ['--user', 'restart', 'remcp-agent.service']);
218
230
  return 'remcp-agent.service';
package/src/cli.mjs CHANGED
@@ -34,7 +34,7 @@ function parse(argv) {
34
34
  }
35
35
 
36
36
  function printHelp() {
37
- console.log(`ReMCP ${VERSION}\n\nCommands:\n remcp start\n remcp status\n remcp doctor\n remcp update\n remcp install\n remcp uninstall\n remcp uninstall --purge\n remcp telemetry [status|on|off]\n remcp godmode [status|on|off]\n remcp --version\n\nPairing commands are generated in the ReMCP workspace.\n\nUsage metrics are opt-out (tool names, timings, outcomes only, sent to your own ReMCP\naccount through the paired agent). Disable them at any time with: remcp telemetry off\n\nUnrestricted mode (remcp godmode on) lifts the access roots and the command guardrails for this\ncomputer only. It is deliberately not reachable from a model or an MCP tool.`);
37
+ console.log(`ReMCP ${VERSION}\n\nCommands:\n remcp start\n remcp status\n remcp doctor\n remcp update\n remcp install\n remcp uninstall\n remcp uninstall --purge\n remcp telemetry [status|on|off]\n remcp godmode [status|on|off]\n remcp --version\n\nPairing commands are generated in the ReMCP workspace.\n\nUsage metrics are opt-out (tool names, timings, outcomes only, sent to your own ReMCP\naccount through the paired agent). Disable them at any time with: remcp telemetry off\n\nUnrestricted mode (remcp godmode on) lifts the access roots and the command guardrails for this\ncomputer only. The MCP configuration tool cannot enable it; protect remote terminal access.`);
38
38
  }
39
39
 
40
40
  export async function main(argv = process.argv.slice(2)) {
@@ -167,9 +167,10 @@ export async function main(argv = process.argv.slice(2)) {
167
167
  }
168
168
 
169
169
  // The switch that lifts every guardrail: no access roots, no command blocklist, no catastrophic
170
- // command protection. It lives here, on the machine, because a model that could turn it on would
171
- // turn any prompt injection into root. The runtime refuses to set it through MCP
172
- // (`set_config_value` lists what it accepts, and this is not on the list).
170
+ // command protection. The runtime refuses to set it through MCP's configuration
171
+ // tool; the device owner can deliberately change it through the CLI or the
172
+ // authenticated Workspace with explicit confirmation. Remote shell access
173
+ // remains powerful and must be protected by the account and OS permissions.
173
174
  if (command === 'godmode' || command === 'unrestricted') {
174
175
  const action = String(positional[0] || 'status').toLowerCase();
175
176
  if (action === 'status') {
@@ -187,7 +188,11 @@ export async function main(argv = process.argv.slice(2)) {
187
188
  if (!['on', 'off', 'enable', 'disable'].includes(action)) throw new Error('Usage: remcp godmode [status|on|off]');
188
189
  const enabled = action === 'on' || action === 'enable';
189
190
  writeJsonFile(runtimeConfigFile, { ...readJsonFile(runtimeConfigFile), unrestricted: enabled });
190
- const restarted = restartPersistentServiceIfInstalled(loadConfig(false));
191
+ // The authenticated Workspace supplies this explicit flag to allow the
192
+ // remote command to finish before its agent schedules a Linux restart.
193
+ // Local CLI and normal update operations retain synchronous semantics.
194
+ const restarted = restartPersistentServiceIfInstalled(loadConfig(false),
195
+ { deferLinux: flags['defer-restart'] === true });
191
196
  if (enabled) {
192
197
  console.error('Unrestricted mode is ON for this computer: every path and every command is allowed, including sudo. Anything the model is asked to do -- and anything a prompt injection asks it to do -- can now change this machine. Turn it off with `remcp godmode off` when you are done.');
193
198
  } else {