fix(tray): kill child PID before IPC close to avoid macOS NSStatusItem orphan

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
decolua 2026-05-15 13:13:28 +07:00
parent bb86808582
commit e1db49190a
4 changed files with 20 additions and 6 deletions

View file

@ -685,6 +685,11 @@ function startServer(latestVersion) {
const { clearScreen } = require("./src/cli/utils/display");
clearScreen();
// Kill current tray FIRST so the new bgProcess can register a fresh
// NSStatusItem on macOS without conflicting with the orphan binary
try { require("./src/cli/tray/tray").killTray(); } catch (e) { }
await new Promise(r => setTimeout(r, 300));
// Enable auto startup on OS boot
try {
const { enableAutoStart } = require("./src/cli/tray/autostart");

View file

@ -1,6 +1,6 @@
{
"name": "9router",
"version": "0.4.44",
"version": "0.4.45",
"description": "9Router CLI - Start and manage 9Router server",
"bin": {
"9router": "./cli.js"

View file

@ -255,10 +255,19 @@ function killTray() {
if (instance) {
try {
if (wasWin) instance.kill();
// systray2.kill(true) defaults to calling process.exit(0) which aborts
// the rest of cleanup (server SIGKILL, MITM/tunnel cleanup). Pass false
// so callers stay in control of process exit.
else instance.kill(false);
else {
// systray2.kill(false) closes IPC but leaves the Go tray binary
// subprocess running, which keeps an orphan NSStatusItem on macOS
// and blocks a freshly spawned tray (e.g. hide-to-tray bgProcess)
// from registering. Kill the child PID directly first.
try {
const proc = instance._process || (typeof instance.process === "function" ? instance.process() : null);
if (proc && proc.pid) {
process.kill(proc.pid, "SIGKILL");
}
} catch (e) {}
instance.kill(false);
}
} catch (e) {}
}
}

View file

@ -1,6 +1,6 @@
{
"name": "9router-app",
"version": "0.4.44",
"version": "0.4.45",
"description": "9Router web dashboard",
"private": true,
"scripts": {