/** * Capture actionable items from conversation text. * * Uses heuristic pattern matching (no LLM) to extract: * - Decisions ("we decided", "let's do", "going with") * - Specs / requirements (bullet lists after spec/feature/plan headings) * - Rules / constraints ("never", "always", "the rule is", "must") * - Errors / gotchas ("error:", "bug:", "gotcha:", "watch out") * - Preferences ("prefer", "use X instead of Y", "don't use") */ export interface ExtractedItem { content: string; category: string; tags: string[]; } /** * Main extraction function. Scans text for actionable items using heuristics. */ export declare function extractFromText(text: string): ExtractedItem[]; export interface CaptureOptions { source: 'stdin' | 'file' | 'last-session'; filePath?: string; /** * Explicit transcript path for `--last-session`. When not set, we fall back * to reading a JSON payload from stdin (the shape Claude Code / OpenCode * SessionEnd hooks pass) and then to auto-discovery under * `~/.claude/projects/`. */ transcriptPath?: string; /** * Tee stdout/stderr to this log file while capture runs. Mirrors the * pattern used by `hippo sleep --log-file` so the SessionEnd hook output * (invisible during TUI teardown) can be surfaced via `hippo last-sleep` * on the next session start. Appends rather than truncates — `hippo sleep` * writes the same file first in the SessionEnd sequence. */ logFile?: string; dryRun: boolean; global: boolean; /** * L9: tenant scope for the dedup read in `cmdCaptureCore`. When provided * AND `global` is false, the dedup check only considers this tenant's * existing memories. Undefined preserves pre-1.12.1 host-wide dedup * behaviour. Ignored when `global: true` (global captures are host-wide). */ tenantId?: string; } /** * Build a compact text summary from a Claude Code / OpenCode JSONL transcript. * Keeps plain user messages and the final chunk of assistant text, drops * thinking blocks, tool_use, and tool_result noise. Output is fed to the * existing `extractFromText` pipeline. * * Exported for tests. */ export declare function summariseTranscript(jsonl: string): string; /** * Resolve a transcript path for `--last-session`. * * Priority: * 1. Explicit `transcriptPath` option (from `--transcript `) * 2. Stdin JSON payload (Claude Code / OpenCode SessionEnd hook shape) * 3. Most recent `.jsonl` under `~/.claude/projects//` * * Returns null when nothing resolves. Never throws. */ export declare function resolveLastSessionTranscript(explicit: string | undefined, stdinText: string | undefined): string | null; export declare function cmdCapture(hippoRoot: string, options: CaptureOptions): void; /** Never read the whole transcript — PreCompact fires exactly when it's largest. */ export declare const PRE_COMPACT_TAIL_BYTES: number; export declare const PRE_COMPACT_TASK_CAP = 200; export declare const PRE_COMPACT_SUMMARY_CAP = 2000; export declare const PRE_COMPACT_NEXT_STEP_CAP = 500; /** * Truncate `text` to at most `maxChars` UTF-16 code units without splitting * a surrogate pair at the boundary. A plain `slice(0, n)` can land between a * high and low surrogate, leaving an unpaired surrogate in a stored/ * re-injected snapshot field. If the code unit at the cut point is a high * surrogate (0xD800-0xDBFF), back off one unit so the pair stays whole. */ export declare function truncateCodePointSafe(text: string, maxChars: number): string; /** * Cap from the RECENT end: summariseTranscript emits user turns oldest-to- * newest with assistant responses after them, so a head-first cap keeps * stale context and drops exactly the newest working state this feature * exists to preserve. Keep the LAST maxChars instead, aligned forward to a * nearby line start, with a trim marker (codex round 3). */ export declare function truncateKeepNewest(text: string, maxChars: number): string; /** * Positional read of the last `capBytes` of `transcriptPath`, aligned * forward to the first complete JSONL line. Uses fs.openSync/readSync at a * byte offset rather than reading the whole file and slicing — PreCompact * fires exactly when transcripts are largest, so a whole-file read is the * one thing this path cannot do. * * Boundary handling (X14): a seek that lands mid-line must drop that * partial first line so every remaining line parses as complete JSON. A * seek that lands exactly after a '\n' already starts on a complete line * and must NOT drop it — doing so would silently discard one whole line on * every tail read whose start offset happens to align with a line break. * Distinguished by peeking at the single byte immediately before `start`. */ export declare function readTranscriptTail(transcriptPath: string, capBytes?: number): string; /** * Log-forgery guard: messages here interpolate payload-controlled values * (transcript paths, session ids). Strip C0 control chars — newlines above * all — so a crafted value can't inject fake `[hippo] ...` log lines. * Exported for every `[hippo]`-prefixed log writer that interpolates * payload-controlled values (cli.ts appendSessionEndCloseLog) — one shared * guard, not per-file copies. */ export declare function sanitizeLogMessage(message: string): string; export interface PreCompactOptions { stdinText?: string; logFile?: string; } /** * PreCompact hook entry point. Exit code 2 on PreCompact BLOCKS compaction, * so this verb must exit 0 on every path — malformed stdin, missing * transcript, and store errors all degrade to a logged no-op rather than a * thrown error. Callers (src/cli.ts) must not wrap this in anything that * could turn a caught-and-logged failure back into a non-zero exit. */ export declare function cmdPreCompact(hippoRoot: string, options: PreCompactOptions): Promise; //# sourceMappingURL=capture.d.ts.map