/** * transcript-reader.ts * * Reads Claude Code session transcripts (.jsonl files) from disk. * Uses head+tail strategy so it handles 100MB+ files without loading them fully. * * Discovery order: * 1. File paths in tool calls → project slug (most reliable) * 2. First real user message → task description * 3. Recent tail exchanges → what was accomplished */ export interface SessionInfo { /** Absolute path to the .jsonl file */ file: string; /** UUID from the filename */ sessionId: string; /** File size in MB */ sizeMb: number; /** Last write time */ lastModified: Date; /** Best-guess project slug from file path patterns (e.g. "cdance-eu") */ projectGuess: string | null; /** cwd field from first record (usually just home dir) */ cwdGuess: string | null; /** First non-system user message (<300 chars) */ firstUserMessage: string | null; /** Last N user+assistant exchanges formatted as text, for agent summarization */ recentExchanges: string; } /** A candidate project slug with its combined signal count. */ export interface ProjectCandidate { slug: string; count: number; } export interface ResolvedSessionProject { /** The resolved slug, an existing/gated new slug, or "auto" when nothing qualifies. */ slug: string; /** top_count / total_candidate_counts across all signals; 0 when slug === "auto". */ confidence: number; /** Every candidate seen, merged across signals, ranked by count desc — kept * even when not selected, so a low-confidence resolution is re-fileable * later (recorded verbatim in the session card, F3). */ candidates: ProjectCandidate[]; } /** * Unified, claim-not-generate project namer (F1). * * Merges the cwd signal (Signal 1) and the boilerplate-excluded content scan * (Signal 2), then resolves under a claim-not-generate policy (Signal 3): * - Scan merged candidates in rank order; the first one that already has an * on-disk project directory wins outright ("prefer an existing slug"). * - Otherwise, the single top-ranked candidate may mint a BRAND-NEW slug * only if it clears both bars: content-signal count >= 3 (a real project * is mentioned in actual dialogue repeatedly, not once via noise) AND a * matching `~/Projects/` directory exists on disk. * - Otherwise: "auto" (confidence 0) — never invent a slug from a single * weak hit. * Every candidate slug is validated against `isValidProjectSlug` before it * can be selected (no deny-list bypass) — invalid candidates are skipped, * never selected, though they remain visible in `candidates` for transparency. */ export declare function resolveSessionProject(headText: string, tailText: string): ResolvedSessionProject; /** A parsed session plus its verbatim head+tail bytes (the lossless dump). */ export interface TranscriptByPath extends SessionInfo { /** head + "\n…\n" + tail of the transcript, capped at ~80KB. */ rawTail: string; /** * Wave-2 wiring (continuity wave 2026-07-31): the raw head sample (default * readHeadTail() sizing, same as the one already used internally for * cwdGuess/firstUserMessage/projectGuess above) — exposed so callers can * feed F1's `resolveSessionProject(headText, tailText)` at the hook-end * call site without a second file read. Additive field; existing * consumers are unaffected. */ headText: string; /** Companion tail sample to `headText` (default readHeadTail() sizing). */ tailText: string; } /** * Wave 2: parse a SINGLE transcript by its absolute path (from the Stop hook's * `transcript_path`), reusing the same head/tail reader as readTodaySessions — * no second reader for the SessionInfo fields below. Returns the parsed * SessionInfo PLUS a verbatim `rawTail` for the lossless archive tier. * Returns null if the path is missing/unreadable. */ export declare function readTranscriptByPath(filePath: string): TranscriptByPath | null; /** * Locate and parse all Claude Code sessions modified today. * * @param claudeDir Directory containing the .jsonl files. * Defaults to ~/.claude/projects/-Users-{username} */ export declare function readTodaySessions(claudeDir?: string): SessionInfo[]; //# sourceMappingURL=transcript-reader.d.ts.map