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 +20 -0
- package/README.md +11 -5
- package/dist/index.d.ts +1 -1
- package/dist/node.d.ts +1 -1
- package/dist/promptHistory.d.ts +82 -10
- package/dist/promptHistory.js +654 -183
- package/package.json +1 -1
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.
|
|
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
|
|
333
|
-
- **
|
|
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';
|
package/dist/promptHistory.d.ts
CHANGED
|
@@ -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
|
|
13
|
-
*
|
|
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
|
|
24
|
-
*
|
|
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
|
|
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
|
|
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
|
|
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
|
|
110
|
+
* Version 1 and 2 cursors are accepted as input; output is always version 3.
|
|
71
111
|
*/
|
|
72
112
|
export interface PromptHistoryCursor {
|
|
73
|
-
version:
|
|
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>;
|