import { describe, expect, it } from "vitest"; import type { AgentState } from "@/features/agents/state/store"; import { parseExecApprovalRequested, parseExecApprovalResolved, resolveExecApprovalAgentId, } from "@/features/agents/approvals/execApprovalEvents"; import type { EventFrame } from "@/lib/gateway/GatewayClient"; const createAgent = (agentId: string, sessionKey: string): AgentState => ({ agentId, name: agentId, sessionKey, status: "idle", sessionCreated: true, awaitingUserInput: false, hasUnseenActivity: false, outputLines: [], lastResult: null, lastDiff: null, runId: null, runStartedAt: null, streamText: null, thinkingTrace: null, latestOverride: null, latestOverrideKind: null, lastAssistantMessageAt: null, lastActivityAt: null, latestPreview: null, lastUserMessage: null, draft: "", sessionSettingsSynced: true, historyLoadedAt: null, historyFetchLimit: null, historyFetchedCount: null, historyMaybeTruncated: false, toolCallingEnabled: true, showThinkingTraces: true, model: "openai/gpt-5", thinkingLevel: "medium", avatarSeed: agentId, avatarUrl: null, }); describe("execApprovalEvents", () => { it("parses exec.approval.requested payload", () => { const event: EventFrame = { type: "event", event: "exec.approval.requested", payload: { id: "approval-1", request: { command: "npm run test", cwd: "/repo", host: "gateway", security: "allowlist", ask: "always", agentId: "agent-1", resolvedPath: "/bin/npm", sessionKey: "agent:agent-1:main", }, createdAtMs: 123, expiresAtMs: 456, }, }; expect(parseExecApprovalRequested(event)).toEqual({ id: "approval-1", request: { command: "npm run test", cwd: "/repo", host: "gateway", security: "allowlist", ask: "always", agentId: "agent-1", resolvedPath: "/bin/npm", sessionKey: "agent:agent-1:main", }, createdAtMs: 123, expiresAtMs: 456, }); }); it("returns null for invalid requested payload", () => { const event: EventFrame = { type: "event", event: "exec.approval.requested", payload: { id: "approval-1", request: { command: "" }, createdAtMs: 0, expiresAtMs: 0, }, }; expect(parseExecApprovalRequested(event)).toBeNull(); }); it("parses exec.approval.resolved payload", () => { const event: EventFrame = { type: "event", event: "exec.approval.resolved", payload: { id: "approval-1", decision: "allow-once", resolvedBy: "studio", ts: 987, }, }; expect(parseExecApprovalResolved(event)).toEqual({ id: "approval-1", decision: "allow-once", resolvedBy: "studio", ts: 987, }); }); it("returns null for unknown resolved decision", () => { const event: EventFrame = { type: "event", event: "exec.approval.resolved", payload: { id: "approval-1", decision: "approve", ts: 987, }, }; expect(parseExecApprovalResolved(event)).toBeNull(); }); it("resolves approval agent by explicit agent id", () => { const requested = { id: "approval-1", request: { command: "pwd", cwd: null, host: "gateway", security: null, ask: null, agentId: "agent-2", resolvedPath: null, sessionKey: "agent:agent-2:main", }, createdAtMs: 1, expiresAtMs: 2, }; const agents = [ createAgent("agent-1", "agent:agent-1:main"), createAgent("agent-2", "agent:agent-2:main"), ]; expect(resolveExecApprovalAgentId({ requested, agents })).toBe("agent-2"); }); it("trusts explicit agent id even when the local agent list has not hydrated it yet", () => { const requested = { id: "approval-1", request: { command: "pwd", cwd: null, host: "gateway", security: null, ask: null, agentId: "agent-prehydration", resolvedPath: null, sessionKey: "agent:agent-prehydration:main", }, createdAtMs: 1, expiresAtMs: 2, }; const agents = [createAgent("agent-1", "agent:agent-1:main")]; expect(resolveExecApprovalAgentId({ requested, agents })).toBe("agent-prehydration"); }); it("falls back to session key when agent id missing", () => { const requested = { id: "approval-1", request: { command: "pwd", cwd: null, host: "gateway", security: null, ask: null, agentId: null, resolvedPath: null, sessionKey: "agent:agent-3:main", }, createdAtMs: 1, expiresAtMs: 2, }; const agents = [createAgent("agent-3", "agent:agent-3:main")]; expect(resolveExecApprovalAgentId({ requested, agents })).toBe("agent-3"); }); it("returns null when no agent mapping matches", () => { const requested = { id: "approval-1", request: { command: "pwd", cwd: null, host: "gateway", security: null, ask: null, agentId: null, resolvedPath: null, sessionKey: "agent:missing:main", }, createdAtMs: 1, expiresAtMs: 2, }; const agents = [createAgent("agent-1", "agent:agent-1:main")]; expect(resolveExecApprovalAgentId({ requested, agents })).toBeNull(); }); });