/**
 * WebSocket wire protocol types shared between the spectral local server and
 * the (future) browser client in `landing/`.
 *
 * Keep this file dependency-free. It will be copied or imported by the
 * frontend in Day 3, so we don't want it to drag in `better-sqlite3`,
 * `ws`, or any spectral SDK types.
 *
 * Naming: client → server messages are `ClientMessage`, server → client
 * frames are `ServerEvent`. JSON-encoded one-per-frame on the wire.
 */
/** Base64-encoded image attached to a user message. */
export interface ImageAttachment {
    /** Raw base64 image data (no data URI prefix). */
    data: string;
    /** MIME type, e.g. "image/jpeg" or "image/png". */
    mimeType: string;
    /** Compressed width in pixels (optional). */
    width?: number;
    /** Compressed height in pixels (optional). */
    height?: number;
}
/** Persisted message row as returned to the browser. */
export interface WireMessage {
    id: string;
    role: "user" | "assistant" | "system";
    content: string;
    /** Newline-delimited JSON of agent events captured for this message (assistant only, may be ""). */
    events: string;
    createdAt: number;
    /** Base64 images attached to user messages (empty for assistant/system). */
    images?: ImageAttachment[];
}
/**
 * Project — a user-declared root directory that owns 0..N sessions.
 *
 * spectral runs with `cwd = project.path`, so the project is the unit of "where on
 * disk this conversation operates". Sessions are scoped to a project; the
 * sidebar is a 2-tier projects → sessions view.
 */
export interface WireProject {
    id: string;
    name: string;
    /** Absolute filesystem path. Server-side validated on create. */
    path: string;
    createdAt: number;
    updatedAt: number;
    /** Number of sessions currently associated with this project. */
    sessionCount: number;
    /** Studio project ID when the project is bound to Aexol Studio (from `.aexol/aexol.jsonc`). */
    studioProjectId?: string;
    /** Studio project display name when bound. Falls back to projectId if name is not set. */
    studioProjectName?: string;
    /** True when at least one of this project's sessions has an in-flight turn. */
    hasActiveSession?: boolean;
}
/** Session row (list view — no messages). */
export interface WireSessionSummary {
    id: string;
    /** Owning project. Always set — sessions cannot exist without a project. */
    projectId: string;
    title: string;
    createdAt: number;
    updatedAt: number;
    messageCount: number;
    /** True when this session currently has an in-flight assistant turn. */
    hasActiveTurn?: boolean;
}
/** Session row with messages (detail view). */
export interface WireSessionDetail {
    id: string;
    /** Owning project. Mirrors WireSessionSummary; included so the client can
     *  recover the project context from a deep link without an extra fetch. */
    projectId: string;
    title: string;
    createdAt: number;
    updatedAt: number;
    messages: WireMessage[];
    /** True when this session was created via "Fork & Compact" and has not yet
     *  had its first compaction. The UI uses this to show a special send button
     *  for the first message. */
    forkCompactPending?: boolean;
}
export interface WireSessionMemoryStatus {
    mode: "active" | "passive";
    phase: "idle" | "observing" | "compacting" | "reflecting" | "pruning";
    inFlight: {
        observer: boolean;
        compaction: boolean;
        reflection: boolean;
        pruner: boolean;
    };
    reflections: {
        count: number;
        tokens: number;
    };
    observations: {
        committedCount: number;
        committedTokens: number;
        pendingCount: number;
        pendingTokens: number;
    };
    thresholds: {
        observation: number;
        compaction: number;
        reflection: number;
    };
    progress: {
        sinceObservationBoundTokens: number;
        sinceLastCompactionTokens: number;
        observationPoolTokens: number;
    };
}
export interface WireObservationItem {
    id: string;
    content: string;
    timestamp: string;
    relevance: "low" | "medium" | "high" | "critical";
    /** Whether this observation is pending (not yet covered by a compaction snapshot). */
    pending: boolean;
}
export interface WireReflectionItem {
    id: string;
    content: string;
    /** IDs of observations that support this reflection. May be empty for legacy reflections. */
    supportingObservationIds: string[];
}
export interface WireSessionMemoryDetails {
    summary: string | null;
    observations: WireObservationItem[];
    reflections: WireReflectionItem[];
}
export type ClientMessage = {
    type: "user_message";
    content: string;
    /** Enable autonomous iterative loop for this message (Ralph Wiggum pattern). */
    loop?: boolean;
    /** Optional base64-encoded images attached to the message. */
    images?: ImageAttachment[];
};
/**
 * Subset of `ServerEvent` that's safe to buffer per turn and replay on
 * reconnect. Excludes framing/lifecycle events (`session_ready`, `agent_end`)
 * that are emitted at the session level rather than within a turn.
 *
 * NOTE: `message_start` IS included because the client uses it to flip into
 * "streaming" status during replay, matching live behavior.
 */
export type ReplayableTurnEvent = Extract<ServerEvent, {
    type: "message_start" | "text_delta" | "thinking_delta" | "tool_call" | "tool_result" | "message_end" | "token_usage" | "error";
}>;
/**
 * Snapshot of an in-flight assistant turn — the buffered event log plus
 * metadata. Sent inside `session_ready.currentTurn` so a reconnecting client
 * can rebuild the timeline up to the present moment.
 */
export interface InProgressTurnSnapshot {
    turnId: string;
    startedAt: number;
    events: ReplayableTurnEvent[];
}
export type ServerEvent = {
    type: "session_ready";
    sessionId: string;
    history: WireMessage[];
    /**
     * If a turn is in flight when this WS attached, the buffered events
     * for that turn so the client can rebuild it. `null`/absent when no
     * turn is active. Additive: older clients ignoring this field still
     * see consistent history.
     */
    currentTurn?: InProgressTurnSnapshot | null;
    /** True when this session was created via "Fork & Compact" and is
     *  awaiting its first compaction. The UI uses this to show a special
     *  send button for the first message. */
    forkCompactPending?: boolean;
    /** Cumulative context tokens used across the session (from spectral's getContextUsage()). Null when unknown. */
    contextWindowUsed: number | null;
    /** Model's total context window in tokens. Null when model metadata is not yet available. */
    contextWindowMax: number | null;
} | {
    /**
     * Broadcast right after a user message is persisted to SQLite. ALL
     * subscribers receive this — including the tab that originated the
     * `user_message`. The client de-duplicates by `message.id` (which is
     * generated server-side at persistence time and is the source of
     * truth). Allows multi-tab live sync to show the user's prompt in
     * every tab without local optimistic appends.
     */
    type: "user_message_appended";
    message: WireMessage;
} | {
    type: "message_start";
    messageId: string;
    role: "assistant";
} | {
    type: "text_delta";
    messageId: string;
    delta: string;
} | {
    type: "thinking_delta";
    messageId: string;
    delta: string;
} | {
    type: "tool_call";
    messageId: string;
    id: string;
    name: string;
    args: unknown;
} | {
    type: "tool_result";
    messageId: string;
    id: string;
    result: unknown;
    isError?: boolean;
} | {
    type: "message_end";
    messageId: string;
} | {
    type: "agent_end";
} | {
    /**
     * Broadcast to ALL subscribers of a session when the server changes the
     * session's title — currently only fired by the server-side auto-titler
     * after the first assistant turn completes. Manual user renames take a
     * different code path (PATCH /api/sessions/:id) and the sidebar
     * already updates locally for those.
     *
     * Clients should treat this as authoritative and reflect the new title
     * everywhere it appears (sidebar list, browser tab title, etc.).
     */
    type: "session_renamed";
    sessionId: string;
    title: string;
} | {
    type: "error";
    message: string;
} | {
    /** Emitted at the start of each loop iteration. */
    type: "loop_iteration";
    iteration: number;
    maxIterations: number;
    prompt: string;
} | {
    /** Emitted when the agent signals completion via <LOOP_DONE> marker. */
    type: "loop_complete";
    iterations: number;
} | {
    /** Emitted when the loop hits the safety iteration limit. */
    type: "loop_max_iterations";
    iterations: number;
} | {
    /**
     * Emitted once per assistant message, right after `message_end`.
     * Carries token counts and estimated usage for the just-completed
     * assistant turn.
     */
    type: "token_usage";
    messageId: string;
    usage: {
        inputTokens: number;
        outputTokens: number;
        cacheReadTokens: number;
        cacheWriteTokens: number;
        totalTokens: number;
        /** @deprecated Legacy USD estimate kept for wire compatibility. */
        cost: number | null;
        /** Estimated Aexol credits used for this message. */
        creditsUsed: number;
    };
    /** Cumulative context tokens used across the session (from spectral's getContextUsage()). Null if unknown. */
    contextWindowUsed: number | null;
    /** Model's total context window in tokens. Null if model metadata is not available. */
    contextWindowMax: number | null;
} | {
    /**
     * Emitted when spectral starts context compaction (manual or auto).
     * Non-replayable session lifecycle event; the client can use this
     * to show a "Compacting context…" indicator.
     */
    type: "compaction_start";
    /** Why compaction was triggered. */
    reason: "manual" | "threshold" | "overflow";
} | {
    /**
     * Emitted when spectral completes context compaction. The session has
     * been reloaded with the compacted context; subsequent prompts
     * will see the reduced context window footprint.
     */
    type: "compaction_end";
    /** Summary text generated by the compaction LLM call. */
    summary: string;
    /** Token count before compaction. */
    tokensBefore: number;
    /** UUID of the first branch entry kept after compaction (spectral's cut point). */
    firstKeptEntryId?: string;
    /** True when compaction was aborted (e.g. by a new user message or manual abort). */
    aborted?: boolean;
} | {
    /**
     * Emitted by extensions (e.g. observational memory) to surface
     * informational status updates in the browser UI. Not part of the
     * turn timeline — purely a transient notification.
     */
    type: "agent_notification";
    /** Human-readable message. */
    message: string;
    /** Severity level. */
    level: "info" | "warning" | "error";
    /**
     * Subsystem that emitted the notification. Allows the UI to show
     * targeted indicators (e.g. "Memory · observing").
     */
    system?: "memory_observer" | "memory_compaction" | "memory_reflection" | "memory_pruner" | "extension" | "vision";
} | {
    /**
     * Emitted when auto-research starts for a project. The UI can show
     * a progress indicator with the project name.
     */
    type: "auto_research_start";
    projectId: string;
} | {
    /**
     * Emitted periodically while auto-research is running. The `phase`
     * field allows the UI to show granular status:
     *   - "context_collecting" — reading project files and git state
     *   - "context_analyzing" — LLM analyzing the collected context
     *   - "extension_generating" — writing .ts extension files
     *   - "extension_validating" — validating generated extensions
     */
    type: "auto_research_progress";
    projectId: string;
    phase: "context_collecting" | "context_analyzing" | "extension_generating" | "extension_validating";
    message: string;
} | {
    /**
     * Emitted when auto-research completes successfully. Contains the
     * list of generated extensions with their names, paths, and brief
     * descriptions. The UI can show a summary and offer to enable them.
     */
    type: "auto_research_complete";
    projectId: string;
    extensions: Array<{
        name: string;
        path: string;
        description: string;
        /** True if the extension uses LLM inference (Phase 5+). */
        usesLLM?: boolean;
        /** File count for multi-file extensions. */
        fileCount?: number;
    }>;
    /** True if AGENTS.md was updated with an auto-research section. */
    agentsMdUpdated?: boolean;
} | {
    /** Emitted when auto-research encounters an error. */
    type: "auto_research_error";
    projectId: string;
    message: string;
} | {
    /**
     * Emitted when a subagent tool invocation begins. The UI can show a
     * dedicated expandable panel with agent name, task description, and
     * a loading indicator. Parallel mode will show multiple cards.
     */
    type: "subagent_start";
    /** Tool call ID so the frontend can correlate with tool_call/tool_result. */
    toolCallId: string;
    mode: "single" | "parallel" | "chain";
    /** Single-mode: the agent name. */
    agent?: string;
    /** Single-mode: the task description. */
    task?: string;
    /** Parallel/chain mode: total task count. */
    taskCount?: number;
    /** Chain mode: total steps. */
    totalSteps?: number;
} | {
    /**
     * Emitted periodically during parallel/chain subagent execution.
     * Carries a status message and completion counts so the UI can
     * show live progress (e.g. "2/5 tasks done, 3 running").
     */
    type: "subagent_progress";
    toolCallId: string;
    mode: "single" | "parallel" | "chain";
    completedCount?: number;
    totalCount?: number;
    currentStep?: number;
    currentAgent?: string;
    message: string;
    /** Streaming text accumulated so far (single mode). Updated on text_delta. */
    streamingText?: string;
} | {
    /**
     * Emitted when a subagent tool invocation completes (all subagents
     * finished). Carries structured results with usage stats so the
     * frontend can render rich expandable panels with per-agent output,
     * token counts, and model info.
     */
    type: "subagent_end";
    toolCallId: string;
    mode: "single" | "parallel" | "chain";
    results: Array<{
        agent: string;
        agentSource: "user" | "project" | "unknown";
        task: string;
        exitCode: number;
        /** Final output text from the subagent. */
        output: string;
        model?: string;
        errorMessage?: string;
        stopReason?: string;
        /** Chain mode: step number (1-indexed). */
        step?: number;
        usage: {
            inputTokens: number;
            outputTokens: number;
            cacheReadTokens: number;
            cacheWriteTokens: number;
            cost: number;
            turns: number;
        };
    }>;
    /** Aggregate usage across all subagents in this invocation. */
    totalUsage: {
        inputTokens: number;
        outputTokens: number;
        cacheReadTokens: number;
        cacheWriteTokens: number;
        cost: number;
        turns: number;
    };
} | {
    /**
     * Broadcast when the prompt queue for this session changes
     * (enqueue, remove, clear, auto-dequeue). Carries the full
     * current queue state so clients can replace their local state
     * atomically.
     */
    type: "queue_changed";
    queue: Array<{
        id: string;
        content: string;
        position: number;
        createdAt: string;
    }>;
};
//# sourceMappingURL=wire.d.ts.map