claude-flow
Version:
Ruflo - Enterprise AI agent orchestration for Claude Code. Deploy 60+ specialized agents in coordinated swarms with self-learning, fault-tolerant consensus, vector memory, and MCP integration
70 lines • 2.4 kB
JavaScript
/**
* Parent-death watchdog (#2234).
*
* `ruflo mcp start` runs as a double-forked grandchild of Claude Code (`npx -y
* ruflo … mcp start` → `npm exec …` → `node … mcp start`). When Claude Code
* exits, only the `npm exec` shim is terminated; the `node` server reparents to
* `launchd`/`init` (`ppid === 1`) and silently lingers — leaving ~50 MB and an
* open database handle per restart. Over a week this accumulates to ~20
* orphaned servers (~1 GB), and an arbitrary stale one can win the next stdio
* handshake, transparently serving superseded code.
*
* Cheap, robust fix: poll `process.ppid`. When it becomes 1 (and didn't start
* there), our original parent has exited — we're orphaned. Run the cleanup
* hook and exit cleanly.
*
* @module runtime/parent-death-watchdog
*/
/**
* Install a parent-death watchdog. Safe to call once per process; calling
* twice replaces the previous interval.
*/
export function installParentDeathWatchdog(opts = {}) {
const intervalMs = opts.intervalMs ?? 2000;
const get = opts.ppidGetter ?? (() => process.ppid);
const exit = opts.exit ?? ((code) => process.exit(code));
const onOrphaned = opts.onOrphaned;
const initialPpid = get();
let triggered = false;
let timer;
const triggerOrphaned = async () => {
if (triggered)
return;
triggered = true;
if (timer) {
clearInterval(timer);
timer = undefined;
}
try {
if (onOrphaned)
await onOrphaned();
exit(0);
}
catch {
exit(1);
}
};
const checkOnce = async () => {
// Only trigger when we *transition* to ppid=1; if we already started there
// (process launched directly under launchd/init) it isn't an orphan event.
const ppid = get();
if (ppid === 1 && initialPpid !== 1)
await triggerOrphaned();
};
timer = setInterval(() => {
void checkOnce();
}, intervalMs);
// Don't keep the event loop alive on the watchdog alone.
if (typeof timer.unref === 'function')
timer.unref();
return {
stop() {
if (timer) {
clearInterval(timer);
timer = undefined;
}
},
checkOnce,
};
}
//# sourceMappingURL=parent-death-watchdog.js.map