import path from "node:path"; import { beforeEach, describe, expect, it, vi } from "vitest"; import type { InternalHookEvent } from "../../internal-hooks.js"; const runBootOnce = vi.fn(); const listAgentIds = vi.fn(); const resolveAgentWorkspaceDir = vi.fn(); const logWarn = vi.fn(); const logDebug = vi.fn(); const MAIN_WORKSPACE_DIR = path.join(path.sep, "ws", "main"); const OPS_WORKSPACE_DIR = path.join(path.sep, "ws", "ops"); vi.mock("../../../gateway/boot.js", () => ({ runBootOnce })); vi.mock("../../../agents/agent-scope.js", () => ({ listAgentIds, resolveAgentWorkspaceDir, })); vi.mock("../../../logging/subsystem.js", () => ({ createSubsystemLogger: () => ({ warn: logWarn, debug: logDebug, }), })); const { default: runBootChecklist } = await import("./handler.js"); function makeEvent(overrides?: Partial): InternalHookEvent { return { type: "gateway", action: "startup", sessionKey: "test", context: {}, timestamp: new Date(), messages: [], ...overrides, }; } describe("boot-md handler", () => { function setupTwoAgentBootConfig() { const cfg = { agents: { list: [{ id: "main" }, { id: "ops" }] } }; listAgentIds.mockReturnValue(["main", "ops"]); resolveAgentWorkspaceDir.mockImplementation((_cfg: unknown, id: string) => id === "main" ? MAIN_WORKSPACE_DIR : OPS_WORKSPACE_DIR, ); return cfg; } function setupSingleMainAgentBootConfig(cfg: unknown) { listAgentIds.mockReturnValue(["main"]); resolveAgentWorkspaceDir.mockReturnValue(MAIN_WORKSPACE_DIR); return cfg; } beforeEach(() => { vi.clearAllMocks(); }); it("skips non-gateway events", async () => { await runBootChecklist(makeEvent({ type: "command", action: "new" })); expect(runBootOnce).not.toHaveBeenCalled(); }); it("skips non-startup actions", async () => { await runBootChecklist(makeEvent({ action: "shutdown" })); expect(runBootOnce).not.toHaveBeenCalled(); }); it("skips when cfg is missing from context", async () => { await runBootChecklist(makeEvent({ context: { workspaceDir: "/tmp" } })); expect(runBootOnce).not.toHaveBeenCalled(); }); it("runs boot for each agent", async () => { const cfg = setupTwoAgentBootConfig(); runBootOnce.mockResolvedValue({ status: "ran" }); await runBootChecklist(makeEvent({ context: { cfg } })); expect(listAgentIds).toHaveBeenCalledWith(cfg); expect(runBootOnce).toHaveBeenCalledTimes(2); expect(runBootOnce).toHaveBeenCalledWith( expect.objectContaining({ cfg, workspaceDir: MAIN_WORKSPACE_DIR, agentId: "main" }), ); expect(runBootOnce).toHaveBeenCalledWith( expect.objectContaining({ cfg, workspaceDir: OPS_WORKSPACE_DIR, agentId: "ops" }), ); }); it("runs boot for single default agent when no agents configured", async () => { const cfg = setupSingleMainAgentBootConfig({}); runBootOnce.mockResolvedValue({ status: "skipped", reason: "missing" }); await runBootChecklist(makeEvent({ context: { cfg } })); expect(runBootOnce).toHaveBeenCalledTimes(1); expect(runBootOnce).toHaveBeenCalledWith( expect.objectContaining({ cfg, workspaceDir: MAIN_WORKSPACE_DIR, agentId: "main" }), ); }); it("logs warning details when a per-agent boot run fails", async () => { const cfg = setupTwoAgentBootConfig(); runBootOnce .mockResolvedValueOnce({ status: "ran" }) .mockResolvedValueOnce({ status: "failed", reason: "agent failed" }); await runBootChecklist(makeEvent({ context: { cfg } })); expect(logWarn).toHaveBeenCalledTimes(1); expect(logWarn).toHaveBeenCalledWith("boot-md failed for agent startup run", { agentId: "ops", workspaceDir: OPS_WORKSPACE_DIR, reason: "agent failed", }); }); it("logs debug details when a per-agent boot run is skipped", async () => { const cfg = setupSingleMainAgentBootConfig({ agents: { list: [{ id: "main" }] } }); runBootOnce.mockResolvedValue({ status: "skipped", reason: "missing" }); await runBootChecklist(makeEvent({ context: { cfg } })); expect(logDebug).toHaveBeenCalledWith("boot-md skipped for agent startup run", { agentId: "main", workspaceDir: MAIN_WORKSPACE_DIR, reason: "missing", }); }); });