@remcp/remcp 0.2.239 → 0.2.240
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 +1 -1
- package/src/cli/service-inventory.mjs +1 -1
- package/src/cli/service-linux.mjs +70 -0
- package/src/cli/service.mjs +2 -6
- package/src/cli.mjs +4 -0
package/package.json
CHANGED
|
@@ -29,7 +29,7 @@ export function persistentServiceState(config) {
|
|
|
29
29
|
const system = linuxSystemAgentOwned();
|
|
30
30
|
const installed = system || fs.existsSync(linuxServiceFile);
|
|
31
31
|
const active = installed && spawnSync('systemctl', [...(system ? [] : ['--user']), 'is-active', '--quiet', 'remcp-agent.service'], { stdio: 'ignore' }).status === 0;
|
|
32
|
-
return { expected, installed, active, manager:system ? 'systemd-system' : 'systemd-user', name:'remcp-agent.service' };
|
|
32
|
+
return { expected, installed, active, manager:installed ? (system ? 'systemd-system' : 'systemd-user') : 'none', name:'remcp-agent.service' };
|
|
33
33
|
}
|
|
34
34
|
if (platform === 'darwin') {
|
|
35
35
|
const installed = fs.existsSync(macServiceFile);
|
|
@@ -19,6 +19,76 @@ export function isManagedLinuxSystemUnit(text, launcher = linuxServiceLauncherFi
|
|
|
19
19
|
return text.split(/\r?\n/).some(line => expected.has(line.trim()));
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
// Discover BOTH supervisors before uninstalling either. A PID-1 migration may
|
|
23
|
+
// leave a disabled historical user unit behind; removing only the active scope
|
|
24
|
+
// makes status incorrectly report an installed service after uninstall.
|
|
25
|
+
export function discoverOwnedLinuxUnits({
|
|
26
|
+
systemFile = linuxSystemServiceFile,
|
|
27
|
+
userFile = linuxServiceFile,
|
|
28
|
+
launcher = linuxServiceLauncherFile,
|
|
29
|
+
includeSystem = process.getuid?.() === 0,
|
|
30
|
+
} = {}) {
|
|
31
|
+
const candidates = [
|
|
32
|
+
...(includeSystem ? [{ scope:'system', file:systemFile }] : []),
|
|
33
|
+
{ scope:'user', file:userFile },
|
|
34
|
+
];
|
|
35
|
+
const found = [];
|
|
36
|
+
for (const unit of candidates) {
|
|
37
|
+
let stat;
|
|
38
|
+
try { stat = fs.lstatSync(unit.file); }
|
|
39
|
+
catch (error) {
|
|
40
|
+
if (error?.code === 'ENOENT') continue;
|
|
41
|
+
throw error;
|
|
42
|
+
}
|
|
43
|
+
if (!stat.isFile() || stat.isSymbolicLink() ||
|
|
44
|
+
!isManagedLinuxSystemUnit(fs.readFileSync(unit.file, 'utf8'), launcher)) {
|
|
45
|
+
throw new Error('Refusing to uninstall an unrecognized ReMCP systemd unit: ' + unit.file);
|
|
46
|
+
}
|
|
47
|
+
found.push(unit);
|
|
48
|
+
}
|
|
49
|
+
return found;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Stop and remove all owned scopes, not just the newest one. Require the
|
|
53
|
+
// stop and daemon-reload to succeed; never claim success after a failed stop.
|
|
54
|
+
export function uninstallOwnedLinuxUnits({
|
|
55
|
+
systemFile = linuxSystemServiceFile,
|
|
56
|
+
userFile = linuxServiceFile,
|
|
57
|
+
launcher = linuxServiceLauncherFile,
|
|
58
|
+
includeSystem = process.getuid?.() === 0,
|
|
59
|
+
runner = spawnSync,
|
|
60
|
+
} = {}) {
|
|
61
|
+
const units = discoverOwnedLinuxUnits({ systemFile, userFile, launcher, includeSystem });
|
|
62
|
+
for (const { scope, file } of units) {
|
|
63
|
+
const option = scope === 'user' ? ['--user'] : [];
|
|
64
|
+
const stop = runner('systemctl', [...option, 'disable', '--now', 'remcp-agent.service'],
|
|
65
|
+
{ encoding:'utf8', timeout:20000 });
|
|
66
|
+
if (stop.status !== 0) {
|
|
67
|
+
throw new Error('Failed to stop ReMCP ' + scope +
|
|
68
|
+
' systemd service; refusing to report a successful uninstall');
|
|
69
|
+
}
|
|
70
|
+
const active = runner('systemctl', [...option, 'is-active', '--quiet', 'remcp-agent.service'],
|
|
71
|
+
{ stdio:'ignore', timeout:10000 });
|
|
72
|
+
if (active.status === 0) {
|
|
73
|
+
throw new Error('ReMCP ' + scope + ' systemd service remains active after stop');
|
|
74
|
+
}
|
|
75
|
+
// Another actor must not replace an owned unit with a symlink or foreign
|
|
76
|
+
// content between discovery and removal.
|
|
77
|
+
const stat = fs.lstatSync(file);
|
|
78
|
+
if (!stat.isFile() || stat.isSymbolicLink() ||
|
|
79
|
+
!isManagedLinuxSystemUnit(fs.readFileSync(file, 'utf8'), launcher)) {
|
|
80
|
+
throw new Error('ReMCP systemd unit changed during uninstall: ' + file);
|
|
81
|
+
}
|
|
82
|
+
fs.unlinkSync(file);
|
|
83
|
+
const reload = runner('systemctl', [...option, 'daemon-reload'],
|
|
84
|
+
{ encoding:'utf8', timeout:20000 });
|
|
85
|
+
if (reload.status !== 0) {
|
|
86
|
+
throw new Error('Failed to reload ' + scope + ' systemd after removing ReMCP service');
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return units.map(unit => unit.scope);
|
|
90
|
+
}
|
|
91
|
+
|
|
22
92
|
export function linuxSystemAgentOwned() {
|
|
23
93
|
if (process.platform !== 'linux' || process.getuid?.() !== 0) return false;
|
|
24
94
|
try {
|
package/src/cli/service.mjs
CHANGED
|
@@ -18,7 +18,7 @@ import { PACKAGE_NAME, VERSION } from '../version.mjs';
|
|
|
18
18
|
import { saveConfig } from './config.mjs';
|
|
19
19
|
import { configDir, home, linuxServiceFile, linuxServiceLauncherFile, macServiceFile, macServiceLabel, windowsServiceLauncherFile, windowsStartupScriptFile, windowsTaskName } from './env.mjs';
|
|
20
20
|
import { run } from './shell.mjs';
|
|
21
|
-
import { linuxActiveServiceFile, linuxServiceScope, linuxSystemAgentOwned, linuxSystemServiceFile, ensureLinuxLinger, ensureLinuxCliCommand } from './service-linux.mjs';
|
|
21
|
+
import { linuxActiveServiceFile, linuxServiceScope, linuxSystemAgentOwned, linuxSystemServiceFile, ensureLinuxLinger, ensureLinuxCliCommand, uninstallOwnedLinuxUnits } from './service-linux.mjs';
|
|
22
22
|
import { windowsServiceLauncherText, windowsTaskAbsenceCommand, windowsStartupScriptText, windowsStartupScriptInstalled } from './windows-supervisor.mjs';
|
|
23
23
|
import { ensureWindowsSupervisorKey, windowsSupervisorCommand } from './windows-user-supervisor.mjs';
|
|
24
24
|
|
|
@@ -386,11 +386,7 @@ export function restartPersistentServiceIfInstalled(config, { deferLinux = false
|
|
|
386
386
|
export function uninstallPersistentService() {
|
|
387
387
|
const platform = servicePlatform();
|
|
388
388
|
if (platform === 'linux') {
|
|
389
|
-
|
|
390
|
-
const option = scope === 'user' ? ['--user'] : [];
|
|
391
|
-
spawnSync('systemctl', [...option, 'disable', '--now', 'remcp-agent.service'], { stdio:'inherit' });
|
|
392
|
-
try { fs.unlinkSync(linuxActiveServiceFile()); } catch {}
|
|
393
|
-
spawnSync('systemctl', [...option, 'daemon-reload'], { stdio:'inherit' });
|
|
389
|
+
uninstallOwnedLinuxUnits();
|
|
394
390
|
} else if (platform === 'darwin') {
|
|
395
391
|
const domain = macLaunchDomain();
|
|
396
392
|
spawnSync('launchctl', ['bootout', domain, macServiceFile], { stdio: 'ignore' });
|
package/src/cli.mjs
CHANGED
|
@@ -360,6 +360,7 @@ export async function main(argv = process.argv.slice(2)) {
|
|
|
360
360
|
},
|
|
361
361
|
agent:{
|
|
362
362
|
mode:service.installed ? 'service' : 'manual',
|
|
363
|
+
installed:service.installed,
|
|
363
364
|
running:service.active,
|
|
364
365
|
manager:service.manager,
|
|
365
366
|
serviceCliVersion:serviceInstall.cliVersion,
|
|
@@ -419,6 +420,9 @@ export async function main(argv = process.argv.slice(2)) {
|
|
|
419
420
|
if (flags.purge) {
|
|
420
421
|
const specs = [PACKAGE_NAME, ...(cfg?.runtime?.packageName ? [cfg.runtime.packageName] : [])];
|
|
421
422
|
run(npm.command, [...npm.args, 'uninstall', '--global', ...specs, '--no-audit', '--no-fund', '--loglevel=error']);
|
|
423
|
+
console.log('ReMCP background service removed and global npm packages uninstalled. Device pairing was retained.');
|
|
424
|
+
} else {
|
|
425
|
+
console.log('ReMCP background service removed. The CLI, runtime packages and device pairing were retained. Use remcp uninstall --purge to also uninstall global npm packages.');
|
|
422
426
|
}
|
|
423
427
|
return;
|
|
424
428
|
}
|