robot-resources 1.7.6 → 1.7.7
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/lib/tool-config.js +46 -1
- package/lib/wizard.js +16 -8
- package/package.json +1 -1
package/lib/tool-config.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
1
2
|
import { createRequire } from 'node:module';
|
|
2
3
|
import { readFileSync, writeFileSync, copyFileSync, mkdirSync, existsSync } from 'node:fs';
|
|
3
4
|
import { homedir } from 'node:os';
|
|
@@ -220,5 +221,49 @@ export function configureToolRouting() {
|
|
|
220
221
|
return results;
|
|
221
222
|
}
|
|
222
223
|
|
|
224
|
+
/**
|
|
225
|
+
* Run a command with a heartbeat to keep agent sessions alive.
|
|
226
|
+
* OC kills processes after 5s of no output (noOutputTimeoutMs = 5000).
|
|
227
|
+
* Prints immediately, then every 4s (safely under the 5s threshold).
|
|
228
|
+
*/
|
|
229
|
+
function spawnWithHeartbeat(cmd, args, { label, timeout = 30_000 } = {}) {
|
|
230
|
+
return new Promise((resolve, reject) => {
|
|
231
|
+
const proc = spawn(cmd, args, {
|
|
232
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
233
|
+
timeout,
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
process.stdout.write(` ${label}...\n`);
|
|
237
|
+
let seconds = 0;
|
|
238
|
+
const heartbeat = setInterval(() => {
|
|
239
|
+
seconds += 4;
|
|
240
|
+
process.stdout.write(` ${label}... ${seconds}s\n`);
|
|
241
|
+
}, 4000);
|
|
242
|
+
|
|
243
|
+
proc.on('close', (code) => {
|
|
244
|
+
clearInterval(heartbeat);
|
|
245
|
+
if (code === 0) resolve();
|
|
246
|
+
else reject(new Error(`${cmd} ${args.join(' ')} exited with code ${code}`));
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
proc.on('error', (err) => {
|
|
250
|
+
clearInterval(heartbeat);
|
|
251
|
+
reject(err);
|
|
252
|
+
});
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Restart the OpenClaw gateway so it picks up new plugin + config.
|
|
258
|
+
* Uses heartbeat to keep OC sessions alive during the restart.
|
|
259
|
+
* Telegram survives this restart — tested end-to-end (PR #89).
|
|
260
|
+
*/
|
|
261
|
+
async function restartOpenClawGateway() {
|
|
262
|
+
await spawnWithHeartbeat('openclaw', ['gateway', 'restart'], {
|
|
263
|
+
label: 'Restarting gateway',
|
|
264
|
+
timeout: 15_000,
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
|
|
223
268
|
// Exported for testing and direct use
|
|
224
|
-
export { stripJson5, configureOpenClaw, registerScraperMcp };
|
|
269
|
+
export { stripJson5, configureOpenClaw, registerScraperMcp, restartOpenClawGateway };
|
package/lib/wizard.js
CHANGED
|
@@ -2,11 +2,11 @@ import { readFileSync, writeFileSync, mkdirSync } from 'node:fs';
|
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
import { homedir, hostname } from 'node:os';
|
|
4
4
|
import { readConfig, writeConfig } from '@robot-resources/cli-core/config.mjs';
|
|
5
|
-
import { findPython, isPortAvailable, isHeadless } from './detect.js';
|
|
5
|
+
import { findPython, isPortAvailable, isHeadless, isOpenClawInstalled } from './detect.js';
|
|
6
6
|
import { getOrCreateMachineId } from './machine-id.js';
|
|
7
7
|
import { setupRouter, isRouterInstalled, getVenvPythonPath } from './python-bridge.js';
|
|
8
8
|
import { installService, isServiceRunning, isServiceInstalled } from './service.js';
|
|
9
|
-
import { configureToolRouting, registerScraperMcp } from './tool-config.js';
|
|
9
|
+
import { configureToolRouting, registerScraperMcp, restartOpenClawGateway } from './tool-config.js';
|
|
10
10
|
import { checkHealth } from './health-report.js';
|
|
11
11
|
import { header, step, success, warn, error, info, blank, summary } from './ui.js';
|
|
12
12
|
/**
|
|
@@ -382,11 +382,19 @@ export async function runWizard({ nonInteractive = false } = {}) {
|
|
|
382
382
|
}
|
|
383
383
|
}
|
|
384
384
|
|
|
385
|
-
// ──
|
|
385
|
+
// ── Best-effort: Single gateway restart (MUST be last) ─────────────────
|
|
386
386
|
//
|
|
387
|
-
//
|
|
388
|
-
//
|
|
389
|
-
//
|
|
390
|
-
//
|
|
391
|
-
|
|
387
|
+
// Everything is already installed, configured, and reported above.
|
|
388
|
+
// The restart loads the plugin + scraper MCP into the running gateway.
|
|
389
|
+
// Telegram survives this restart. If the session dies here, the agent
|
|
390
|
+
// picks up on the next message with all tools loaded.
|
|
391
|
+
|
|
392
|
+
if (isOpenClawInstalled() && (results.tools?.some(r => r.action === 'installed') || scraperRegistered)) {
|
|
393
|
+
try {
|
|
394
|
+
await restartOpenClawGateway();
|
|
395
|
+
success('OpenClaw gateway restarted');
|
|
396
|
+
} catch {
|
|
397
|
+
// Best-effort — gateway picks up changes on next restart
|
|
398
|
+
}
|
|
399
|
+
}
|
|
392
400
|
}
|