import express from "express"; import request from "supertest"; import { beforeEach, describe, expect, it, vi } from "vitest"; const mockAgentService = vi.hoisted(() => ({ getById: vi.fn(), })); const mockHeartbeatService = vi.hoisted(() => ({ getRunIssueSummary: vi.fn(), getActiveRunIssueSummaryForAgent: vi.fn(), })); const mockIssueService = vi.hoisted(() => ({ getById: vi.fn(), getByIdentifier: vi.fn(), })); function registerModuleMocks() { vi.doMock("../services/index.js", () => ({ agentService: () => mockAgentService, agentInstructionsService: () => ({}), accessService: () => ({}), approvalService: () => ({}), companySkillService: () => ({ listRuntimeSkillEntries: vi.fn() }), budgetService: () => ({}), heartbeatService: () => mockHeartbeatService, issueApprovalService: () => ({}), issueService: () => mockIssueService, logActivity: vi.fn(), secretService: () => ({}), syncInstructionsBundleConfigFromFilePath: vi.fn((_agent, config) => config), workspaceOperationService: () => ({}), })); vi.doMock("../adapters/index.js", () => ({ findServerAdapter: vi.fn(), listAdapterModels: vi.fn(), detectAdapterModel: vi.fn(), findActiveServerAdapter: vi.fn(), requireServerAdapter: vi.fn(), })); } async function createApp() { const [{ agentRoutes }, { errorHandler }] = await Promise.all([ vi.importActual("../routes/agents.js"), vi.importActual("../middleware/index.js"), ]); const app = express(); app.use(express.json()); app.use((req, _res, next) => { (req as any).actor = { type: "board", userId: "local-board", companyIds: ["company-1"], source: "local_implicit", isInstanceAdmin: false, }; next(); }); app.use("/api", agentRoutes({} as any)); app.use(errorHandler); return app; } describe("agent live run routes", () => { beforeEach(() => { vi.resetModules(); vi.doUnmock("../services/index.js"); vi.doUnmock("../adapters/index.js"); vi.doUnmock("../routes/agents.js"); vi.doUnmock("../routes/authz.js"); vi.doUnmock("../middleware/index.js"); registerModuleMocks(); vi.resetAllMocks(); mockIssueService.getByIdentifier.mockResolvedValue({ id: "issue-1", companyId: "company-1", executionRunId: "run-1", assigneeAgentId: "agent-1", status: "in_progress", }); mockIssueService.getById.mockResolvedValue(null); mockAgentService.getById.mockResolvedValue({ id: "agent-1", companyId: "company-1", name: "Builder", adapterType: "codex_local", }); mockHeartbeatService.getRunIssueSummary.mockResolvedValue({ id: "run-1", status: "running", invocationSource: "on_demand", triggerDetail: "manual", startedAt: new Date("2026-04-10T09:30:00.000Z"), finishedAt: null, createdAt: new Date("2026-04-10T09:29:59.000Z"), agentId: "agent-1", issueId: "issue-1", }); mockHeartbeatService.getActiveRunIssueSummaryForAgent.mockResolvedValue(null); }); it("returns a compact active run payload for issue polling", async () => { const res = await request(await createApp()).get("/api/issues/PAP-1295/active-run"); expect(res.status, JSON.stringify(res.body)).toBe(200); expect(mockIssueService.getByIdentifier).toHaveBeenCalledWith("PAP-1295"); expect(mockHeartbeatService.getRunIssueSummary).toHaveBeenCalledWith("run-1"); expect(res.body).toEqual({ id: "run-1", status: "running", invocationSource: "on_demand", triggerDetail: "manual", startedAt: "2026-04-10T09:30:00.000Z", finishedAt: null, createdAt: "2026-04-10T09:29:59.000Z", agentId: "agent-1", issueId: "issue-1", agentName: "Builder", adapterType: "codex_local", }); expect(res.body).not.toHaveProperty("resultJson"); expect(res.body).not.toHaveProperty("contextSnapshot"); expect(res.body).not.toHaveProperty("logRef"); }); it("ignores a stale execution run from another issue and falls back to the assignee's matching run", async () => { mockHeartbeatService.getRunIssueSummary.mockResolvedValue({ id: "run-foreign", status: "running", invocationSource: "assignment", triggerDetail: "callback", startedAt: new Date("2026-04-10T10:00:00.000Z"), finishedAt: null, createdAt: new Date("2026-04-10T09:59:00.000Z"), agentId: "agent-1", issueId: "issue-2", }); mockHeartbeatService.getActiveRunIssueSummaryForAgent.mockResolvedValue({ id: "run-1", status: "running", invocationSource: "on_demand", triggerDetail: "manual", startedAt: new Date("2026-04-10T09:30:00.000Z"), finishedAt: null, createdAt: new Date("2026-04-10T09:29:59.000Z"), agentId: "agent-1", issueId: "issue-1", }); const res = await request(await createApp()).get("/api/issues/PAP-1295/active-run"); expect(res.status, JSON.stringify(res.body)).toBe(200); expect(mockHeartbeatService.getRunIssueSummary).toHaveBeenCalledWith("run-1"); expect(mockHeartbeatService.getActiveRunIssueSummaryForAgent).toHaveBeenCalledWith("agent-1"); expect(res.body).toMatchObject({ id: "run-1", issueId: "issue-1", agentId: "agent-1", agentName: "Builder", adapterType: "codex_local", }); }); });