infinicode 2.8.22 → 2.8.23
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/dist/robopark/stop-all.d.ts +6 -0
- package/dist/robopark/stop-all.js +121 -0
- package/dist/robopark-cli.js +25 -0
- package/package.json +1 -1
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RoboPark / infinicode — stop everything on this machine, including whatever
|
|
3
|
+
* would respawn it.
|
|
4
|
+
*
|
|
5
|
+
* `--supervised` nodes (systemd/Task Scheduler/launchd, `Restart=always`) come
|
|
6
|
+
* back on their own after a plain kill — that's the class of bug that leaves a
|
|
7
|
+
* stale hub process answering on a port after someone thought they killed it.
|
|
8
|
+
* This kills every matching PID directly (never a blanket `killall node`) AND
|
|
9
|
+
* disables/removes the supervisor unit so it does not restart.
|
|
10
|
+
*/
|
|
11
|
+
import { spawnSync } from 'node:child_process';
|
|
12
|
+
// Long-running daemons only — never a short-lived CLI invocation like
|
|
13
|
+
// `robopark setup` or `robopark stop` itself, which would otherwise match
|
|
14
|
+
// its own (or an ancestor shell's) command line and self-terminate mid-run.
|
|
15
|
+
const PATTERNS = [
|
|
16
|
+
'infinicode serve',
|
|
17
|
+
'infinicode.js serve',
|
|
18
|
+
'cli.js serve', // source/dev invocation: `node dist/cli.js serve ...`
|
|
19
|
+
'robopark serve',
|
|
20
|
+
'robopark-cli.js serve',
|
|
21
|
+
'preview_agent.py',
|
|
22
|
+
'app_pi_clean.py',
|
|
23
|
+
];
|
|
24
|
+
export async function stopAll() {
|
|
25
|
+
const platform = process.platform;
|
|
26
|
+
if (platform === 'win32')
|
|
27
|
+
return stopAllWindows();
|
|
28
|
+
return stopAllUnix();
|
|
29
|
+
}
|
|
30
|
+
function stopAllWindows() {
|
|
31
|
+
const killedPids = [];
|
|
32
|
+
const removedUnits = [];
|
|
33
|
+
const errors = [];
|
|
34
|
+
// Find every process whose command line matches, by PID — not by image
|
|
35
|
+
// name, so we never touch an unrelated node.exe (e.g. an MCP server).
|
|
36
|
+
const ps = spawnSync('powershell.exe', [
|
|
37
|
+
'-NoProfile', '-NonInteractive', '-Command',
|
|
38
|
+
`Get-CimInstance Win32_Process | Where-Object { $_.CommandLine -and ($_.CommandLine -match '${PATTERNS.join('|').replace(/'/g, "''")}') } | Select-Object -ExpandProperty ProcessId`,
|
|
39
|
+
], { encoding: 'utf8' });
|
|
40
|
+
const pids = (ps.stdout ?? '').split(/\r?\n/).map(s => s.trim()).filter(Boolean).map(Number).filter(Number.isFinite);
|
|
41
|
+
const self = process.pid;
|
|
42
|
+
for (const pid of pids) {
|
|
43
|
+
if (pid === self)
|
|
44
|
+
continue; // never kill the process running this command
|
|
45
|
+
const kill = spawnSync('taskkill', ['/PID', String(pid), '/F', '/T'], { encoding: 'utf8' });
|
|
46
|
+
if (kill.status === 0)
|
|
47
|
+
killedPids.push(pid);
|
|
48
|
+
else
|
|
49
|
+
errors.push(`taskkill ${pid}: ${(kill.stderr || kill.stdout || '').trim()}`);
|
|
50
|
+
}
|
|
51
|
+
// Remove any Scheduled Tasks registered by `robopark setup --auto-start`
|
|
52
|
+
// (auto-start.ts names them "RoboPark-<role>-<name>") so they don't relaunch
|
|
53
|
+
// on next login/boot.
|
|
54
|
+
const query = spawnSync('schtasks', ['/Query', '/FO', 'CSV', '/NH'], { encoding: 'utf8' });
|
|
55
|
+
const taskNames = (query.stdout ?? '')
|
|
56
|
+
.split(/\r?\n/)
|
|
57
|
+
.map(line => line.split(',')[0]?.replace(/^"|"$/g, ''))
|
|
58
|
+
.filter((n) => !!n && n.startsWith('\\RoboPark-'));
|
|
59
|
+
for (const name of taskNames) {
|
|
60
|
+
const del = spawnSync('schtasks', ['/Delete', '/TN', name, '/F'], { encoding: 'utf8' });
|
|
61
|
+
if (del.status === 0)
|
|
62
|
+
removedUnits.push(name);
|
|
63
|
+
else
|
|
64
|
+
errors.push(`schtasks /Delete ${name}: ${(del.stderr || del.stdout || '').trim()}`);
|
|
65
|
+
}
|
|
66
|
+
return { killedPids, removedUnits, errors };
|
|
67
|
+
}
|
|
68
|
+
function stopAllUnix() {
|
|
69
|
+
const killedPids = [];
|
|
70
|
+
const removedUnits = [];
|
|
71
|
+
const errors = [];
|
|
72
|
+
const self = process.pid;
|
|
73
|
+
const ps = spawnSync('ps', ['ax', '-o', 'pid=,command='], { encoding: 'utf8' });
|
|
74
|
+
const lines = (ps.stdout ?? '').split('\n');
|
|
75
|
+
const re = new RegExp(PATTERNS.map(p => p.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('|'));
|
|
76
|
+
for (const line of lines) {
|
|
77
|
+
const m = line.match(/^\s*(\d+)\s+(.*)$/);
|
|
78
|
+
if (!m)
|
|
79
|
+
continue;
|
|
80
|
+
const pid = Number(m[1]);
|
|
81
|
+
const cmd = m[2];
|
|
82
|
+
if (pid === self || !re.test(cmd))
|
|
83
|
+
continue;
|
|
84
|
+
const kill = spawnSync('kill', ['-9', String(pid)], { encoding: 'utf8' });
|
|
85
|
+
if (kill.status === 0)
|
|
86
|
+
killedPids.push(pid);
|
|
87
|
+
else
|
|
88
|
+
errors.push(`kill -9 ${pid}: ${(kill.stderr || '').trim()}`);
|
|
89
|
+
}
|
|
90
|
+
// Also free the well-known RoboPark ports directly — belt and suspenders
|
|
91
|
+
// against a supervised process whose command line didn't match a pattern.
|
|
92
|
+
for (const port of [47913, 47921, 47922, 8080, 5000, 5057]) {
|
|
93
|
+
const lsof = spawnSync('lsof', ['-t', `-i:${port}`], { encoding: 'utf8' });
|
|
94
|
+
const pids = (lsof.stdout ?? '').split('\n').map(s => s.trim()).filter(Boolean).map(Number);
|
|
95
|
+
for (const pid of pids) {
|
|
96
|
+
if (pid === self || killedPids.includes(pid))
|
|
97
|
+
continue;
|
|
98
|
+
const kill = spawnSync('kill', ['-9', String(pid)], { encoding: 'utf8' });
|
|
99
|
+
if (kill.status === 0)
|
|
100
|
+
killedPids.push(pid);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (process.platform === 'linux') {
|
|
104
|
+
const list = spawnSync('systemctl', ['list-units', '--all', '--plain', '--no-legend', 'robopark-*'], { encoding: 'utf8' });
|
|
105
|
+
const units = (list.stdout ?? '')
|
|
106
|
+
.split('\n')
|
|
107
|
+
.map(l => l.trim().split(/\s+/)[0])
|
|
108
|
+
.filter((u) => !!u && u.endsWith('.service'));
|
|
109
|
+
for (const unit of units) {
|
|
110
|
+
spawnSync('systemctl', ['stop', unit], { encoding: 'utf8' });
|
|
111
|
+
const disable = spawnSync('systemctl', ['disable', unit], { encoding: 'utf8' });
|
|
112
|
+
if (disable.status === 0)
|
|
113
|
+
removedUnits.push(unit);
|
|
114
|
+
else
|
|
115
|
+
errors.push(`systemctl disable ${unit}: ${(disable.stderr || '').trim()}`);
|
|
116
|
+
}
|
|
117
|
+
if (units.length)
|
|
118
|
+
spawnSync('systemctl', ['daemon-reload'], { encoding: 'utf8' });
|
|
119
|
+
}
|
|
120
|
+
return { killedPids, removedUnits, errors };
|
|
121
|
+
}
|
package/dist/robopark-cli.js
CHANGED
|
@@ -15,6 +15,7 @@ import { attachRoboparkSubcommands as attachLegacy } from './commands/robopark.j
|
|
|
15
15
|
import { roboparkScan } from './robopark/scan.js';
|
|
16
16
|
import { roboparkServe } from './robopark/serve.js';
|
|
17
17
|
import { roboparkSetup } from './robopark/setup.js';
|
|
18
|
+
import { stopAll } from './robopark/stop-all.js';
|
|
18
19
|
// Read the real version from package.json so `--version` never drifts from
|
|
19
20
|
// what is actually installed (this was a hardcoded constant that went stale
|
|
20
21
|
// across several releases — see the identical fix + comment in cli.ts).
|
|
@@ -135,6 +136,30 @@ program
|
|
|
135
136
|
const { roboparkVisionAgent } = await import('./robopark/vision-agent-launcher.js');
|
|
136
137
|
await roboparkVisionAgent(opts);
|
|
137
138
|
});
|
|
139
|
+
program
|
|
140
|
+
.command('stop')
|
|
141
|
+
.description('Stop every infinicode/robopark process on this device AND remove any supervisor (systemd/Task Scheduler/launchd) that would respawn it')
|
|
142
|
+
.action(async () => {
|
|
143
|
+
console.log(chalk.bold('\n robopark stop\n ' + '─'.repeat(48)));
|
|
144
|
+
try {
|
|
145
|
+
const result = await stopAll();
|
|
146
|
+
if (result.killedPids.length)
|
|
147
|
+
console.log(chalk.green(` ✓ killed ${result.killedPids.length} process(es): ${result.killedPids.join(', ')}`));
|
|
148
|
+
else
|
|
149
|
+
console.log(chalk.dim(' no matching processes were running'));
|
|
150
|
+
if (result.removedUnits.length)
|
|
151
|
+
console.log(chalk.green(` ✓ removed ${result.removedUnits.length} supervisor unit(s): ${result.removedUnits.join(', ')}`));
|
|
152
|
+
else
|
|
153
|
+
console.log(chalk.dim(' no supervisor units registered'));
|
|
154
|
+
for (const err of result.errors)
|
|
155
|
+
console.log(chalk.yellow(` ! ${err}`));
|
|
156
|
+
console.log('');
|
|
157
|
+
}
|
|
158
|
+
catch (e) {
|
|
159
|
+
console.error('stop failed:', e instanceof Error ? (e.stack ?? e.message) : e);
|
|
160
|
+
process.exitCode = 1;
|
|
161
|
+
}
|
|
162
|
+
});
|
|
138
163
|
program
|
|
139
164
|
.command('setup')
|
|
140
165
|
.description('Set up this device in one pass')
|
package/package.json
CHANGED