/** * @file quit.js — Quit AgentHub (issue #65, 9router's tray "Quit"): stop the * dashboard and every lane pane, and keep it stopped until the user starts it * again. "Stopped" is the file `/runtime/stopped`: the plugin * bootstrap starts no server while it exists, and every server that starts * clears it — so a boot or login through an enabled autostart unit still * brings the dashboard back, and only Claude Code's SessionStart is held off. * Kept free of anything but fs/path: the bootstrap reads it before the * runtime's dependencies are installed. * @author Nguyễn Ngọc Trí Vĩ */ const fs = require("fs"); const path = require("path"); const { getDataDir } = require("./claude-home"); function flagPath(rt = path.join(getDataDir(), "runtime")) { return path.join(rt, "stopped"); } function isQuit(rt) { return fs.existsSync(flagPath(rt)); } function markQuit(rt) { const file = flagPath(rt); fs.mkdirSync(path.dirname(file), { recursive: true }); fs.writeFileSync(file, `${new Date().toISOString()}\n`, "utf8"); } function clearQuit(rt) { fs.rmSync(flagPath(rt), { force: true }); } /** * Stops this server. A unit of ours that is running is stopped THROUGH its * service manager: a SIGTERM'd server exits 0, which `Restart=always` / * `KeepAlive` answer by starting it again. Async spawns, because launchd's * `bootout` waits for the job — this process — to exit. If this process was * not the unit's (a second dashboard beside it), it follows a moment later. */ function stopServer({ svc = require("../../scripts/service-manager"), spawn = require("child_process").spawn, kill = () => process.kill(process.pid, "SIGTERM"), } = {}) { const owned = svc.systemctlAvailable() && svc.unitIsOurs("agenthub") && svc.unitIsActive("agenthub"); if (!owned) return kill(); const argv = svc.kind === "launchd" ? ["launchctl", ["bootout", `gui/${process.getuid()}/io.smartgift.agenthub`]] : ["systemctl", ["--user", "stop", "--no-block", "agenthub.service"]]; spawn(argv[0], argv[1], { detached: true, stdio: "ignore" }).unref(); setTimeout(kill, 5000).unref(); } module.exports = { flagPath, isQuit, markQuit, clearQuit, stopServer };