@remcp/remcp 0.2.209 → 0.2.211
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 +1 -1
- package/package.json +2 -2
- package/src/cli/installation-audit.mjs +79 -0
- package/src/cli.mjs +12 -10
package/README.md
CHANGED
|
@@ -90,7 +90,7 @@ permission, and `remcp doctor` reports the state of each one.
|
|
|
90
90
|
|
|
91
91
|
## Updates
|
|
92
92
|
|
|
93
|
-
The agent asks the server which versions it should run on every successful connection and every six hours, installs the exact trusted client/runtime release pair in the background, and restarts the managed service so it takes effect. The updater resolves itself and the sibling runtime from the package that is actually running instead of depending on an interactive shell PATH. When
|
|
93
|
+
The agent asks the server which versions it should run on every successful connection and every six hours, installs the exact trusted client/runtime release pair in the background, and restarts the managed service so it takes effect. The updater resolves itself and the sibling runtime from the package that is actually running instead of depending on an interactive shell PATH. When a computer has several Node.js environments (for example NVM, FNM or a system installation), ReMCP updates only the canonical managed service packages. It does not upgrade Node.js, rewrite unrelated npm packages, or silently remove old ReMCP copies. `remcp status` counts package roots verified from the current CLI/service and bounded installation history; aliases and vanished paths are not extra installations. `remcp doctor` adds the exact read-only package roots, corresponding client/runtime versions, aliases and historical/cache classifications. These are **physical package copies, not a count of running agents**. Old copies are never automatically removed; verifying process, startup and script dependencies is required before an explicit owner-approved cleanup. A failed install is retried no more often than every thirty minutes and update-check failures are logged, so a broken release cannot become a silent install loop. `remcp update` does the same immediately; `remcp auto-update off` disables automatic checks.
|
|
94
94
|
|
|
95
95
|
## Computer-use routing
|
|
96
96
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remcp/remcp",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.211",
|
|
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/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/update.mjs && node --check src/cli/windows-supervisor.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/update.mjs && node --check src/cli/windows-supervisor.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": {
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
|
|
4
|
+
const CLIENT_PACKAGE = '@remcp/remcp';
|
|
5
|
+
const MAX_HISTORY = 32;
|
|
6
|
+
|
|
7
|
+
// Inventory only paths previously recorded by this owner and the two current CLI
|
|
8
|
+
// entrypoints. Never crawl npm/node directories or infer running processes.
|
|
9
|
+
function installedPackageAt(cliPath) {
|
|
10
|
+
if (typeof cliPath !== 'string' || !cliPath.trim() || !fs.existsSync(cliPath)) return null;
|
|
11
|
+
let resolved;
|
|
12
|
+
try { resolved = fs.realpathSync(cliPath); } catch { return null; }
|
|
13
|
+
const normalized = resolved.replaceAll('\\', '/');
|
|
14
|
+
const marker = '/node_modules/@remcp/remcp/';
|
|
15
|
+
const markerAt = normalized.lastIndexOf(marker);
|
|
16
|
+
let root = markerAt < 0 ? null : resolved.slice(0, markerAt + marker.length - 1);
|
|
17
|
+
// npm on Windows uses a .cmd shim in the global prefix instead of a link.
|
|
18
|
+
if (!root && path.basename(resolved).toLowerCase() === 'remcp.cmd') {
|
|
19
|
+
root = path.join(path.dirname(resolved), 'node_modules', '@remcp', 'remcp');
|
|
20
|
+
}
|
|
21
|
+
if (!root) return null;
|
|
22
|
+
try {
|
|
23
|
+
const manifest = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8'));
|
|
24
|
+
if (manifest.name !== CLIENT_PACKAGE || typeof manifest.version !== 'string') return null;
|
|
25
|
+
let runtimeVersion = null;
|
|
26
|
+
try {
|
|
27
|
+
const runtime = JSON.parse(fs.readFileSync(path.join(root, '..', 'runtime', 'package.json'), 'utf8'));
|
|
28
|
+
if (runtime.name === '@remcp/runtime' && typeof runtime.version === 'string') runtimeVersion = runtime.version;
|
|
29
|
+
} catch {}
|
|
30
|
+
return { root:fs.realpathSync(root), resolved, version:manifest.version, runtimeVersion };
|
|
31
|
+
} catch { return null; }
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function auditKnownInstallations(config, { currentCliPath, serviceCliPath } = {}) {
|
|
35
|
+
const history = Array.isArray(config?.installations) ? config.installations.slice(-MAX_HISTORY) : [];
|
|
36
|
+
const candidates = [
|
|
37
|
+
{ path:currentCliPath, source:'invoked_cli' },
|
|
38
|
+
{ path:serviceCliPath, source:'managed_service' },
|
|
39
|
+
...history.map(item => ({ path:item?.cliPath, source:'saved_history' })),
|
|
40
|
+
];
|
|
41
|
+
const packages = new Map();
|
|
42
|
+
const aliases = [];
|
|
43
|
+
let ignoredUnverified = 0;
|
|
44
|
+
for (const candidate of candidates) {
|
|
45
|
+
if (typeof candidate.path !== 'string' || !candidate.path.trim() || !fs.existsSync(candidate.path)) continue;
|
|
46
|
+
const installed = installedPackageAt(candidate.path);
|
|
47
|
+
if (!installed) { ignoredUnverified++; continue; }
|
|
48
|
+
let copy = packages.get(installed.root);
|
|
49
|
+
if (!copy) {
|
|
50
|
+
copy = { packageRoot:installed.root, version:installed.version, runtimeVersion:installed.runtimeVersion, sources:new Set(), cliPaths:new Set() };
|
|
51
|
+
packages.set(installed.root, copy);
|
|
52
|
+
}
|
|
53
|
+
copy.sources.add(candidate.source);
|
|
54
|
+
copy.cliPaths.add(candidate.path);
|
|
55
|
+
if (candidate.path !== installed.resolved && !aliases.some(a => a.path === candidate.path)) {
|
|
56
|
+
aliases.push({ path:candidate.path, resolvesTo:installed.resolved });
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const copies = [...packages.values()].map(item => ({
|
|
60
|
+
packageRoot:item.packageRoot,
|
|
61
|
+
version:item.version,
|
|
62
|
+
runtimeVersion:item.runtimeVersion,
|
|
63
|
+
sources:[...item.sources],
|
|
64
|
+
kind:item.packageRoot.replaceAll('\\', '/').includes('/_npx/') ? 'npx_cache' : 'npm_package',
|
|
65
|
+
isInvoked:item.sources.has('invoked_cli'),
|
|
66
|
+
isManagedService:item.sources.has('managed_service'),
|
|
67
|
+
cliPaths:[...item.cliPaths],
|
|
68
|
+
}));
|
|
69
|
+
return {
|
|
70
|
+
scope:'recorded_paths_only',
|
|
71
|
+
processConcurrency:'not_measured',
|
|
72
|
+
packageCopyCount:copies.length,
|
|
73
|
+
otherCopyCount:copies.filter(item => !item.isInvoked && !item.isManagedService).length,
|
|
74
|
+
ignoredUnverifiedPathCount:ignoredUnverified,
|
|
75
|
+
aliases,
|
|
76
|
+
copies,
|
|
77
|
+
removal:'disabled; explicit owner review and process/dependency audit required',
|
|
78
|
+
};
|
|
79
|
+
}
|
package/src/cli.mjs
CHANGED
|
@@ -13,6 +13,7 @@ import { assertRuntimeTrust, assertSecureServerUrl, pairWithDeviceCode } from '.
|
|
|
13
13
|
import { diagnoseLocalRuntime, installedVersion, runtimeAllowedRoots } from './cli/doctor.mjs';
|
|
14
14
|
import { configFile, npm, officialOrigin, runtimeConfigFile } from './cli/env.mjs';
|
|
15
15
|
import { currentInstallationInfo, ensureMacCliCommand, installPersistentAgent, persistentServiceState, servicePlatform, rememberCurrentInstallation, restartPersistentServiceIfInstalled, serviceInstallationInfo, uninstallPersistentService } from './cli/service.mjs';
|
|
16
|
+
import { auditKnownInstallations } from './cli/installation-audit.mjs';
|
|
16
17
|
import { scheduleMacTemperatureRepair } from './cli/mac-native-temperature.mjs';
|
|
17
18
|
import { repairMacTemperatureAfterStart } from './cli/npm-global.mjs';
|
|
18
19
|
import { run } from './cli/shell.mjs';
|
|
@@ -305,16 +306,13 @@ export async function main(argv = process.argv.slice(2)) {
|
|
|
305
306
|
const targetClient = String(advertised?.cliVersion || '').trim() || null;
|
|
306
307
|
const targetRuntime = String(advertised?.runtime || '').trim() || null;
|
|
307
308
|
const configuredRuntime = String(cfg.runtime.packageSpec || '');
|
|
308
|
-
//
|
|
309
|
-
//
|
|
310
|
-
const
|
|
311
|
-
currentInstall.cliPath,
|
|
312
|
-
serviceInstall.cliPath,
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
try { return fs.realpathSync(file); } catch { return file; }
|
|
316
|
-
}));
|
|
317
|
-
const multipleInstallations = installationPaths.size > 1;
|
|
309
|
+
// Count verified physical ReMCP package roots, not merely surviving paths or
|
|
310
|
+
// shell aliases. This is NOT a concurrent-agent/process count.
|
|
311
|
+
const installationAudit = auditKnownInstallations(cfg, {
|
|
312
|
+
currentCliPath:currentInstall.cliPath,
|
|
313
|
+
serviceCliPath:service.installed ? serviceInstall.cliPath : null,
|
|
314
|
+
});
|
|
315
|
+
const multipleInstallations = installationAudit.packageCopyCount > 1;
|
|
318
316
|
const knownCliVersions = [VERSION, serviceInstall.cliVersion].filter(Boolean);
|
|
319
317
|
const knownRuntimeVersions = [installedRuntime, serviceInstall.runtimeVersion].filter(Boolean);
|
|
320
318
|
const versionConsistent = cfg.runtime.packageName === '@remcp/runtime'
|
|
@@ -368,6 +366,9 @@ export async function main(argv = process.argv.slice(2)) {
|
|
|
368
366
|
targetClient,
|
|
369
367
|
targetRuntime,
|
|
370
368
|
multipleInstallations,
|
|
369
|
+
knownPackageCopies:installationAudit.packageCopyCount,
|
|
370
|
+
additionalKnownPackageCopies:installationAudit.otherCopyCount,
|
|
371
|
+
installationCountScope:'verified_physical_packages_not_running_agents',
|
|
371
372
|
versionConsistent,
|
|
372
373
|
state:updateState,
|
|
373
374
|
upToDate,
|
|
@@ -382,6 +383,7 @@ export async function main(argv = process.argv.slice(2)) {
|
|
|
382
383
|
serviceInstalled:service.installed,
|
|
383
384
|
runtimeEntry:cfg.runtime.entry,
|
|
384
385
|
npmManaged:true,
|
|
386
|
+
installations:installationAudit,
|
|
385
387
|
};
|
|
386
388
|
}
|
|
387
389
|
console.log(JSON.stringify(report, null, 2));
|