/**
 * Session file parsers for Claude, Codex, Gemini, and OpenCode.
 *
 * Each agent stores sessions in a different format (JSONL, JSON, SQLite).
 * This module normalizes all of them into a flat array of SessionEvent
 * objects suitable for rendering, filtering, and summarization.
 */
import type { SessionAgentId, SessionEvent } from './types.js';
/**
 * Largest session file we will load into memory. Above this we throw a clean
 * error instead of OOMing or hitting V8's ERR_STRING_TOO_LONG. Aligns with
 * Node's ~512MB string ceiling with a healthy margin.
 */
export declare const SESSION_FILE_MAX_BYTES = 200000000;
/**
 * Strip terminal control sequences that a malicious session file could use to
 * hijack the user's terminal (clipboard via OSC 52, scrollback wipe, alt-screen
 * takeover, cursor moves, etc.). Allowed through: tab (0x09), newline (0x0a),
 * carriage return (0x0d). Everything else in the C0/C1 range and every CSI/OSC
 * escape is dropped.
 */
export { sanitizeForTerminal } from '../redact.js';
/** In-place sanitize every user-visible string field on a list of events. */
export declare function sanitizeEvents(events: SessionEvent[]): void;
/**
 * Read a session file, refusing files above maxBytes. Bounded read protects
 * against multi-GB session blobs that would OOM the CLI or exceed V8's
 * ERR_STRING_TOO_LONG ceiling.
 */
export declare function safeReadSessionFile(filePath: string, maxBytes?: number): string;
export interface ParseSessionOptions {
    /** Keep normalized tool results compact by default; renderers can request full output. */
    maxToolOutputChars?: number;
    /** Opt-in because interrupts are not user messages and would change the published event stream. */
    includeInterrupts?: boolean;
}
export declare function parseSession(filePath: string, agent?: SessionAgentId, opts?: ParseSessionOptions): SessionEvent[];
/** Infer the agent type from a session file path using known directory conventions. */
export declare function detectAgent(filePath: string): SessionAgentId | null;
/**
 * Checklist-snapshot tool names across harnesses — each sends the WHOLE list on
 * every write, so the last call is the current checklist. Claude `TodoWrite`,
 * Kimi `TodoList`, Droid/OpenCode `todo_write`, Codex `update_plan`.
 */
export declare const SNAPSHOT_TODO_TOOLS: Set<string>;
/**
 * Whether a harness's checklist status means "finished". Claude/Codex write
 * `completed`; Kimi writes `done`.
 */
export declare function isCompletedTodoStatus(status: unknown): boolean;
/**
 * Summarize a tool_use into a one-liner string.
 */
export declare function summarizeToolUse(tool: string, args?: Record<string, any>): string;
/** Parse a Claude JSONL session file into normalized events. */
export declare function parseClaude(filePath: string, opts?: ParseSessionOptions): SessionEvent[];
/**
 * Parse Claude JSONL *content* (already read into a string) into normalized
 * events. Split from `parseClaude` so the tail reader can parse just the last
 * chunk of a file without re-reading the whole thing. Malformed leading lines
 * (a tail that starts mid-line) are skipped by the per-line try/catch below.
 */
export declare function parseClaudeContent(content: string, opts?: ParseSessionOptions): SessionEvent[];
/** Parse a Codex JSONL session file into normalized events. */
export declare function parseCodex(filePath: string): SessionEvent[];
/**
 * Extract target file path(s) from a Codex apply_patch envelope. The patch body
 * opens with `*** Begin Patch` and carries one or more file ops of the form
 * `*** Update File: <path>` / `*** Add File: <path>` / `*** Delete File: <path>`.
 * Returns every path in order (a multi-file patch emits multiple paths so
 * artifact discovery sees each file — RUSH-1410). Empty when unparseable.
 */
export declare function applyPatchTargets(input: string): Array<{
    path: string;
    op: 'Add' | 'Update' | 'Delete';
}>;
export declare function applyPatchTargetPaths(input: string): string[];
/**
 * Parse Codex JSONL *content* (already read into a string) into normalized
 * events. Split from `parseCodex` so the tail reader can parse just the last
 * chunk without re-reading the whole file.
 */
export declare function parseCodexContent(content: string): SessionEvent[];
/** Parse a Gemini JSON session file into normalized events. */
export declare function parseGemini(filePath: string): SessionEvent[];
/**
 * Parse an Antigravity conversation SQLite DB into normalized tool_use events.
 * Deduped by the tool-call id so each tool appears once (Antigravity writes a
 * request step and a completion step that share the id).
 */
export declare function parseAntigravity(dbPath: string): SessionEvent[];
/**
 * Separator between a container file and the id it holds inside a *composite*
 * session `file_path`. Some harnesses keep every session in ONE file (OpenCode's
 * single `opencode.db`), so the index stores `<container>#<session-id>` rather
 * than one path per session — e.g.
 * `/home/u/.local/share/opencode/opencode.db#ses_02410a2c…`.
 */
export declare const SESSION_FILE_PATH_SEP = "#";
/**
 * Split a stored session `file_path` into its on-disk container and the optional
 * in-container fragment. For a plain per-session file the container is the path
 * itself and `fragment` is undefined; for a composite path it is the part before
 * the first `#` and the id after it.
 */
export declare function splitSessionFilePath(filePath: string): {
    container: string;
    fragment: string | undefined;
};
/**
 * The filesystem path whose existence/stat decides whether a session row is
 * stale. For a composite `file_path` this is the CONTAINER file — the row is a
 * record inside it, never a filesystem entry of its own — so a composite session
 * is stale only when its container is gone. For a plain path it is the path
 * itself. Keying off the composite FORM (a `#` fragment), not any harness name,
 * means any future single-file-DB harness inherits the correct behavior.
 */
export declare function sessionFilePathContainer(filePath: string): string;
/**
 * Parse an OpenCode session from its SQLite database.
 * filePath format: "/path/to/opencode.db#session_id"
 *
 * Data model: session -> message -> part
 * Messages have role (user/assistant) and metadata.
 * Parts contain the actual content: text, tool, reasoning, patch, step-start/finish.
 */
/**
 * Parse a Grok (xAI CLI) session into normalized events.
 *
 * A Grok session dir holds several files; the conversation transcript is
 * `chat_history.jsonl`, one JSON object per line with a `type`:
 *   - `system`       — the system prompt (skipped; not conversational)
 *   - `user`         — `content` is an array of `{ type: 'text', text }` blocks
 *   - `assistant`    — `content` is a string, plus a `tool_calls[]` array of
 *                      `{ id, name, arguments }` (arguments is a JSON string)
 *   - `reasoning`    — chain-of-thought; text (when present) lives in `summary`
 *   - `tool_result`  — `{ tool_call_id, content }`, correlated back to the call
 *
 * The scanner records `summary.json` as the session's filePath (see
 * `readGrokMeta` in discover.ts), so resolve `chat_history.jsonl` from the same
 * dir; also accept being handed the transcript file directly. Per-line
 * timestamps aren't stored, so every event carries the session's `created_at`
 * (from summary.json), falling back to the transcript's mtime.
 */
export declare function parseGrok(filePath: string): SessionEvent[];
/**
 * The transcript query {@link parseOpenCode} runs, exported so a test can assert
 * the projection's real cost against a database instead of re-typing the SQL.
 *
 * A tool part is PROJECTED to exactly the fields the `case 'tool'` branch below
 * reads — `tool`, `callID`, `state.status`, `state.input`, `state.output` —
 * rather than carried whole. Two things this has to get right at once:
 *
 *   - Keep `state.input`. It carries `filePath` / `command`, and losing it is
 *     what left `recentDirectoriesTouched` empty (RUSH-2358).
 *   - Stay bounded. A tool part is not bounded by its output: on a real
 *     `opencode.db` the largest part is 1,346,068 bytes of which
 *     `state.attachments` (a base64 data URL from `read`) is 1,345,674, while
 *     `state.output` is 23. Truncating only `state.output` therefore bounded
 *     nothing — it took one session's loaded tool payload from 299,365 to
 *     1,911,209 bytes. The projection drops `attachments` (and every other
 *     unread key) outright, caps `state.output`, and collapses an oversized
 *     `state.input` to just its addressing fields. Those are the keys the
 *     enrichment reads — `filePath`/`path` for an edit and `cwd`/`workdir`/
 *     `working_directory` for a shell (`extractRecentDirectoriesTouched` in
 *     state.ts), plus `command`/`description`, themselves capped since a command
 *     can be arbitrarily long. Above the cap every other input key (an `edit`'s
 *     `oldString`/`newString`) is gone, deliberately — nothing downstream reads
 *     them, and they are the weight.
 *
 * `json_valid` guards every `json_extract`: SQLite raises "malformed JSON" on a
 * non-JSON value, which aborts the WHOLE query, so one bad `part` row would
 * otherwise cost the entire transcript. Note the single-argument form is
 * RFC-8259-strict — it rejects a JSONB blob that `json_extract` would accept.
 * That is correct for today's schema (`part.data` / `message.data` are TEXT on
 * a real database); if OpenCode ever migrates them to JSONB, these guards must
 * move to `json_valid(data, 6)` or they will drop every row.
 *
 * The session id is bound as a parameter; the two caps are numeric literals.
 */
export declare const OPENCODE_TRANSCRIPT_QUERY: string;
export declare function parseOpenCode(filePath: string): SessionEvent[];
/** Parse a Rush JSONL session file into normalized events. */
export declare function parseRush(filePath: string): SessionEvent[];
/**
 * Muse Code session.jsonl → normalized events.
 *
 * Muse records an append-only event log. We map:
 *   - runtime.command_intake.received / turn_submit → user message
 *   - assistant_message_committed → assistant message
 *   - model_completed.usage → usage
 *   - tool-related events when present
 */
export declare function parseMuse(filePath: string): SessionEvent[];
/** Parse a Hermes session JSON file into normalized events. */
export declare function parseHermes(filePath: string): SessionEvent[];
/** Parse a Kimi session state.json file by reading its agents/main/wire.jsonl. */
export declare function parseKimi(filePath: string): SessionEvent[];
/** Parse Cursor's Anthropic-shaped message JSONL transcript. */
export declare function parseCursor(filePath: string): SessionEvent[];
/**
 * Parse a Droid (Factory) JSONL session file into normalized events. Droid
 * wraps each turn in a `{type:'message', message:{role, content, modelId}}`
 * envelope; the content blocks are Anthropic-shaped (text/thinking/tool_use/
 * tool_result), so block handling mirrors the Claude parser.
 */
export declare function parseDroid(filePath: string): SessionEvent[];
