import { z } from "zod"; // === Enums === export const EventType = z.enum([ "step.start", "step.complete", "decision", "agent.dispatch", "agent.result", "artifact.create", "validation", "error", "note", ]); export const StepStatus = z.enum(["pass", "fail", "blocked"]); export const ArtifactType = z.enum(["doc", "code", "config", "report", "seed", "asset"]); export const ArtifactOperation = z.enum(["create", "update", "delete"]); // === Conversation === export const ConversationMessage = z.object({ role: z.enum(["user", "agent"]), message: z.string(), }); // === Git context (auto-captured by CLI) === export const GitContext = z.object({ branch: z.string(), commit: z.string(), }); // === Event data payloads === export const StepStartData = z.object({ skill: z.string(), context: z.record(z.string(), z.unknown()), }); export const StepCompleteData = z.object({ status: StepStatus, summary: z.string(), artifacts: z.array(z.string()), }); export const DecisionData = z.object({ question: z.string(), choice: z.string(), alternatives: z.array(z.string()), rationale: z.string(), }); export const AgentDispatchData = z.object({ agentName: z.string(), task: z.string(), inputs: z.record(z.string(), z.unknown()), }); export const AgentResultData = z.object({ agentName: z.string(), status: z.enum(["pass", "fail"]), outputs: z.record(z.string(), z.unknown()), duration_ms: z.number(), }); export const ArtifactCreateData = z.object({ path: z.string(), type: ArtifactType, operation: ArtifactOperation, }); export const ValidationData = z.object({ command: z.string(), status: z.enum(["pass", "fail"]), issues: z.array(z.string()), }); export const ErrorData = z.object({ message: z.string(), recoverable: z.boolean(), }); export const NoteData = z.object({ message: z.string(), tags: z.array(z.string()), }); // === Flattened entry schemas === // Each variant is a complete object (no .and() intersection) // to avoid Zod 4 issues with union + intersection. // // conversation field is recreated per schema to avoid sharing a .default() // schema instance across multiple union members (Zod 4 limitation). const convField = () => z.array(ConversationMessage).default([]); // --- Entry schemas (stored in JSONL) --- export const StepStartEntry = z.object({ v: z.literal(1), timestamp: z.iso.datetime(), sessionId: z.string(), prompt: z.string(), git: GitContext, conversation: convField(), event: z.literal("step.start"), data: StepStartData, }); export const StepCompleteEntry = z.object({ v: z.literal(1), timestamp: z.iso.datetime(), sessionId: z.string(), prompt: z.string(), git: GitContext, conversation: convField(), event: z.literal("step.complete"), data: StepCompleteData, }); export const DecisionEntry = z.object({ v: z.literal(1), timestamp: z.iso.datetime(), sessionId: z.string(), prompt: z.string(), git: GitContext, conversation: convField(), event: z.literal("decision"), data: DecisionData, }); export const AgentDispatchEntry = z.object({ v: z.literal(1), timestamp: z.iso.datetime(), sessionId: z.string(), prompt: z.string(), git: GitContext, conversation: convField(), event: z.literal("agent.dispatch"), data: AgentDispatchData, }); export const AgentResultEntry = z.object({ v: z.literal(1), timestamp: z.iso.datetime(), sessionId: z.string(), prompt: z.string(), git: GitContext, conversation: convField(), event: z.literal("agent.result"), data: AgentResultData, }); export const ArtifactCreateEntry = z.object({ v: z.literal(1), timestamp: z.iso.datetime(), sessionId: z.string(), prompt: z.string(), git: GitContext, conversation: convField(), event: z.literal("artifact.create"), data: ArtifactCreateData, }); export const ValidationEntry = z.object({ v: z.literal(1), timestamp: z.iso.datetime(), sessionId: z.string(), prompt: z.string(), git: GitContext, conversation: convField(), event: z.literal("validation"), data: ValidationData, }); export const ErrorEntry = z.object({ v: z.literal(1), timestamp: z.iso.datetime(), sessionId: z.string(), prompt: z.string(), git: GitContext, conversation: convField(), event: z.literal("error"), data: ErrorData, }); export const NoteEntry = z.object({ v: z.literal(1), timestamp: z.iso.datetime(), sessionId: z.string(), prompt: z.string(), git: GitContext, conversation: convField(), event: z.literal("note"), data: NoteData, }); // z.union auto-detects the "event" discriminator in Zod 4 export const ProgressEntry = z.union([ StepStartEntry, StepCompleteEntry, DecisionEntry, AgentDispatchEntry, AgentResultEntry, ArtifactCreateEntry, ValidationEntry, ErrorEntry, NoteEntry, ]); // --- Input schemas (what skills pass to CLI, no timestamp/git) --- export const StepStartInput = z.object({ v: z.literal(1), sessionId: z.string(), prompt: z.string(), conversation: convField(), event: z.literal("step.start"), data: StepStartData, }); export const StepCompleteInput = z.object({ v: z.literal(1), sessionId: z.string(), prompt: z.string(), conversation: convField(), event: z.literal("step.complete"), data: StepCompleteData, }); export const DecisionInput = z.object({ v: z.literal(1), sessionId: z.string(), prompt: z.string(), conversation: convField(), event: z.literal("decision"), data: DecisionData, }); export const AgentDispatchInput = z.object({ v: z.literal(1), sessionId: z.string(), prompt: z.string(), conversation: convField(), event: z.literal("agent.dispatch"), data: AgentDispatchData, }); export const AgentResultInput = z.object({ v: z.literal(1), sessionId: z.string(), prompt: z.string(), conversation: convField(), event: z.literal("agent.result"), data: AgentResultData, }); export const ArtifactCreateInput = z.object({ v: z.literal(1), sessionId: z.string(), prompt: z.string(), conversation: convField(), event: z.literal("artifact.create"), data: ArtifactCreateData, }); export const ValidationInput = z.object({ v: z.literal(1), sessionId: z.string(), prompt: z.string(), conversation: convField(), event: z.literal("validation"), data: ValidationData, }); export const ErrorInput = z.object({ v: z.literal(1), sessionId: z.string(), prompt: z.string(), conversation: convField(), event: z.literal("error"), data: ErrorData, }); export const NoteInput = z.object({ v: z.literal(1), sessionId: z.string(), prompt: z.string(), conversation: convField(), event: z.literal("note"), data: NoteData, }); export const ProgressInput = z.union([ StepStartInput, StepCompleteInput, DecisionInput, AgentDispatchInput, AgentResultInput, ArtifactCreateInput, ValidationInput, ErrorInput, NoteInput, ]); export const InputSchemaMap: Record = { "step.start": StepStartInput, "step.complete": StepCompleteInput, decision: DecisionInput, "agent.dispatch": AgentDispatchInput, "agent.result": AgentResultInput, "artifact.create": ArtifactCreateInput, validation: ValidationInput, error: ErrorInput, note: NoteInput, }; // === Inferred types === export type EventType = z.infer; export type ConversationMessage = z.infer; export type GitContext = z.infer; export type ProgressEntry = z.infer; export type ProgressInput = z.infer;