oc-inspector 1.5.0 → 1.5.1
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/bin/cli.mjs +50 -0
- package/package.json +1 -1
- package/src/config.mjs +12 -2
package/bin/cli.mjs
CHANGED
|
@@ -350,7 +350,31 @@ async function runDaemonStop(silent = false, cmdOpts = {}) {
|
|
|
350
350
|
|
|
351
351
|
if (st.alive) {
|
|
352
352
|
try {
|
|
353
|
+
// 2a. Send SIGTERM for graceful shutdown
|
|
353
354
|
process.kill(st.pid, "SIGTERM");
|
|
355
|
+
|
|
356
|
+
// 2b. Wait up to 5 seconds for the process to exit
|
|
357
|
+
let died = false;
|
|
358
|
+
for (let i = 0; i < 10; i++) {
|
|
359
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
360
|
+
try {
|
|
361
|
+
process.kill(st.pid, 0); // probe — throws ESRCH if dead
|
|
362
|
+
} catch {
|
|
363
|
+
died = true;
|
|
364
|
+
break;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// 2c. Escalate to SIGKILL if still alive
|
|
369
|
+
if (!died) {
|
|
370
|
+
try {
|
|
371
|
+
process.kill(st.pid, "SIGKILL");
|
|
372
|
+
if (!silent) {
|
|
373
|
+
console.log(` \x1b[33m⚠\x1b[0m Process didn't exit after SIGTERM — sent SIGKILL (PID ${st.pid})`);
|
|
374
|
+
}
|
|
375
|
+
} catch { /* already dead */ }
|
|
376
|
+
}
|
|
377
|
+
|
|
354
378
|
if (!silent) {
|
|
355
379
|
console.log(` \x1b[32m✓\x1b[0m Stopped inspector (PID ${st.pid})`);
|
|
356
380
|
console.log("");
|
|
@@ -463,8 +487,17 @@ async function runServe(opts) {
|
|
|
463
487
|
}
|
|
464
488
|
|
|
465
489
|
const gracefulShutdown = async (signal) => {
|
|
490
|
+
// Force-exit after 5s so we never leave a zombie process
|
|
491
|
+
const forceTimer = setTimeout(() => {
|
|
492
|
+
console.log(" \x1b[33m⚠\x1b[0m Shutdown timed out — forcing exit");
|
|
493
|
+
cleanupPidFile();
|
|
494
|
+
process.exit(1);
|
|
495
|
+
}, 5000);
|
|
496
|
+
forceTimer.unref();
|
|
497
|
+
|
|
466
498
|
console.log(`\n Shutting down (${signal})...`);
|
|
467
499
|
await restoreConfigOnExit(opts);
|
|
500
|
+
cleanupPidFile();
|
|
468
501
|
process.exit(0);
|
|
469
502
|
};
|
|
470
503
|
|
|
@@ -503,8 +536,17 @@ async function runForeground(opts) {
|
|
|
503
536
|
}
|
|
504
537
|
|
|
505
538
|
const gracefulShutdown = async (signal) => {
|
|
539
|
+
// Force-exit after 5s so we never leave a zombie process
|
|
540
|
+
const forceTimer = setTimeout(() => {
|
|
541
|
+
console.log(" \x1b[33m⚠\x1b[0m Shutdown timed out — forcing exit");
|
|
542
|
+
cleanupPidFile();
|
|
543
|
+
process.exit(1);
|
|
544
|
+
}, 5000);
|
|
545
|
+
forceTimer.unref();
|
|
546
|
+
|
|
506
547
|
console.log(`\n Shutting down (${signal})...`);
|
|
507
548
|
await restoreConfigOnExit(opts);
|
|
549
|
+
cleanupPidFile();
|
|
508
550
|
process.exit(0);
|
|
509
551
|
};
|
|
510
552
|
|
|
@@ -512,6 +554,14 @@ async function runForeground(opts) {
|
|
|
512
554
|
process.on("SIGTERM", () => gracefulShutdown("SIGTERM"));
|
|
513
555
|
}
|
|
514
556
|
|
|
557
|
+
/**
|
|
558
|
+
* Remove the daemon PID file on exit.
|
|
559
|
+
* Called during graceful shutdown so stop/status don't see stale PIDs.
|
|
560
|
+
*/
|
|
561
|
+
function cleanupPidFile() {
|
|
562
|
+
try { unlinkSync(PID_FILE); } catch { /* ignore */ }
|
|
563
|
+
}
|
|
564
|
+
|
|
515
565
|
/**
|
|
516
566
|
* Restore original OpenClaw config on process exit.
|
|
517
567
|
* Used by graceful shutdown handlers in _serve and run modes.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "oc-inspector",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.1",
|
|
4
4
|
"description": "Real-time API traffic inspector for OpenClaw — intercepts LLM provider requests, shows token usage, costs, and message flow in a live web dashboard.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/src/config.mjs
CHANGED
|
@@ -14,6 +14,16 @@ import { homedir } from "node:os";
|
|
|
14
14
|
import { execSync } from "node:child_process";
|
|
15
15
|
import { BUILTIN_URLS, detectActiveProviders } from "./providers.mjs";
|
|
16
16
|
|
|
17
|
+
/**
|
|
18
|
+
* Regex matching inspector proxy URLs on localhost (any port).
|
|
19
|
+
*
|
|
20
|
+
* Used to detect whether a baseUrl has been patched by the inspector,
|
|
21
|
+
* regardless of which port was configured at the time.
|
|
22
|
+
*
|
|
23
|
+
* @type {RegExp}
|
|
24
|
+
*/
|
|
25
|
+
const PROXY_URL_RE = /127\.0\.0\.1:\d+/;
|
|
26
|
+
|
|
17
27
|
/** Default OpenClaw state directory. */
|
|
18
28
|
const DEFAULT_OPENCLAW_DIR = join(homedir(), ".openclaw");
|
|
19
29
|
|
|
@@ -260,7 +270,7 @@ export function disable({ configPath, openclawDir }) {
|
|
|
260
270
|
// Verify backup is clean (doesn't contain proxy URLs)
|
|
261
271
|
try {
|
|
262
272
|
const backupContent = readFileSync(backupPath, "utf-8");
|
|
263
|
-
if (!
|
|
273
|
+
if (!PROXY_URL_RE.test(backupContent)) {
|
|
264
274
|
copyFileSync(backupPath, configPath);
|
|
265
275
|
removeState(openclawDir);
|
|
266
276
|
const restart = restartGateway();
|
|
@@ -331,7 +341,7 @@ function cleanProxyUrls(configPath) {
|
|
|
331
341
|
let cleaned = false;
|
|
332
342
|
|
|
333
343
|
for (const [name, cfg] of Object.entries(providers)) {
|
|
334
|
-
if (cfg.baseUrl && cfg.baseUrl
|
|
344
|
+
if (cfg.baseUrl && PROXY_URL_RE.test(cfg.baseUrl)) {
|
|
335
345
|
if (BUILTIN_URLS[name]) {
|
|
336
346
|
// Known provider — restore builtin URL
|
|
337
347
|
cfg.baseUrl = BUILTIN_URLS[name];
|