- pnpm dev / new pnpm start default to the dashboard command - fn dashboard (and bare fn/fusion/npx, incl. packaged binaries) now runs supervised by default via an attached foreground child (TUI-safe); --no-supervise opts out; FUSION_RESTART_EXIT_CODE=86 = intentional restart - New /api/system routes: info, restart, rebuild jobs with SSE output, engine restart, agents restart-all, plugins reload-all, log tail - System tab: rebuild & restart (source checkouts only, hidden elsewhere), restart server/engine/agents, backup DB, live server logs, copy diagnostics, report bug; new Plugins tab reusing PluginManager - Desktop restart via Electron app.relaunch(); DashboardLogSink now keeps a bounded history + listener feed for the log viewer Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
46 lines
2.1 KiB
TypeScript
46 lines
2.1 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { resolveSupervisorRespawnCommand, shouldSuperviseDashboard } from "../dashboard.js";
|
|
|
|
/*
|
|
FNXC:SystemPanel 2026-07-12-14:25:
|
|
Supervision must be the DEFAULT for the dashboard across install shapes (bare
|
|
`fn`/`fusion`, npx, packaged binary) so the System panel restart works out of
|
|
the box, while never nesting supervisors (FUSION_RESTART_SUPERVISED=1 set by
|
|
the supervisor itself and by scripts/dev-with-memory.mjs), never fighting an
|
|
attached debugger, and honoring the --no-supervise opt-out.
|
|
*/
|
|
describe("shouldSuperviseDashboard", () => {
|
|
it("defaults to supervised for a plain dashboard invocation", () => {
|
|
expect(shouldSuperviseDashboard(["dashboard"], {}, [])).toBe(true);
|
|
});
|
|
|
|
it("defaults to supervised for a bare invocation (no explicit command)", () => {
|
|
expect(shouldSuperviseDashboard([], {}, [])).toBe(true);
|
|
});
|
|
|
|
it("is disabled by --no-supervise", () => {
|
|
expect(shouldSuperviseDashboard(["dashboard", "--no-supervise"], {}, [])).toBe(false);
|
|
});
|
|
|
|
it("never nests: disabled when a supervising parent already exists", () => {
|
|
expect(shouldSuperviseDashboard(["dashboard"], { FUSION_RESTART_SUPERVISED: "1" }, [])).toBe(false);
|
|
});
|
|
|
|
it("is disabled when an inspector is attached (child would fight over the port)", () => {
|
|
expect(shouldSuperviseDashboard(["dashboard"], {}, ["--inspect=9230"])).toBe(false);
|
|
expect(shouldSuperviseDashboard(["dashboard"], {}, ["--inspect-brk"])).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe("resolveSupervisorRespawnCommand", () => {
|
|
it("re-execs the node entry script with execArgv preserved outside a compiled binary", () => {
|
|
const respawn = resolveSupervisorRespawnCommand();
|
|
expect(respawn).not.toBeNull();
|
|
expect(respawn!.command).toBe(process.execPath);
|
|
// Under a plain-node/vitest run, argv[1] is the entry script and must be
|
|
// the last respawn arg, after any loader flags from execArgv.
|
|
expect(respawn!.args[respawn!.args.length - 1]).toBe(process.argv[1]);
|
|
expect(respawn!.args.slice(0, -1)).toEqual(process.execArgv);
|
|
});
|
|
});
|