f460fff406
- Sagi: clicking the pet opens its chat window directly (PetChat + SagiInfo status strip, Needs you, Mute / Clear alerts); SagiPanel removed. - Chat view answers Claude's unnumbered folder-trust prompt (parseBareMenu). - pty-attach: resize/write after a Windows attach exited, and node-pty's pipe errors, no longer throw out of the WebSocket handler. - restart-helper: the server started by an update logs to data/agenthub-server.log instead of discarding its output.
69 lines
2.0 KiB
JavaScript
69 lines
2.0 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* @file Detached helper spawned by `server/lib/self-restart.js`. Polls the
|
|
* old dashboard PID until it exits (server/index.js's own SIGTERM handler
|
|
* has a 5s force-exit backstop, so this never waits forever), then starts a
|
|
* fresh server from the same entry point and exits itself. The new server's
|
|
* stdout/stderr are appended to the log file it is given (the checkout's
|
|
* `data/agenthub-server.log`, the one `agenthub start` writes), so a crash
|
|
* after an update still leaves Node's stack trace behind.
|
|
* @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>
|
|
*/
|
|
|
|
require("../server/lib/windows-hide").install(); // before child_process is read
|
|
const fs = require("fs");
|
|
const path = require("path");
|
|
const { spawn } = require("child_process");
|
|
const { rotateIfLarge } = require("./log-rotate");
|
|
|
|
const [, , pidArg, entry, logArg] = process.argv;
|
|
const pid = parseInt(pidArg, 10);
|
|
|
|
// ponytail: fixed poll cadence/cap, not configurable — this script has one caller.
|
|
const POLL_MS = 200;
|
|
const MAX_WAIT_MS = 20_000;
|
|
|
|
function isAlive(p) {
|
|
try {
|
|
process.kill(p, 0);
|
|
return true;
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/** Append fd for the new server's output, or "ignore" when there is none. */
|
|
function openLog(file) {
|
|
if (!file) return "ignore";
|
|
try {
|
|
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
rotateIfLarge(file);
|
|
const fd = fs.openSync(file, "a");
|
|
fs.writeSync(fd, `[${new Date().toISOString()}] restart-helper: old server ${pid} gone, starting ${entry}\n`);
|
|
return fd;
|
|
} catch {
|
|
return "ignore"; // a log must never stop the restart
|
|
}
|
|
}
|
|
|
|
function restart() {
|
|
const out = openLog(logArg);
|
|
const child = spawn(process.execPath, [entry], {
|
|
detached: true,
|
|
stdio: ["ignore", out, out],
|
|
env: process.env,
|
|
});
|
|
child.unref();
|
|
process.exit(0);
|
|
}
|
|
|
|
function waitAndRestart(waited = 0) {
|
|
if (isAlive(pid) && waited < MAX_WAIT_MS) {
|
|
setTimeout(() => waitAndRestart(waited + POLL_MS), POLL_MS);
|
|
return;
|
|
}
|
|
restart();
|
|
}
|
|
|
|
waitAndRestart();
|