import type { AgentState } from "@/features/agents/state/store"; import type { EventFrame } from "@/lib/gateway/GatewayClient"; import type { ExecApprovalDecision } from "@/features/agents/approvals/types"; type RequestedPayload = { id: string; request: { command: string; cwd: string | null; host: string | null; security: string | null; ask: string | null; agentId: string | null; resolvedPath: string | null; sessionKey: string | null; }; createdAtMs: number; expiresAtMs: number; }; type ResolvedPayload = { id: string; decision: ExecApprovalDecision; resolvedBy: string | null; ts: number; }; const asRecord = (value: unknown): Record | null => value && typeof value === "object" && !Array.isArray(value) ? (value as Record) : null; const asNonEmptyString = (value: unknown): string | null => { if (typeof value !== "string") return null; const trimmed = value.trim(); return trimmed.length > 0 ? trimmed : null; }; const asOptionalString = (value: unknown): string | null => typeof value === "string" && value.trim().length > 0 ? value.trim() : null; const asPositiveTimestamp = (value: unknown): number | null => typeof value === "number" && Number.isFinite(value) && value > 0 ? value : null; export const parseExecApprovalRequested = (event: EventFrame): RequestedPayload | null => { if (event.type !== "event" || event.event !== "exec.approval.requested") return null; const payload = asRecord(event.payload); if (!payload) return null; const id = asNonEmptyString(payload.id); const request = asRecord(payload.request); const createdAtMs = asPositiveTimestamp(payload.createdAtMs); const expiresAtMs = asPositiveTimestamp(payload.expiresAtMs); if (!id || !request || !createdAtMs || !expiresAtMs) return null; const command = asNonEmptyString(request.command); if (!command) return null; return { id, request: { command, cwd: asOptionalString(request.cwd), host: asOptionalString(request.host), security: asOptionalString(request.security), ask: asOptionalString(request.ask), agentId: asOptionalString(request.agentId), resolvedPath: asOptionalString(request.resolvedPath), sessionKey: asOptionalString(request.sessionKey), }, createdAtMs, expiresAtMs, }; }; export const parseExecApprovalResolved = (event: EventFrame): ResolvedPayload | null => { if (event.type !== "event" || event.event !== "exec.approval.resolved") return null; const payload = asRecord(event.payload); if (!payload) return null; const id = asNonEmptyString(payload.id); const decisionRaw = asNonEmptyString(payload.decision); const ts = asPositiveTimestamp(payload.ts); if (!id || !decisionRaw || !ts) return null; if (decisionRaw !== "allow-once" && decisionRaw !== "allow-always" && decisionRaw !== "deny") { return null; } return { id, decision: decisionRaw, resolvedBy: asOptionalString(payload.resolvedBy), ts, }; }; export const resolveExecApprovalAgentId = (params: { requested: RequestedPayload; agents: AgentState[]; }): string | null => { const requestedAgentId = params.requested.request.agentId; if (requestedAgentId) { return requestedAgentId; } const requestedSessionKey = params.requested.request.sessionKey; if (!requestedSessionKey) return null; const matchedBySession = params.agents.find( (agent) => agent.sessionKey.trim() === requestedSessionKey ); return matchedBySession?.agentId ?? null; };