import type { CodexThreadSettings } from './codex-service-tier.js'; /** Extract the cliSessionId encoded in a rollout filename. Codex's session * id is UUID-shaped (8-4-4-4-12 hex), which lets us anchor the regex on * the UUID alone — the `` segment between "rollout-" and the sid * contains its own dashes that would otherwise let a greedy match swallow * parts of the sid. Returns undefined for paths that don't match. */ export declare function codexSessionIdFromRolloutPath(path: string): string | undefined; type CodexRolloutRef = { path: string; cliSessionId: string; }; /** Find the rollout file an externally-running Codex process has open. A * single open rollout is authoritative for that pid. Multiple open rollouts * are ambiguous: current Codex versions can keep parent and sibling-agent * transcripts open in the same process, so choosing the first fd can bind * an adopted pane to the wrong conversation. * * 两种平台都用 `codexSessionIdFromRolloutPath` 提取 sid。 */ export declare function findCodexRolloutByPid(pid: number): CodexRolloutRef | undefined; /** Enumerate ALL rollouts a Codex pid currently has open, keyed by lowercased * sessionId. Unlike `findCodexRolloutByPid`, this does NOT collapse the * parent+sibling multi-rollout case to `undefined` — it returns every match so * a caller can test membership (`historySid ∈ set`). * * This is the ownership gate for post-submit rollout re-attach: `history.jsonl` * is a single global file shared by every Codex pane under one CODEX_HOME, so a * concurrent sibling pane submitting identical text can make writeInput return * the WRONG session id. Only a sid this exact pid actually holds open is safe to * re-attach to; a foreign sid (another pane's) is rejected, leaving the current * binding untouched. Returns an empty Set when the pid holds no rollout, and * undefined only when the fd enumeration itself is unavailable — callers must * treat undefined as "cannot prove ownership" (fail closed: do not re-attach). */ export declare function findCodexRolloutSetByPid(pid: number): Set | undefined; /** Pure ownership decision: is `cliSessionId` one of the rollouts the observed * pid holds open? `ownedRollouts` is the lowercased sid set from * findCodexRolloutSetByPid (undefined when fd enumeration was unavailable). * FAIL CLOSED — a missing set or a non-member id returns false so the caller * never binds the bridge to a session it can't prove the pid owns. Extracted so * the exact predicate the worker's attach entry points use is unit-testable * without a live pid. */ export declare function codexHistorySidIsOwned(cliSessionId: string, ownedRollouts: Set | undefined): boolean; export interface CodexBridgeEvent { /** Synthetic uuid for dedup: `:` of the line start. * Stable across re-drains because rollout files are append-only. */ uuid: string; /** Wall-clock ms parsed from the event's `timestamp` field. Falls back * to Date.now() if missing/unparseable so the gate's window math still * has something to compare against. */ timestampMs: number; /** Discriminator for the queue layer: * - 'user' starts a pending Lark turn (fingerprint-matched) * - 'assistant_final' closes the currently-collecting turn with output * - 'turn_aborted' closes it without producing fallback output */ kind: 'user' | 'assistant_final' | 'turn_aborted'; /** Concatenated text from the message's content blocks (input_text for * user, output_text for assistant). */ text: string; /** Optional durable-delivery terminal outcome carried by bridges with an * explicit completion record (for example Grok `turn_completed`). Codex * final-answer records omit it and retain the historical completed * default. */ terminalStatus?: 'completed' | 'failed' | 'ambiguous'; terminalErrorCode?: string; /** Safe, bounded user-facing detail extracted from a structured failure. * Raw provider payloads stay in the rollout/Web terminal. */ terminalErrorSummary?: string; sourceSessionId?: string; /** Keep the pending turn's original markTimeMs instead of moving it to the * transcript user timestamp. Used by bridges whose committed user * timestamp can lag behind in-turn delivery markers. */ preserveMarkTimeMs?: boolean; } export declare const CODEX_RATE_LIMIT_ERROR_CODE = "codex_rate_limited"; export declare const CODEX_AUTH_ERROR_CODE = "codex_auth_failed"; export declare const CODEX_INVALID_REQUEST_ERROR_CODE = "codex_invalid_request"; export declare const CODEX_CONNECTION_ERROR_CODE = "codex_connection_failed"; export declare const CODEX_TASK_FAILED_ERROR_CODE = "codex_task_failed"; /** Bounded, redacted user-facing summary of a structured task_complete error. * Exported for the TRAE drainer, which mirrors the Codex error→failed * terminal mapping on the same payload shape. */ export declare function safeFailureSummary(error: unknown): string | undefined; /** Classify a structured task_complete error into a stable failure code. * Shared with the TRAE drainer (traex-transcript.ts), whose task_complete * error payloads use the same Codex-family shape — keep one classifier so * both bridges map e.g. connection failures to the same code. */ export declare function codexTaskFailureCode(error: unknown): string; export declare function isCodexRateLimitEvent(event: CodexBridgeEvent): boolean; /** Extract the last completed user/assistant turn from a Codex / CoCo bridge * event sequence. Used by /adopt to surface the previous turn as a * preamble card in the Lark thread — gives the user context to continue * from. CoCo events share the same shape (uuid/timestampMs/kind/text), * so this works for both bridges. * * Algorithm: scan tail-first for the most recent `assistant_final`, then * pair it with the most recent `user` event that precedes it. Returns * undefined when either side is missing — typically a fresh session whose * user typed something but the model hasn't replied yet. */ export declare function extractLastCodexTurn(events: readonly { kind: 'user' | 'assistant_final' | 'turn_aborted'; text: string; }[]): { userText: string; assistantText: string; } | undefined; /** Split a drained event list into "history" (older than the live cutoff) * and "live" (cutoff or newer). The Codex adopt bridge uses this when * it discovers the rollout file LATE (after the user already typed in * iTerm or sent a Lark message): drain-from-0 produces a mix of pre- * adopt history and post-adopt live events. The worker then `absorb()`s * the history (so it isn't replayed) and `ingest()`s the live partition * (so the local-turn synthesis / fingerprint match still works). Pure * function — no I/O, easy to test against fixed timestamps. */ export declare function splitCodexEventsByCutoff(events: readonly CodexBridgeEvent[], liveSinceMs: number): { history: CodexBridgeEvent[]; live: CodexBridgeEvent[]; }; export interface CodexDrainResult { events: CodexBridgeEvent[]; /** Byte offset of the last fully-parsed line + its trailing \n. The next * drain should pass this back as fromOffset. */ newOffset: number; /** A line that was written without its terminating \n yet. Currently * informational — only complete lines produce events. */ pendingTail: string; /** Latest complete settings record in this byte range, if any. */ latestThreadSettings?: CodexThreadSettings; /** Newest executor model observed in this byte range (from `turn_context`), * latest-wins. Undefined when no `turn_context` appeared in the range. */ latestModel?: string; /** Newest executor reasoning effort observed in this byte range (from * `turn_context`), latest-wins. Undefined when none appeared. */ latestReasoningEffort?: string; } /** Locate the rollout file for a given Codex sessionId. Codex names files * `rollout--.jsonl`, so a suffix match is unambiguous. The * directory tree is small (year/month/day) — a one-shot recursive scan * is cheap enough that we don't bother caching. */ export declare function findCodexRolloutBySessionId(cliSessionId: string, opts?: { codexHome?: string; noFollow?: boolean; }): string | undefined; /** Find the newest Codex session whose history entry includes a botmux * session id. Fresh dashboard rows often only know botmux's UUID; Codex's * rollout filename uses its own UUID, and history.jsonl is the durable bridge * between the two. Only the trailing `maxTailBytes` of the file is scanned. */ export declare function findCodexSessionIdByBotmuxSessionId(botmuxSessionId: string, opts?: { maxTailBytes?: number; codexHome?: string; noFollow?: boolean; }): string | undefined; /** Increment-read the rollout from `fromOffset`. Mirrors the byte-offset * contract of claude-transcript.drainTranscript so callers can swap them * out and reuse the existing fs.watch / poll wakeup machinery. */ export declare function drainCodexRollout(path: string, fromOffset: number): CodexDrainResult; /** * One-shot bootstrap for an existing rollout. Reads backwards in fixed-size * chunks and stops at the newest settings record, keeping memory bounded even * for long sessions. Live changes use `drainCodexRollout`'s byte offset and do * not call this function. */ export declare function scanCodexThreadSettings(path: string, opts?: { chunkBytes?: number; }): CodexThreadSettings | undefined; /** One-shot bootstrap of the current Codex runtime (model / reasoning effort) * from `turn_context` records, for attach/restore paths that cursor straight * to the tail without draining history. Scans BACKWARD in fixed-size chunks * and stops once both fields resolve — the newest `turn_context` sits near the * tail. A hard byte cap bounds the pathological missing-field case. A * non-newline-terminated trailing partial is excluded via baselineJsonlCursor * so a crash mid-write cannot surface a half-written record. Mirrors * traex-transcript's readLatestTraexRuntime. */ export declare function readLatestCodexRuntime(path: string): { model?: string; reasoningEffort?: string; }; export {}; //# sourceMappingURL=codex-transcript.d.ts.map