import { mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises"; import { createRequire } from "node:module"; import { dirname, join, resolve } from "node:path"; import { fileURLToPath, pathToFileURL } from "node:url"; import { createJiti } from "jiti"; import { describe, expect, it } from "vitest"; import { WSOutboundMessageSchema as GeneratedWSOutboundMessageSchema } from "../../src/generated/validation/ws-outbound.aot.js"; interface GeneratedSchema { safeParse(input: unknown): { success: boolean; data?: unknown }; } const protocolRoot = resolve(dirname(fileURLToPath(import.meta.url)), "../.."); const generatedWSOutboundPath = resolve( protocolRoot, "src/generated/validation/ws-outbound.aot.ts", ); const require = createRequire(import.meta.url); async function compileInlineSchema(sourceSchema: string): Promise { const scratchRoot = resolve(protocolRoot, "../../.tmp"); await mkdir(scratchRoot, { recursive: true }); const tempDir = await mkdtemp(join(scratchRoot, "paseo-zod-aot-")); try { const sourcePath = join(tempDir, "schema.source.js"); const outputPath = join(tempDir, "schema.generated.ts"); await writeFile(join(tempDir, "package.json"), '{"type":"module"}\n'); await writeFile( sourcePath, [ 'import { z } from "zod";', 'import { compile } from "zod-aot";', sourceSchema, "export const Schema = compile(SourceSchema);", "", ].join("\n"), ); const zodAotEntry = require.resolve("zod-aot"); const zodAotRoot = resolve(dirname(zodAotEntry), ".."); const [{ discoverSchemas }, { compileSchemas }, { generateCompiledFileContent }] = await Promise.all([ import(pathToFileURL(resolve(zodAotRoot, "dist/discovery.js")).href), import(pathToFileURL(resolve(zodAotRoot, "dist/core/pipeline.js")).href), import(pathToFileURL(resolve(zodAotRoot, "dist/cli/emitter.js")).href), ]); const schemas = await discoverSchemas(sourcePath, { cacheBust: true }); const compiled = compileSchemas(schemas, { mode: "inline" }); const content = generateCompiledFileContent(compiled, "./schema.source.js", { zodCompat: false, }); await writeFile(outputPath, content); const jiti = createJiti(import.meta.url, { moduleCache: false }); const generated = await jiti.import(outputPath); return generated.Schema as GeneratedSchema; } finally { await rm(tempDir, { recursive: true, force: true }); } } describe("WS outbound zod-aot validation", () => { it("applies defaults inside discriminated-union branches", async () => { const schema = await compileInlineSchema(` const SourceSchema = z.discriminatedUnion("type", [ z.object({ type: z.literal("with_default"), enabled: z.boolean().default(true), }), z.object({ type: z.literal("without_default"), label: z.string(), }), ]); `); expect(schema.safeParse({ type: "with_default" })).toMatchObject({ success: true, data: { type: "with_default", enabled: true }, }); }); it("routes tool-call-like status unions through the current sequential item union", async () => { const schema = await compileInlineSchema(` const ToolCallItemSchema = z.discriminatedUnion("status", [ z.object({ type: z.literal("tool_call"), status: z.literal("running"), callId: z.string() }), z.object({ type: z.literal("tool_call"), status: z.literal("completed"), callId: z.string(), output: z.string() }), z.object({ type: z.literal("tool_call"), status: z.literal("failed"), callId: z.string(), error: z.string() }), z.object({ type: z.literal("tool_call"), status: z.literal("canceled"), callId: z.string() }), ]); const TimelineItemSchema = z.union([ z.object({ type: z.literal("assistant_message"), text: z.string() }), ToolCallItemSchema, ]); const SourceSchema = z.object({ item: TimelineItemSchema, }); `); expect( schema.safeParse({ item: { type: "tool_call", status: "running", callId: "run" } }), ).toMatchObject({ success: true, data: { item: { type: "tool_call", status: "running", callId: "run" } }, }); expect( schema.safeParse({ item: { type: "tool_call", status: "completed", callId: "done", output: "ok" }, }), ).toMatchObject({ success: true, data: { item: { type: "tool_call", status: "completed", callId: "done", output: "ok" } }, }); expect( schema.safeParse({ item: { type: "tool_call", status: "failed", callId: "fail", error: "boom" }, }), ).toMatchObject({ success: true, data: { item: { type: "tool_call", status: "failed", callId: "fail", error: "boom" } }, }); expect( schema.safeParse({ item: { type: "tool_call", status: "canceled", callId: "stop" } }), ).toMatchObject({ success: true, data: { item: { type: "tool_call", status: "canceled", callId: "stop" } }, }); }); it("accepts a minimal valid envelope and rejects a corrupted envelope", () => { expect(GeneratedWSOutboundMessageSchema.safeParse({ type: "pong" }).success).toBe(true); expect(GeneratedWSOutboundMessageSchema.safeParse({ type: "not_a_message" }).success).toBe( false, ); }); it.each([ { name: "dedicated attention message", message: { type: "agent_attention_required", payload: { agentId: "agent-1", reason: "finished", timestamp: "2026-07-22T18:00:00.000Z", shouldNotify: true, notification: { title: "Agent finished", body: "Done", data: { serverId: "server-1", workspaceId: "workspace-1", agentId: "agent-1", reason: "finished", }, }, }, }, }, { name: "agent stream attention event", message: { type: "agent_stream", payload: { agentId: "agent-1", timestamp: "2026-07-22T18:00:00.000Z", event: { type: "attention_required", provider: "codex", reason: "finished", timestamp: "2026-07-22T18:00:00.000Z", shouldNotify: true, notification: { title: "Agent finished", body: "Done", data: { serverId: "server-1", workspaceId: "workspace-1", agentId: "agent-1", reason: "finished", }, }, }, }, }, }, ])("preserves workspaceId in a $name", ({ message }) => { const envelope = { type: "session", message }; expect(GeneratedWSOutboundMessageSchema.safeParse(envelope)).toEqual({ success: true, data: envelope, }); }); it("emits runtime imports with .js extensions", async () => { const generated = await readFile(generatedWSOutboundPath, "utf8"); expect(generated).toContain('from "../../validation/ws-outbound-schema-metadata.js"'); }); it("accepts a forge.search.response envelope", () => { const result = GeneratedWSOutboundMessageSchema.safeParse({ type: "session", message: { type: "forge.search.response", payload: { items: [ { kind: "change_request", number: 17, title: "Fix search", url: "https://gitlab.com/acme/repo/-/merge_requests/17", state: "open", body: null, labels: [], }, ], authState: "authenticated", error: null, requestId: "search-forge", }, }, }); expect(result.success).toBe(true); }); it("accepts a legacy github_search_response envelope", () => { const result = GeneratedWSOutboundMessageSchema.safeParse({ type: "session", message: { type: "github_search_response", payload: { items: [ { kind: "pr", number: 42, title: "Legacy PR", url: "https://github.com/acme/repo/pull/42", state: "open", body: null, labels: [], }, ], featuresEnabled: true, githubFeaturesEnabled: true, authState: "authenticated", error: null, requestId: "search-github", }, }, }); expect(result.success).toBe(true); }); });