@remcp/remcp 0.2.228 → 0.2.230
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.
|
|
3
|
+
"version": "0.2.230",
|
|
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",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"README.md"
|
|
19
19
|
],
|
|
20
20
|
"scripts": {
|
|
21
|
-
"check": "node --check bin/remcp.mjs && node --check src/agent-deploy-reconnect.mjs && node --check src/agent-network-probe-client.mjs && node --check src/agent-relay-connection.mjs && node --check src/agent-responder.mjs && node --check src/agent-runtime-capabilities.mjs && node --check src/agent-update-monitor.mjs && node --check src/agent-update.mjs && node --check src/agent-utilities.mjs && node --check src/agent.mjs && node --check src/cli.mjs && node --check src/cli/config.mjs && node --check src/cli/connect.mjs && node --check src/cli/doctor.mjs && node --check src/cli/env.mjs && node --check src/cli/installation-audit.mjs && node --check src/cli/mac-native-temperature.mjs && node --check src/cli/npm-global.mjs && node --check src/cli/pairing-qr.mjs && node --check src/cli/service-inventory.mjs && node --check src/cli/service-macos.mjs && node --check src/cli/service-paths.mjs && node --check src/cli/service.mjs && node --check src/cli/shell.mjs && node --check src/cli/supervised-agent-lifecycle.mjs && node --check src/cli/update.mjs && node --check src/cli/windows-owned-job-source.mjs && node --check src/cli/windows-owned-job.mjs && node --check src/cli/windows-supervisor.mjs && node --check src/cli/windows-update-lock.mjs && node --check src/cli/windows-user-supervisor.mjs && node --check src/fetch-update-manifest.mjs && node --check src/fs-access.mjs && node --check src/npm.mjs && node --check src/runtime.mjs && node --check src/version.mjs",
|
|
21
|
+
"check": "node --check bin/remcp.mjs && node --check src/agent-deploy-reconnect.mjs && node --check src/agent-network-probe-client.mjs && node --check src/agent-relay-connection.mjs && node --check src/agent-responder.mjs && node --check src/agent-runtime-capabilities.mjs && node --check src/agent-update-monitor.mjs && node --check src/agent-update.mjs && node --check src/agent-utilities.mjs && node --check src/agent.mjs && node --check src/cli.mjs && node --check src/cli/config.mjs && node --check src/cli/connect.mjs && node --check src/cli/doctor.mjs && node --check src/cli/env.mjs && node --check src/cli/installation-audit.mjs && node --check src/cli/mac-native-temperature.mjs && node --check src/cli/npm-global.mjs && node --check src/cli/pairing-qr.mjs && node --check src/cli/service-inventory.mjs && node --check src/cli/service-macos.mjs && node --check src/cli/service-paths.mjs && node --check src/cli/service.mjs && node --check src/cli/shell.mjs && node --check src/cli/supervised-agent-lifecycle.mjs && node --check src/cli/update.mjs && node --check src/cli/windows-cli-shim.mjs && node --check src/cli/windows-owned-job-source.mjs && node --check src/cli/windows-owned-job.mjs && node --check src/cli/windows-supervisor.mjs && node --check src/cli/windows-update-lock.mjs && node --check src/cli/windows-user-supervisor.mjs && node --check src/fetch-update-manifest.mjs && node --check src/fs-access.mjs && node --check src/npm.mjs && node --check src/runtime.mjs && node --check src/version.mjs",
|
|
22
22
|
"test": "node --test test/*.test.mjs"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
@@ -43,7 +43,9 @@ export function createAgentRelayConnection({
|
|
|
43
43
|
reconnectTimer = null;
|
|
44
44
|
connect();
|
|
45
45
|
}, safeDelay);
|
|
46
|
-
|
|
46
|
+
// A failed handshake may leave no other referenced handles. Keep the reconnect
|
|
47
|
+
// timer referenced, or Node exits 0 and a supervisor can restart it forever.
|
|
48
|
+
// clearReconnect() releases the timer on intentional shutdown.
|
|
47
49
|
}
|
|
48
50
|
|
|
49
51
|
function scheduleBackoffReconnect() {
|
package/src/cli/npm-global.mjs
CHANGED
|
@@ -7,6 +7,7 @@ import { home, npm } from './env.mjs';
|
|
|
7
7
|
import { buildVettedMacTemperatureAddon } from './mac-native-temperature.mjs';
|
|
8
8
|
import { output, run } from './shell.mjs';
|
|
9
9
|
import { withWindowsUpdateLock } from './windows-update-lock.mjs';
|
|
10
|
+
import { assertWindowsNpmPowerShellShimOwned, preferWindowsCmdShim } from './windows-cli-shim.mjs';
|
|
10
11
|
|
|
11
12
|
export function servicePlatform() {
|
|
12
13
|
return process.env.NODE_ENV === 'test' && process.env.REMCP_TEST_PLATFORM ? process.env.REMCP_TEST_PLATFORM : process.platform;
|
|
@@ -55,7 +56,14 @@ function npmGlobalInstallArgs(specs, { preferOnline = false } = {}) {
|
|
|
55
56
|
|
|
56
57
|
export function npmGlobalInstall(...specs) {
|
|
57
58
|
const prefix = assertSafeReMcpNpmPrefix(globalPrefix()); // Reject an unsafe prefix before npm writes anything.
|
|
58
|
-
const install = () =>
|
|
59
|
+
const install = () => {
|
|
60
|
+
const updatingClient = servicePlatform() === 'win32' && isManagedWindowsRuntimePrefix(prefix)
|
|
61
|
+
&& specs.some(spec => /^@remcp\/remcp@/.test(spec));
|
|
62
|
+
// A custom remcp.ps1 must be refused BEFORE npm overwrites its contents.
|
|
63
|
+
if (updatingClient) assertWindowsNpmPowerShellShimOwned(prefix);
|
|
64
|
+
run(npm.command, [...npm.args, ...npmGlobalInstallArgs(specs)]);
|
|
65
|
+
if (updatingClient) preferWindowsCmdShim(prefix);
|
|
66
|
+
};
|
|
59
67
|
if (servicePlatform() === 'win32') withWindowsUpdateLock(prefix, install);
|
|
60
68
|
else install();
|
|
61
69
|
if (servicePlatform() === 'darwin' && specs.some(spec => /^@remcp\/runtime@[0-9]/.test(spec))) {
|
|
@@ -184,6 +192,9 @@ function transactionalWindowsGlobalInstall({ resolved, prefix, packageNames, spe
|
|
|
184
192
|
return;
|
|
185
193
|
}
|
|
186
194
|
|
|
195
|
+
// The transaction deletes its previous shim backup after success. Reject a
|
|
196
|
+
// user-created remcp.ps1 before touching npm or moving any existing files.
|
|
197
|
+
if (packageNames.includes(PACKAGE_NAME)) assertWindowsNpmPowerShellShimOwned(prefix);
|
|
187
198
|
const backupRoot = path.join(prefix, `.remcp-update-backup-${process.pid}-${Date.now()}`);
|
|
188
199
|
const moved = [];
|
|
189
200
|
const moveAside = (source, label) => {
|
|
@@ -221,6 +232,7 @@ function transactionalWindowsGlobalInstall({ resolved, prefix, packageNames, spe
|
|
|
221
232
|
for (const shim of ['remcp', 'remcp.cmd', 'remcp.ps1']) moveAside(path.join(prefix, shim), `bin-${shim}`);
|
|
222
233
|
}
|
|
223
234
|
run(resolved.command, [...resolved.args, ...npmGlobalInstallArgs(specs, { preferOnline })]);
|
|
235
|
+
if (uniqueNames.includes(PACKAGE_NAME)) preferWindowsCmdShim(prefix);
|
|
224
236
|
} catch (error) {
|
|
225
237
|
restore(error);
|
|
226
238
|
throw error;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// ReMCP's private Windows npm prefix is called from both cmd.exe and PowerShell.
|
|
2
|
+
// npm generates both remcp.cmd and remcp.ps1, but PowerShell prefers the .ps1
|
|
3
|
+
// even when ExecutionPolicy=Restricted. That makes a successful installation
|
|
4
|
+
// appear broken. Keep the batch shim, and remove only the recognizable npm shim.
|
|
5
|
+
import fs from 'node:fs';
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
|
|
8
|
+
// Exact npm cmd-shim template; partial markers cannot establish ownership.
|
|
9
|
+
export const WINDOWS_NPM_POWERSHELL_SHIM = String.raw`#!/usr/bin/env pwsh
|
|
10
|
+
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
|
|
11
|
+
|
|
12
|
+
$exe=""
|
|
13
|
+
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
|
|
14
|
+
# Fix case when both the Windows and Linux builds of Node
|
|
15
|
+
# are installed in the same directory
|
|
16
|
+
$exe=".exe"
|
|
17
|
+
}
|
|
18
|
+
$ret=0
|
|
19
|
+
if (Test-Path "$basedir/node$exe") {
|
|
20
|
+
# Support pipeline input
|
|
21
|
+
if ($MyInvocation.ExpectingInput) {
|
|
22
|
+
$input | & "$basedir/node$exe" "$basedir/node_modules/@remcp/remcp/bin/remcp.mjs" $args
|
|
23
|
+
} else {
|
|
24
|
+
& "$basedir/node$exe" "$basedir/node_modules/@remcp/remcp/bin/remcp.mjs" $args
|
|
25
|
+
}
|
|
26
|
+
$ret=$LASTEXITCODE
|
|
27
|
+
} else {
|
|
28
|
+
# Support pipeline input
|
|
29
|
+
if ($MyInvocation.ExpectingInput) {
|
|
30
|
+
$input | & "node$exe" "$basedir/node_modules/@remcp/remcp/bin/remcp.mjs" $args
|
|
31
|
+
} else {
|
|
32
|
+
& "node$exe" "$basedir/node_modules/@remcp/remcp/bin/remcp.mjs" $args
|
|
33
|
+
}
|
|
34
|
+
$ret=$LASTEXITCODE
|
|
35
|
+
}
|
|
36
|
+
exit $ret
|
|
37
|
+
`;
|
|
38
|
+
|
|
39
|
+
function normalizedShim(text) {
|
|
40
|
+
return text.replace(/^\uFEFF/, '').replace(/\r\n/g, '\n').replace(/\n+$/, '');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function assertWindowsNpmPowerShellShimOwned(prefix) {
|
|
44
|
+
const powershell = path.join(prefix, 'remcp.ps1');
|
|
45
|
+
let metadata;
|
|
46
|
+
try { metadata = fs.lstatSync(powershell); }
|
|
47
|
+
catch (error) { if (error?.code === 'ENOENT') return false; throw error; }
|
|
48
|
+
if (!metadata.isFile() || metadata.isSymbolicLink()) {
|
|
49
|
+
throw new Error('Refusing to replace an unknown ReMCP PowerShell launcher');
|
|
50
|
+
}
|
|
51
|
+
const contents = fs.readFileSync(powershell, 'utf8');
|
|
52
|
+
if (contents.length > 16000 || normalizedShim(contents) !== normalizedShim(WINDOWS_NPM_POWERSHELL_SHIM)) {
|
|
53
|
+
throw new Error('Refusing to remove a non-npm ReMCP PowerShell launcher');
|
|
54
|
+
}
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function preferWindowsCmdShim(prefix) {
|
|
59
|
+
if (!assertWindowsNpmPowerShellShimOwned(prefix)) return false;
|
|
60
|
+
const batch = path.join(prefix, 'remcp.cmd');
|
|
61
|
+
const powershell = path.join(prefix, 'remcp.ps1');
|
|
62
|
+
let batchStat;
|
|
63
|
+
try { batchStat = fs.lstatSync(batch); }
|
|
64
|
+
catch (error) {
|
|
65
|
+
if (error?.code !== 'ENOENT') throw error;
|
|
66
|
+
throw new Error('Cannot remove the PowerShell launcher without a ReMCP .cmd launcher');
|
|
67
|
+
}
|
|
68
|
+
if (!batchStat.isFile() || batchStat.isSymbolicLink()) {
|
|
69
|
+
throw new Error('Cannot remove the PowerShell launcher without a trusted ReMCP .cmd launcher');
|
|
70
|
+
}
|
|
71
|
+
fs.unlinkSync(powershell);
|
|
72
|
+
return true;
|
|
73
|
+
}
|