sidekick-shared 0.27.1 → 0.27.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,26 @@ All notable changes to sidekick-shared will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.27.2] - 2026-09-22
9
+
10
+ ### Fixed
11
+
12
+ - `collectPromptHistory()` streams session files instead of reading each unread range into one buffer. A file whose unread part exceeded `maxFileBytes` used to be skipped on every call; now it is read in 1 MiB chunks up to `maxFileBytes` per call, stops after a complete line, keeps what it returned, and continues on the next call (cursor `backlog: true`), even if its size and mtime are unchanged. Memory stays near one chunk plus one record. Deadline, abort, `maxSessions`, `maxTotalBytes`, and the new `maxEntries` stop at the last complete line the same way instead of discarding the partly read file. The first file of a call always finishes its first record, so a record larger than the budget cannot stall. Lines split only at `\n`, so UTF-8 characters across chunk edges decode exactly; half-written final lines and bytes appended during a call wait for the next call.
13
+ - Late answer metadata no longer depends on a replay window. `pending` now keeps `lineBytes`, `timestamp`, and `answer: { status, id?, model?, usage? }` (answer state, never text), the scan continues from the file's offset however far the answer is, and only the prompt's own line is re-read (and verified against its length and timestamp) when the prompt must be returned again. Replays that 0.27.1 dropped for exceeding `maxFileBytes` no longer happen.
14
+
15
+ ### Added
16
+
17
+ - Bounds `maxRecordBytes` (default 16 MiB; a longer record is skipped as it streams past, without buffering, even across calls while it is still being written) and `maxEntries` (default 10 000), and bound name `'maxEntries'`.
18
+ - `PromptHistoryResult.hasMore` (a bound left bytes or files unread) and `exclusions: PromptHistoryExclusion[]` (`{ provider, sessionId, reason: 'oversizedRecord' | 'malformedRecord', offset }`, up to 1000 per call). These are the only permanent exclusions; a prompt inside such a record is lost and consumes no ordinal.
19
+ - Stats `sessionsWithBacklog`, `sessionsRewritten`, `recordsOverSizeLimit`, and `recordsMalformed`; types `PromptHistoryAnswerState` and `PromptHistoryExclusion`.
20
+ - Rewrite detection: a file that shrank below its offset, whose first 4 KiB digest (`head`) changed, whose resume point no longer follows a newline, or whose pending prompt line no longer matches is read again from the start with fresh ordinals.
21
+
22
+ ### Changed
23
+
24
+ - The cursor is `version: 3`: sessions gain optional `backlog`, `skipping`, and `head`; `pending` gains `lineBytes`, `timestamp`, and `answer`; the cursor gains `next`, the key of the file a call-wide stop left off at, where the next call starts. Version 1 and 2 cursors are accepted: each file is re-verified once, and a version 2 `pending` prompt is replayed from its line in resumable passes. Files 0.27.1 skipped for size were never in its cursor and are read in full; metadata 0.27.1 already abandoned is not recoverable. A session carried unchanged from an older cursor and not visited keeps its old shape (for example `pending` without `answer`).
25
+ - `maxFileBytes` is now a per-file, per-call read budget instead of a skip threshold, and `stats.filesOverSizeLimit` counts files that used it up and continue on the next call.
26
+ - The Claude first-answer fallback id for assistant records without `message.id` is the line's byte offset instead of a per-scan line index, so it stays stable across calls.
27
+
8
28
  ## [0.27.1] - 2026-09-22
9
29
 
10
30
  ### Fixed
package/README.md CHANGED
@@ -9,6 +9,7 @@ Types, parsers, providers, readers, formatters, aggregation, search, reporting,
9
9
 
10
10
  ## Recent additions
11
11
 
12
+ - **0.27.2: streamed prompt history** — `collectPromptHistory()` reads session logs of any size in bounded, resumable passes instead of skipping files over `maxFileBytes`: every call keeps what it read, the cursor (`version: 3`) continues where each file stopped, and a pending prompt keeps its answer state so a far-away answer still settles it. Adds `maxRecordBytes` and `maxEntries` bounds, `hasMore`, permanently skipped records in `exclusions`, and rewrite detection.
12
13
  - **0.27.1: late prompt metadata** — `collectPromptHistory()` returns a prompt again, with the same provider, sessionId, ordinal, timestamp, and text, when its first answering call is written after an earlier collection, and entries gain `metadataStatus` (`pending` / `provisional` / `final`). The cursor becomes `version: 2`, keeps a replay offset and metadata digest for the one open prompt per file (no prompt text), and still accepts 0.27.0 cursors.
13
14
  - **0.27.0: human prompt history** — `collectPromptHistory()` (Node-only) returns the prompts a person typed in Claude Code and Codex sessions under a set of workspace roots (plus git worktree siblings), with fail-closed cwd scoping, untruncated text, stable per-session ordinals, the answering model and usage, a JSON-serializable resume cursor, and bounds that stop cleanly and report themselves in `boundsHit`. `isHumanPrompt()` / `humanPromptText()` expose the same classification for any canonical transcript message, and transcript provenance now keeps Claude Code's `isCompactSummary`, `originKind`, and `promptSource`. Claude Opus 5.5 gets its own pricing and context entries.
14
15
  - **0.26.6: verified account switching** — `syncLiveAccountState()` reconciles the live Claude Code and Codex logins with saved profiles (registers unknown logins under their email, folds rotated tokens, merges duplicate Codex profiles, re-points the active pointer) and runs at startup, on account-change events, and as phase one of every switch; `getAccountHealth()` / `listAccountsWithHealth()` report secret-free `fresh | expiring | expired | unknown | missing` health; `switchAccount[Async]()` returns a `SwitchAccountResult` with verification, `runningConsumers`, `needsLogin`, and an `undoToken` for `undoLastSwitch()`; `detectRunningAccountConsumers()`, `getAccountLaunchEnv()`, `refreshInactiveAccounts()`, and `getCodexCredentialStoreMode()` are new. Claude logins run `claude auth login`, the Keychain suffix follows Claude Code 2.1.x, and the unused shell-hook helpers were removed.
@@ -310,8 +311,10 @@ const result = await collectPromptHistory({
310
311
  cursor,
311
312
  bounds: {
312
313
  maxSessions: 1000,
313
- maxFileBytes: 16 << 20,
314
+ maxFileBytes: 16 << 20, // per file per call; the rest is read next call
314
315
  maxTotalBytes: 256 << 20,
316
+ maxRecordBytes: 16 << 20, // one longer record is skipped and reported
317
+ maxEntries: 10_000,
315
318
  deadlineMs: 30_000,
316
319
  },
317
320
  signal: AbortSignal.timeout(60_000),
@@ -321,16 +324,19 @@ for (const entry of result.entries) {
321
324
  // { provider, sessionId, ordinal, timestamp, text, cwd, gitBranch?, model?, usage?, metadataStatus }
322
325
  // Upsert by (provider, sessionId, ordinal): a prompt comes back when its answer metadata changes.
323
326
  }
324
- saveCursor(result.cursor); // sensitive local state; unchanged files are skipped next time
325
- if (result.boundsHit.length > 0) console.warn('partial pass', result.boundsHit, result.stats);
327
+ saveCursor(result.cursor); // sensitive local state; fully read unchanged files are skipped next time
328
+ if (result.hasMore) scheduleAnotherCall(); // a bound stopped the pass; the cursor resumes it
329
+ for (const exclusion of result.exclusions) console.warn('record left out', exclusion); // permanent
326
330
  ```
327
331
 
328
332
  - **Scope fails closed.** A prompt is returned only when its recorded working directory (the Claude line's `cwd`; the Codex `session_meta` / `turn_context` cwd) realpath-resolves to a root or somewhere inside one. Missing or unresolvable cwds are excluded and counted in `stats.promptsOutOfScope`; Codex scope never comes from the rollout's location. `cwd` is the only path in entries. Cursor keys hold no paths, but cursor values can (Codex resume state keeps the session's cwd and branch), so store the cursor as sensitive, local-only state.
329
333
  - **Parse-only.** No redaction and no network I/O; text is untruncated.
330
334
  - **Ordinals are stable.** Every human prompt in a file consumes one ordinal, even when it is out of scope, older than `since`, or lacks a timestamp (such lines are skipped and counted, never given a synthesized time). Entries are ordered by provider, session, then ordinal.
331
335
  - **Model and usage** come from the first model call that answered the prompt (Claude: the first non-synthetic assistant message, with split records of that call replacing rather than adding usage; Codex: the first `token_count` with the model from `turn_context`). Later tool-loop calls never replace it. `inputTokens` is uncached input, and missing usage stays `undefined`, never zero.
332
- - **Late answers enrich the same prompt.** A prompt can be collected before its answer is written. `metadataStatus` is `pending` (no answering call yet), `provisional` (Claude call still being written, `stop_reason: null`), or `final`. While a file's last prompt is not final, the cursor keeps the byte offset of its line and a digest of what was returned (never prompt or answer text); the next call replays from that line and returns the prompt again, with the same provider, sessionId, ordinal, timestamp, and text, only when its model, usage, or status changed. A prompt closed by the next prompt without an answer comes back once as `final` with no usage. Consumers should upsert by identity. Cursors from 0.27.0 (`version: 1`) are accepted but cannot recover prompts they already returned without metadata.
333
- - **Bounds never throw.** Hitting `maxSessions`, `maxTotalBytes`, the deadline, or an abort stops the pass. An interrupted file contributes no entries, and the cursor covers only fully processed files, so the next call picks up where this one stopped. A file over `maxFileBytes` is different: it is skipped and counted in `stats.filesOverSizeLimit`, and calling again with the same bounds skips it again, so raise the bound to make progress on it. When only the replay of a pending prompt would exceed `maxFileBytes`, the replay is dropped and the file continues from its committed offset; that prompt is not revisited.
336
+ - **Late answers enrich the same prompt.** A prompt can be collected before its answer is written. `metadataStatus` is `pending` (no answering call yet), `provisional` (Claude call still being written, `stop_reason: null`), or `final`. While a file's last prompt is not final, the cursor keeps the byte offset and length of its line, its timestamp, and its answer state so far (first-answer message id, model, and usage, never prompt or answer text). The next call continues from where the file stopped, however far the answer is, and returns the prompt again with the same provider, sessionId, ordinal, timestamp, and text only when its model, usage, or status changed; the text comes from re-reading that one line. A prompt closed by the next prompt without an answer comes back once as `final` with no usage. Consumers should upsert by identity.
337
+ - **Large files are streamed and resumable.** Files are read in 1 MiB chunks and every pass stops after a complete line, so memory stays near one chunk plus one record whatever the file size. `maxFileBytes` is the most one file may read in one call: a file with more left keeps what it returned, records `backlog` in its cursor, is counted in `stats.filesOverSizeLimit`, and continues on the next call even if its size and mtime have not changed. `maxSessions`, `maxTotalBytes`, `maxEntries`, the deadline, and an abort stop the whole call the same way, and `cursor.next` makes the next call start with the file that was stopped, so a large or busy session cannot starve the others. The first file of a call always finishes its first record, so a record larger than the budget still moves forward. Bytes appended during a call and a half-written final line wait for the next call. `boundsHit` lists these resumable stops and `hasMore` says whether calling again would read more. No bound throws.
338
+ - **Permanent exclusions are reported.** A record over `maxRecordBytes` is skipped as it streams past without being buffered, even when it is still being written, and a complete line that is not JSON is skipped. Each is counted (`stats.recordsOverSizeLimit`, `stats.recordsMalformed`) and listed in `exclusions` with its byte offset. A prompt inside such a record is lost and does not consume an ordinal. A file that shrank or whose first 4 KiB changed is treated as rewritten: it is read again from the start with fresh ordinals and counted in `stats.sessionsRewritten`.
339
+ - **Cursor versions.** Output is `version: 3`. Cursors from 0.27.0 (`version: 1`) and 0.27.1 (`version: 2`) are accepted: each file is re-verified once, and a 0.27.1 pending prompt is replayed from its line in resumable passes, so it now settles even when its answer is far away. Files 0.27.1 skipped for size were never in its cursor and are read in full on the first call. Metadata that 0.27.1 already gave up on (a pending replay that exceeded `maxFileBytes`) was not saved and cannot be recovered, and a 0.27.0 cursor still cannot recover prompts it returned without metadata.
334
340
 
335
341
  For an already-open incremental Codex rollout, keep one `CodexRolloutParser` per stream and pass each parsed `SessionEvent[]` batch to `projectSessionTranscript()` (or append the events to an existing projection). This preserves parser state for paired tool calls, model context, and cumulative token deltas; consumers should not convert raw `response_item` rows themselves.
336
342
 
package/dist/index.d.ts CHANGED
@@ -11,7 +11,7 @@ export { projectSessionTranscript } from './transcript';
11
11
  export type { TranscriptFidelity, TranscriptSourceProvenance, CanonicalTranscriptBlock, CanonicalTranscriptMessage, CanonicalToolCall, CanonicalTranscriptUsageTotals, CanonicalSessionTranscript, ProjectSessionTranscriptOptions, } from './transcript';
12
12
  export { listRecentSessions, readSessionTranscript } from './sessionTranscripts';
13
13
  export { collectPromptHistory } from './promptHistory';
14
- export type { CollectPromptHistoryOptions, PromptHistoryBound, PromptHistoryBounds, PromptHistoryCursor, PromptHistoryCursorSession, PromptHistoryEntry, PromptHistoryMetadataStatus, PromptHistoryPendingPrompt, PromptHistoryProvider, PromptHistoryResult, PromptHistoryResumeState, PromptHistoryStats, PromptHistoryUsage, } from './promptHistory';
14
+ export type { CollectPromptHistoryOptions, PromptHistoryAnswerState, PromptHistoryBound, PromptHistoryBounds, PromptHistoryCursor, PromptHistoryCursorSession, PromptHistoryEntry, PromptHistoryExclusion, PromptHistoryMetadataStatus, PromptHistoryPendingPrompt, PromptHistoryProvider, PromptHistoryResult, PromptHistoryResumeState, PromptHistoryStats, PromptHistoryUsage, } from './promptHistory';
15
15
  export { HUMAN_CLAUDE_ENTRYPOINTS, HUMAN_CODEX_SOURCES, humanPromptText, isHumanPrompt, } from './humanPrompt';
16
16
  export type { HumanPromptProvider } from './humanPrompt';
17
17
  export { computeSessionFileStats, firstUserPrompt, providerContextSizeFn, readSessionFileStats, } from './sessionStats';
package/dist/node.d.ts CHANGED
@@ -11,7 +11,7 @@ export { loadObservedContextWindows, recordObservedContextWindow, getObservedCon
11
11
  export type { ObservedContextWindowOptions, ObservedContextWindowStore, } from './observedContextWindows';
12
12
  export { listRecentSessions, readSessionTranscript } from './sessionTranscripts';
13
13
  export { collectPromptHistory } from './promptHistory';
14
- export type { CollectPromptHistoryOptions, PromptHistoryBound, PromptHistoryBounds, PromptHistoryCursor, PromptHistoryCursorSession, PromptHistoryEntry, PromptHistoryMetadataStatus, PromptHistoryPendingPrompt, PromptHistoryProvider, PromptHistoryResult, PromptHistoryResumeState, PromptHistoryStats, PromptHistoryUsage, } from './promptHistory';
14
+ export type { CollectPromptHistoryOptions, PromptHistoryAnswerState, PromptHistoryBound, PromptHistoryBounds, PromptHistoryCursor, PromptHistoryCursorSession, PromptHistoryEntry, PromptHistoryExclusion, PromptHistoryMetadataStatus, PromptHistoryPendingPrompt, PromptHistoryProvider, PromptHistoryResult, PromptHistoryResumeState, PromptHistoryStats, PromptHistoryUsage, } from './promptHistory';
15
15
  export { HUMAN_CLAUDE_ENTRYPOINTS, HUMAN_CODEX_SOURCES, humanPromptText, isHumanPrompt, } from './humanPrompt';
16
16
  export type { HumanPromptProvider } from './humanPrompt';
17
17
  export { computeSessionFileStats, firstUserPrompt, providerContextSizeFn, readSessionFileStats, } from './sessionStats';
@@ -8,24 +8,37 @@
8
8
  * or somewhere inside one. Every bound stops cleanly and is reported in
9
9
  * `boundsHit`; nothing is silently truncated and no bound throws.
10
10
  *
11
+ * Files are streamed in fixed-size chunks and every pass stops at a complete
12
+ * line, so a large or busy log is read across several calls: the cursor holds
13
+ * where each file stopped and the next call continues from there. A single
14
+ * record over `maxRecordBytes` is skipped without being buffered and reported
15
+ * in `exclusions`, the only way a record is permanently left out.
16
+ *
11
17
  * A prompt can be written before its answer. The cursor then keeps the byte
12
- * offset of that prompt's line (not its text), the next call replays from it,
13
- * and the prompt is returned again under the same identity once its first
18
+ * offset of that prompt's line and its answer-tracking state (never text), and
19
+ * the prompt is returned again under the same identity once its first
14
20
  * answering call brings model or usage (`metadataStatus` says how settled).
15
21
  */
16
22
  import { type HumanPromptProvider } from './humanPrompt';
17
23
  export type PromptHistoryProvider = HumanPromptProvider;
18
- export type PromptHistoryBound = 'maxSessions' | 'maxFileBytes' | 'maxTotalBytes' | 'deadline' | 'aborted';
24
+ export type PromptHistoryBound = 'maxSessions' | 'maxFileBytes' | 'maxTotalBytes' | 'maxEntries' | 'deadline' | 'aborted';
19
25
  export interface PromptHistoryBounds {
20
26
  /** Session files read in one call (unchanged files do not count). Default 1000. */
21
27
  maxSessions?: number;
22
28
  /**
23
- * Bytes a single file may need read in this pass. Default 16 MiB. A file over
24
- * it is skipped, and calling again with the same bounds skips it again.
29
+ * Bytes read from one file in one call. Default 16 MiB. A file with more to
30
+ * read stops at a line boundary and continues on the next call.
25
31
  */
26
32
  maxFileBytes?: number;
27
33
  /** Bytes read across all files in this call. Default 256 MiB. */
28
34
  maxTotalBytes?: number;
35
+ /**
36
+ * Largest single log record that is parsed. Default 16 MiB. A longer record
37
+ * is skipped without being buffered and reported in `exclusions`.
38
+ */
39
+ maxRecordBytes?: number;
40
+ /** Entries returned by one call. Default 10 000. */
41
+ maxEntries?: number;
29
42
  /** Wall-clock budget for the call. Default 30 000 ms. */
30
43
  deadlineMs?: number;
31
44
  }
@@ -39,18 +52,36 @@ export interface PromptHistoryResumeState {
39
52
  /** `session_meta` has been seen. */
40
53
  meta?: boolean;
41
54
  }
55
+ /** Answer metadata gathered so far for an open prompt; never text. */
56
+ export interface PromptHistoryAnswerState {
57
+ status: 'pending' | 'provisional';
58
+ /** Claude message id of the first answering call, once one has been seen. */
59
+ id?: string;
60
+ model?: string;
61
+ usage?: PromptHistoryUsage;
62
+ }
42
63
  /**
43
64
  * The last emitted prompt of a file whose answering call is not final yet.
44
- * Holds a replay position and a metadata digest, never prompt or answer text.
65
+ * Holds a position and answer metadata, never prompt or answer text.
45
66
  */
46
67
  export interface PromptHistoryPendingPrompt {
47
68
  ordinal: number;
48
- /** Byte offset where the prompt's log line starts; the next pass replays from here. */
69
+ /** Byte offset where the prompt's log line starts. */
49
70
  offset: number;
71
+ /** Byte length of the prompt's log line, without its newline. */
72
+ lineBytes?: number;
73
+ /** Timestamp of the prompt line, used to verify it when it is read again. */
74
+ timestamp?: string;
50
75
  /** Digest of the model, usage, and status last returned for this prompt. */
51
76
  emitted: string;
52
77
  /** Codex parse state as it was just before the prompt line. */
53
78
  state?: PromptHistoryResumeState;
79
+ /**
80
+ * Answer tracking to continue from the session offset. Absent only on a
81
+ * session carried unchanged from a version 2 cursor, which replays from
82
+ * `offset` the next time it is read.
83
+ */
84
+ answer?: PromptHistoryAnswerState;
54
85
  }
55
86
  export interface PromptHistoryCursorSession {
56
87
  provider: PromptHistoryProvider;
@@ -59,19 +90,30 @@ export interface PromptHistoryCursorSession {
59
90
  mtimeMs: number;
60
91
  /** Ordinal of the last human prompt seen in this file, or -1 when none. */
61
92
  lastOrdinal: number;
62
- /** Byte offset just past the last complete line processed. */
93
+ /** Byte offset where the next pass starts reading. */
63
94
  offset: number;
64
95
  state?: PromptHistoryResumeState;
65
96
  pending?: PromptHistoryPendingPrompt;
97
+ /** A bound stopped the last pass before the end of the file. */
98
+ backlog?: true;
99
+ /** `offset` is inside a record over `maxRecordBytes`; skip to its newline. */
100
+ skipping?: true;
101
+ /** Digest of the file's first bytes, used to detect a rewritten file. */
102
+ head?: {
103
+ bytes: number;
104
+ hash: string;
105
+ };
66
106
  }
67
107
  /**
68
108
  * JSON-serializable resume point. Keys are opaque and never contain paths, but
69
109
  * values can (Codex `state.cwd`), so treat the cursor as sensitive local state.
70
- * Version 1 cursors from 0.27.0 are accepted as input; output is always version 2.
110
+ * Version 1 and 2 cursors are accepted as input; output is always version 3.
71
111
  */
72
112
  export interface PromptHistoryCursor {
73
- version: 2;
113
+ version: 3;
74
114
  sessions: Record<string, PromptHistoryCursorSession>;
115
+ /** Opaque key of the file the next call starts with, after a call-wide stop. */
116
+ next?: string;
75
117
  }
76
118
  /**
77
119
  * How settled an entry's `model` / `usage` are:
@@ -112,14 +154,35 @@ export interface PromptHistoryEntry {
112
154
  */
113
155
  metadataStatus: PromptHistoryMetadataStatus;
114
156
  }
157
+ /**
158
+ * A log record permanently left out. Records over `maxRecordBytes` and lines
159
+ * that are not valid JSON are never parsed, so any prompt inside is lost, and
160
+ * the ordinals of later prompts in that file do not count it.
161
+ */
162
+ export interface PromptHistoryExclusion {
163
+ provider: PromptHistoryProvider;
164
+ sessionId: string;
165
+ reason: 'oversizedRecord' | 'malformedRecord';
166
+ /** Byte offset where the record starts. */
167
+ offset: number;
168
+ }
115
169
  export interface PromptHistoryStats {
116
170
  sessionsScanned: number;
117
171
  sessionsSkippedUnchanged: number;
118
172
  /** Scanned sessions with human prompts but none inside the allowed roots. */
119
173
  sessionsOutOfScope: number;
174
+ /** Files whose `maxFileBytes` budget ran out; they continue on the next call. */
120
175
  filesOverSizeLimit: number;
176
+ /** Scanned sessions left with unread bytes by any bound; they continue next call. */
177
+ sessionsWithBacklog: number;
178
+ /** Sessions whose file was truncated or rewritten and was read again from the start. */
179
+ sessionsRewritten: number;
121
180
  /** Codex sessions skipped as non-interactive (subagent, fork, unknown source). */
122
181
  sessionsNotInteractive: number;
182
+ /** Records skipped for exceeding `maxRecordBytes` (see `exclusions`). */
183
+ recordsOverSizeLimit: number;
184
+ /** Complete lines that were not valid JSON (see `exclusions`). */
185
+ recordsMalformed: number;
123
186
  /** Human prompts dropped because the log line had no usable timestamp. */
124
187
  promptsMissingTimestamp: number;
125
188
  /** Human prompts dropped because their cwd was missing or outside the roots. */
@@ -143,7 +206,16 @@ export interface PromptHistoryResult {
143
206
  entries: PromptHistoryEntry[];
144
207
  cursor: PromptHistoryCursor;
145
208
  stats: PromptHistoryStats;
209
+ /** Resumable stops: calling again with the returned cursor continues past them. */
146
210
  boundsHit: PromptHistoryBound[];
211
+ /** Permanent exclusions found in this call (at most 1000; stats count all). */
212
+ exclusions: PromptHistoryExclusion[];
213
+ /** A bound left bytes or files unread; call again with the cursor to continue. */
214
+ hasMore: boolean;
147
215
  }
216
+ /** Test hooks; not part of the public entry points. */
217
+ export declare const __promptHistoryTesting: {
218
+ setReadChunkBytes(bytes: number | null): void;
219
+ };
148
220
  /** Collect human-typed prompts from Claude Code and Codex logs under the given roots. */
149
221
  export declare function collectPromptHistory(options: CollectPromptHistoryOptions): Promise<PromptHistoryResult>;