@workerdeck/react 0.15.0 → 0.17.0

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/README.md CHANGED
@@ -137,6 +137,23 @@ input by construction: fine for the user's own data, never a source of server-au
137
137
 
138
138
  ## Rules you cannot infer from the types
139
139
 
140
+ - **A truncated tool result is hydrated into transcript state, not into a row.** The hook attaches
141
+ with `truncateResults`, so a huge result arrives as a head carrying
142
+ `result.truncated`/`totalChars`/`sourceSeq`; `loadFullResult(toolUseId)` fetches the rest and
143
+ folds it in through `hydrateToolResult`, which clears the markers. Keeping it in row-local state
144
+ instead would mean the copy button copies the head, the transcript cache drops it on a session
145
+ switch, and the next event re-truncates the row.
146
+
147
+ - **`result.images` is the same idea for pictures, and it is set only when there are any.** The
148
+ hook also attaches with `imageRefs`, so a `tool_result`'s base64 images arrive as addresses and
149
+ the reducer records `{ partIndex, mediaType, bytes, sourceSeq }` per picture — absent, never
150
+ empty, because an item that gained a field is an item every renderer re-measures (on iOS
151
+ `ToolCallItem` is `Equatable` and half the row-plan cache key). Each entry carries its **own**
152
+ `sourceSeq`: the result-level one is cleared by text hydration, and a reader who pressed "show
153
+ everything" must still be able to load the screenshot. Raw base64 parts are still dropped on
154
+ arrival, as they always were — folding them into state would pin megabytes inside the transcript
155
+ cache.
156
+
140
157
  - **Companions must ride the hook's own `handle`.** The server's tool bridge asks the *first
141
158
  attached client*, so a second `useClaudeSession` for the same session is a second attach that
142
159
  will never be asked anything. `useAttachments`, `useHostFileSearch` and `useToolCallHost` all
@@ -152,6 +169,16 @@ input by construction: fine for the user's own data, never a source of server-au
152
169
  - **The recap is counted, never written.** `summarizeSince` returns numbers because generating
153
170
  prose would spend a turn on a summary nobody asked for, and would be worst exactly where it
154
171
  matters most: a session that failed while unattended.
172
+ - **Detached transcripts stay warm by default.** `useClaudeSession` keeps a bounded, module-scope
173
+ cache of the last few transcripts it held, so switching back to a session paints in the mount
174
+ frame and re-attaches with `afterSeq`, replaying only what it missed. Entries are keyed by the
175
+ client's `identityKey` — gateway base URL plus auth headers — never the session id alone (a
176
+ session id is unique only within one gateway), and a cached `afterSeq` pointed at a log the
177
+ server no longer has (a dormant rebuild, a restart) is detected off the attach frame
178
+ (`staleAttach`) and discarded with a full resync, because that attach would otherwise deliver
179
+ nothing and the stale rows would stand forever. Opt out with `cacheTranscript: false` if your
180
+ principal varies on one base URL by means the client cannot see, and call
181
+ `clearTranscriptCache()` on an in-place logout.
155
182
 
156
183
  ## License
157
184
 
package/build/index.d.mts CHANGED
@@ -1,8 +1,8 @@
1
- import { ContextUsage, EngineCapabilities, HostDirEntry, HostFileMatch, MessageAttachment, ModelOption, PermissionMode, PermissionRequest, ProfileEngine, RateLimitInfo, SessionEvent, SessionInfo, SessionStatus, SkillInfo, SlashCommandInfo, ToolExecutionBackend } from "@workerdeck/protocol";
1
+ import { AttachedFrame, ContextUsage, EngineCapabilities, FilePatch, HostDirEntry, HostFileMatch, MessageAttachment, ModelOption, PermissionMode, PermissionRequest, ProfileEngine, ProfileUsage, RateLimitInfo, SessionEvent, SessionInfo, SessionRow, SessionStatus, SkillInfo, SlashCommandInfo, ToolExecutionBackend, UsageWindowRow } from "@workerdeck/protocol";
2
2
  import { SessionHandle, WorkerDeckClient } from "@workerdeck/client";
3
3
  import { RunScriptResult, SandboxEngine, SandboxVfs } from "@workerdeck/sandbox";
4
4
 
5
- //#region src/transcript.d.ts
5
+ //#region src/lib/transcript.d.ts
6
6
  /**
7
7
  * Pure transcript state machine over the wire-protocol event stream. Framework-free
8
8
  * so it can be unit-tested and reused outside React.
@@ -12,6 +12,18 @@ type TranscriptItem = {
12
12
  id: string;
13
13
  text: string;
14
14
  attachments?: MessageAttachment[];
15
+ /**
16
+ * The `Task` call this prompt was addressed to, when it is a subagent's
17
+ * brief rather than something a person typed.
18
+ *
19
+ * Optional where the other kinds carry it as `string | null`, and the
20
+ * asymmetry is the point: on those it is a fact about every instance, so
21
+ * forgetting to stamp it should not typecheck. Here the overwhelming case
22
+ * is a human prompt, which has no parent at all — `undefined` says that,
23
+ * where `null` on 24 construction sites would only say "somebody
24
+ * remembered".
25
+ */
26
+ parentToolUseId?: string;
15
27
  } | {
16
28
  kind: 'assistant_text';
17
29
  id: string;
@@ -39,10 +51,56 @@ type TranscriptItem = {
39
51
  * deferred call has no result yet and is not the same as a running one.
40
52
  */
41
53
  status: 'running' | 'pending' | 'deferred' | 'settled' | 'failed';
54
+ /**
55
+ * `truncated`/`totalChars`/`sourceSeq` are set **only** when the replay
56
+ * delivered a head (protocol's {@link ToolResultBlock.truncated}), so
57
+ * every other result stays byte-identical to what it was before this
58
+ * feature existed. That matters beyond tidiness: on iOS `ToolCallItem` is
59
+ * `Equatable` and is half the row-plan cache key.
60
+ *
61
+ * `sourceSeq` is what makes the press possible at all — the item is what a
62
+ * renderer holds, and it must be able to name the event to fetch. It goes
63
+ * away again on hydration, along with the other two, so a hydrated result
64
+ * is indistinguishable from one that was never cut.
65
+ */
42
66
  result?: {
43
67
  text: string;
44
68
  isError: boolean;
45
- }; /** Correlation id when this call is executed outside the model loop. */
69
+ truncated?: boolean;
70
+ totalChars?: number;
71
+ sourceSeq?: number;
72
+ /**
73
+ * The pictures this result carried, as addresses rather than bytes —
74
+ * set **only** when the replay delivered `image_ref` parts, so every
75
+ * other result stays byte-identical (the `Equatable` argument above,
76
+ * again).
77
+ *
78
+ * Each entry carries its **own** `sourceSeq`, which is not redundant
79
+ * with the one beside it: that one is cleared by text hydration, and a
80
+ * reader who pressed "show everything" must still be able to load the
81
+ * screenshot afterwards.
82
+ *
83
+ * Raw base64 `image` parts are still dropped on arrival, as they always
84
+ * were. Folding them in would pin megabytes inside `TranscriptState`,
85
+ * which the transcript LRU then retains across session switches.
86
+ */
87
+ images?: ReadonlyArray<{
88
+ partIndex: number;
89
+ mediaType: string;
90
+ bytes: number;
91
+ sourceSeq: number;
92
+ }>;
93
+ };
94
+ /**
95
+ * What this call changed on disk, when it was a file edit — the engine's
96
+ * own hunks and line numbers (see protocol's {@link FilePatch}).
97
+ *
98
+ * Only ever set from the wire. A client cannot derive it: it has never
99
+ * seen the file, so a diff it computed from the tool's *input* would have
100
+ * no line numbers, and one parsed out of the result prose would be welded
101
+ * to an engine's text formatting.
102
+ */
103
+ patch?: FilePatch; /** Correlation id when this call is executed outside the model loop. */
46
104
  executionId?: string; /** Which backend is executing it, when known. */
47
105
  backend?: ToolExecutionBackend; /** Logs captured by the executor (guest console output). */
48
106
  logs?: string[];
@@ -156,18 +214,31 @@ declare function seedFromSessionInfo(state: TranscriptState, info: SessionInfo):
156
214
  * The session's rate-limit windows in reading order: the session window, the
157
215
  * weekly window, then whichever per-model weekly windows it reports.
158
216
  *
159
- * Discovered rather than hardcoded the SDK's set of windows is an open union
160
- * and has grown before but ordered, so the first two always mean the same
161
- * thing. A window with no `utilization` is *unknown*, not zero, and is dropped
162
- * entirely rather than drawn as an empty bar that reads as "plenty left".
217
+ * The ordering and the drop-the-unknown rule are protocol's `orderUsageWindows`
218
+ * — the dashboard renders the same windows straight off `ProfileInfo.usage`,
219
+ * with no transcript anywhere near it, and two orderings would be one account
220
+ * described two ways. This stays as the transcript-shaped door to it.
163
221
  */
164
- declare function rateLimitWindows(state: TranscriptState): Array<{
165
- key: string;
166
- info: RateLimitInfo;
167
- }>;
222
+ declare function rateLimitWindows(state: TranscriptState): UsageWindowRow[];
223
+ /**
224
+ * Put a fetched tool result back where its head was — the other half of
225
+ * `truncateResults`.
226
+ *
227
+ * Into **transcript state**, not row-local state, and the three reasons are the
228
+ * design: the copy button then copies the whole thing rather than the head, the
229
+ * transcript cache retains it across a session switch, and no later event can
230
+ * re-truncate it. The markers are cleared, so a hydrated result is
231
+ * indistinguishable from one that was never cut and every renderer needs a
232
+ * branch for exactly one state, not two.
233
+ *
234
+ * Keyed on `toolUseId`, which is the id the row already holds; `seq` is what the
235
+ * *fetch* needed, not what the fold needs. Unknown id returns `state` unchanged
236
+ * — a press answered after the session was cleared must not resurrect a row.
237
+ */
238
+ declare function hydrateToolResult(state: TranscriptState, toolUseId: string, text: string): TranscriptState;
168
239
  declare function applyEvent(state: TranscriptState, event: SessionEvent): TranscriptState;
169
240
  //#endregion
170
- //#region src/use-session.d.ts
241
+ //#region src/hooks/use-session.d.ts
171
242
  /**
172
243
  * How the client is doing at reaching the gateway — deliberately not the session's
173
244
  * status. The two are orthogonal, and while the socket is down the status a client
@@ -178,11 +249,88 @@ declare function applyEvent(state: TranscriptState, event: SessionEvent): Transc
178
249
  * been failing rather than a state the transport reports.
179
250
  */
180
251
  type ConnectionState = 'live' | 'reconnecting' | 'offline';
252
+ /**
253
+ * The seq the initial attach replay ends on, or undefined when there is nothing
254
+ * to hold for.
255
+ *
256
+ * This is an exact signal, not a heuristic: the `attached` frame is sent before
257
+ * any replayed `event` frame and carries the runner's seq at attach time
258
+ * (`session.lastSeq`), so the moment the frame arrives the client knows
259
+ * precisely which seq the replay ends on. Every runner keeps its full event log
260
+ * and always delivers the highest-seq event on a fresh replay (the
261
+ * `conversation_reset` skip is strictly-below-the-reset, and the reset's seq is
262
+ * itself ≤ lastSeq), so `TranscriptState.lastSeq >= target` means the replay
263
+ * has landed. No quiet window or other arrival heuristic belongs here.
264
+ *
265
+ * Only a FRESH attach yields a target (`replayingFrom === 0`): a reconnect
266
+ * replays into a transcript the reader is already looking at, and blanking it
267
+ * mid-turn would be a worse bug than the flicker the hold exists to fix. A
268
+ * brand-new session (`lastSeq === 0`) has nothing to replay and never holds.
269
+ */
270
+ declare function initialReplayTarget(frame: AttachedFrame): number | undefined;
271
+ /**
272
+ * Whether an attach frame describes a DIFFERENT event log than the transcript
273
+ * `held` was built from — in which case attaching with `afterSeq: held.lastSeq`
274
+ * has already gone wrong: every event in the new log has seq ≤ afterSeq, so
275
+ * nothing will ever arrive and the stale rows would stand forever, with no
276
+ * error. The only recovery is to forget the state and re-attach from seq 0.
277
+ *
278
+ * A log resets on routine paths, not corner cases: a dormant session
279
+ * (claude/codex surviving a gateway restart) is rebuilt with a brand-new
280
+ * runner whose log starts at 0 and refills from the engine's own store. Two
281
+ * checks, each of which the other misses:
282
+ *
283
+ * - `session.lastSeq < held.lastSeq` — the server's log is shorter than what
284
+ * we hold. Within one log seq only grows, so this is proof of a reset. It
285
+ * catches a rebuilt runner that has not yet re-run far — but not one whose
286
+ * backfill already advanced past us.
287
+ * - `session.createdAt !== held.session.createdAt` — a different runner
288
+ * incarnation. The claude and codex runners stamp `Date.now()` at
289
+ * construction, so a dormant rebuild always changes it; the provider runner
290
+ * restores `createdAt` from its snapshot precisely when it also restores
291
+ * the event log and seq counter (ai-sdk-runner's `#restore`), so equality
292
+ * truthfully means "same log" for every engine.
293
+ *
294
+ * A full replay (`replayingFrom === 0`) is never stale — it carries the whole
295
+ * log, so the caller heals by resetting state and applying it — and holding
296
+ * nothing (`held.lastSeq === 0`) has nothing to be stale about. That first
297
+ * clause is also what makes the recovery loop-proof: the re-attach from 0 can
298
+ * never re-trigger this predicate.
299
+ *
300
+ * Not cache-specific: a live handle reconnecting after a gateway restart
301
+ * re-attaches with its own advanced `afterSeq` against the rebuilt log and
302
+ * hits the identical silence, so the hook applies this to every attach frame.
303
+ */
304
+ declare function staleAttach(frame: AttachedFrame, held: TranscriptState): boolean;
305
+ /**
306
+ * Backstop for the replay hold: if the target seq has not landed after this
307
+ * long, reveal what has arrived. On a healthy attach the target is always
308
+ * reached (see {@link initialReplayTarget}); the backstop exists because a
309
+ * blank panel forever would be a much worse failure than a visible stream, so
310
+ * the hold is bounded no matter what a future filter or a lossy path does. It
311
+ * runs from the attach — a per-event re-arm would be a quiet-window heuristic
312
+ * in a new costume.
313
+ */
314
+ declare const REPLAY_HOLD_MAX_MS = 1500;
181
315
  type UseClaudeSessionOptions = {
182
316
  /** Called when the server rejects a command with a protocol_error frame — e.g. a
183
317
  * permission-mode switch the CLI refuses. Without a handler these are dropped
184
318
  * silently and the UI looks like "nothing happened". */
185
319
  onProtocolError?: (message: string) => void;
320
+ /**
321
+ * Keep this session's transcript warm after unmount (default true): the next
322
+ * mount of the same (client identity, session) paints the cached rows in its
323
+ * first frame and attaches with `afterSeq`, replaying only what it missed.
324
+ * Bounded module-scope LRU, keyed by the client's `identityKey` (gateway +
325
+ * auth headers) so nothing crosses gateways or credentials; if the attach
326
+ * frame shows a different event log (see {@link staleAttach}), the entry is
327
+ * discarded and the hook re-attaches from seq 0.
328
+ *
329
+ * Set `false` for an embedder whose principal varies on one base URL by
330
+ * means the client cannot see (a custom `fetchImpl` switching users, say) —
331
+ * or call `clearTranscriptCache()` on logout. Read at attach time.
332
+ */
333
+ cacheTranscript?: boolean;
186
334
  };
187
335
  type UseClaudeSessionResult = {
188
336
  state: TranscriptState;
@@ -190,6 +338,16 @@ type UseClaudeSessionResult = {
190
338
  * carries the same fact with the "has it been failing a while" distinction. */
191
339
  connected: boolean;
192
340
  connection: ConnectionState;
341
+ /**
342
+ * True while the initial attach replay is still landing: the `attached` frame
343
+ * said events up to `session.lastSeq` follow, and they have not all been
344
+ * applied yet. A surface can hold its paint on this — keep the rows mounted
345
+ * and measuring, show nothing — and reveal a settled transcript in one frame,
346
+ * instead of streaming hundreds of replayed rows past the reader. Always
347
+ * false on a reconnect (only a fresh attach holds; see
348
+ * {@link initialReplayTarget}) and bounded by {@link REPLAY_HOLD_MAX_MS}.
349
+ */
350
+ replaying: boolean;
193
351
  /** The server's `PROTOCOL_VERSION` when it disagrees with the one this build
194
352
  * mirrors — undefined when they match. Some events may not render. */
195
353
  protocolMismatch?: number;
@@ -219,11 +377,30 @@ type UseClaudeSessionResult = {
219
377
  setModel: (model?: string) => void;
220
378
  closeSession: () => void; /** Skip the reconnect backoff — what a tab returning to the foreground does. */
221
379
  reconnectNow: () => void;
380
+ /**
381
+ * Fetch the whole of a tool result the replay delivered as a head, and put it
382
+ * back on its row (`result.truncated` clears with it).
383
+ *
384
+ * Resolves `false` when there was nothing to do — an untruncated row, an
385
+ * unknown id, or a gateway that refused (a stale `sourceSeq` after a dormant
386
+ * rebuild 404s by design; re-attaching is what fixes that, not a retry). It
387
+ * never throws, because the caller is a press on a row and an exception there
388
+ * has nowhere sensible to go.
389
+ */
390
+ loadFullResult: (toolUseId: string) => Promise<boolean>;
222
391
  };
223
392
  /** Attach to a session and maintain live transcript state. Detaches on unmount. */
224
393
  declare function useClaudeSession(client: WorkerDeckClient, sessionId: string | undefined, options?: UseClaudeSessionOptions): UseClaudeSessionResult;
225
394
  //#endregion
226
- //#region src/use-attachments.d.ts
395
+ //#region src/lib/transcript-cache.d.ts
396
+ /**
397
+ * Drop every cached transcript. For an embedder changing principals in place
398
+ * (a logout that keeps the page alive) — entries are unreachable through the
399
+ * new principal's client either way, but scrubbing them is free and final.
400
+ */
401
+ declare function clearTranscriptCache(): void;
402
+ //#endregion
403
+ //#region src/hooks/use-attachments.d.ts
227
404
  /**
228
405
  * Files staged for the next message.
229
406
  *
@@ -288,7 +465,7 @@ declare function useAttachments(client: WorkerDeckClient, sessionId: string | un
288
465
  engine
289
466
  }: UseAttachmentsOptions): UseAttachmentsResult;
290
467
  //#endregion
291
- //#region src/prompt-tokens.d.ts
468
+ //#region src/lib/prompt-tokens.d.ts
292
469
  /**
293
470
  * The two prompt tokens the CLI understands — `@file` and `/command` — found in
294
471
  * text that has already been sent.
@@ -317,7 +494,7 @@ type PromptToken = {
317
494
  */
318
495
  declare function scanPromptTokens(text: string): PromptToken[];
319
496
  //#endregion
320
- //#region src/host-tree.d.ts
497
+ //#region src/lib/host-tree.d.ts
321
498
  /**
322
499
  * One directory as the tree knows it: what `/fs/list` answered, plus whether the
323
500
  * server held entries back.
@@ -365,7 +542,7 @@ declare function flattenHostTree(root: string, dirs: ReadonlyMap<string, HostDir
365
542
  */
366
543
  declare function ancestorsWithin(root: string, path: string): string[];
367
544
  //#endregion
368
- //#region src/use-host-files.d.ts
545
+ //#region src/hooks/use-host-files.d.ts
369
546
  type UseHostFileSearchResult = {
370
547
  /**
371
548
  * Whether `@file` completion is on offer at all: the session's cwd is known
@@ -453,7 +630,45 @@ type UseHostFileTreeResult = {
453
630
  */
454
631
  declare function useHostFileTree(client: WorkerDeckClient, cwd: string | undefined): UseHostFileTreeResult;
455
632
  //#endregion
456
- //#region src/use-session-info.d.ts
633
+ //#region src/hooks/use-project-icons.d.ts
634
+ type ClientForHost = (hostId: string) => WorkerDeckClient | undefined;
635
+ declare function useProjectIcons(rows: readonly SessionRow[], clientFor: ClientForHost): Record<string, string>;
636
+ //#endregion
637
+ //#region src/hooks/use-profile-usage.d.ts
638
+ type UseProfileUsageOptions = {
639
+ /** How often to re-ask while enabled. Default 60s. */intervalMs?: number;
640
+ /** Set false to hold the poll — a panel that is off screen has nothing to
641
+ * refresh. Default true. */
642
+ enabled?: boolean;
643
+ };
644
+ type UseProfileUsageResult = {
645
+ /** The gateway's plan-usage state for this profile, or undefined when there
646
+ * is none to have: no profile, an older gateway, or nothing reported yet.
647
+ * Absent is **unknown, never 0%** — see `ProfileUsageWindow`. */
648
+ usage: ProfileUsage | undefined; /** Ask again now. */
649
+ refresh: () => void;
650
+ };
651
+ /**
652
+ * The gateway's per-profile plan usage, over REST.
653
+ *
654
+ * The session's own event stream carries a `rate_limit` reading only when the
655
+ * engine volunteers one — for claude that is at a turn's edges and nowhere else,
656
+ * so a session idle since yesterday replays yesterday's number, and a session
657
+ * opened today knows nothing of what a sibling on the same account spent an hour
658
+ * ago. `GET /profiles` answers the account-wide question, which is why this is a
659
+ * poll and not a subscription: nothing pushes it.
660
+ *
661
+ * Polling and not attaching, deliberately — a second WebSocket per surface is
662
+ * exactly what the bridge's "asks the first attached client" rule forbids, and
663
+ * this is one small GET a minute.
664
+ *
665
+ * Self-disabling on a 404, like {@link useHostFileSearch}: a gateway without the
666
+ * route will never grow one mid-session, so stop asking rather than log a miss
667
+ * every minute.
668
+ */
669
+ declare function useProfileUsage(client: WorkerDeckClient, profile: string | undefined, options?: UseProfileUsageOptions): UseProfileUsageResult;
670
+ //#endregion
671
+ //#region src/hooks/use-session-info.d.ts
457
672
  type UseSessionInfoResult = {
458
673
  info: SessionInfo | undefined; /** True until the first answer — distinguishes "still asking" from "no such session". */
459
674
  loading: boolean; /** Set when the gateway refused; `info` stays undefined. */
@@ -473,7 +688,7 @@ type UseSessionInfoResult = {
473
688
  */
474
689
  declare function useSessionInfo(client: WorkerDeckClient, sessionId: string | undefined): UseSessionInfoResult;
475
690
  //#endregion
476
- //#region src/open-files.d.ts
691
+ //#region src/lib/open-files.d.ts
477
692
  /**
478
693
  * One open file, in whatever state its read got to.
479
694
  *
@@ -610,7 +825,7 @@ declare const initialOpenFilesState: OpenFilesState;
610
825
  */
611
826
  declare function openFilesReducer(state: OpenFilesState, action: OpenFilesAction): OpenFilesState;
612
827
  //#endregion
613
- //#region src/use-open-files.d.ts
828
+ //#region src/hooks/use-open-files.d.ts
614
829
  type UseOpenFilesResult = OpenFilesState & {
615
830
  /** The focused file, resolved — what the editor renders. */active: OpenFile | undefined; /** Any tab with unsaved edits — what a close or unload guard asks. */
616
831
  hasUnsaved: boolean; /** Open a path, or focus it if it is already open. */
@@ -645,7 +860,7 @@ type UseOpenFilesResult = OpenFilesState & {
645
860
  */
646
861
  declare function useOpenFiles(client: WorkerDeckClient): UseOpenFilesResult;
647
862
  //#endregion
648
- //#region src/tool-host.d.ts
863
+ //#region src/lib/tool-host.d.ts
649
864
  /** What the host was asked to do and how it went (for UI/telemetry). */
650
865
  type ToolHostExecution = {
651
866
  executionId: string;
@@ -698,7 +913,7 @@ declare function createToolCallHost(handle: SessionHandle, options?: ToolCallHos
698
913
  dispose: () => void;
699
914
  };
700
915
  //#endregion
701
- //#region src/use-tool-host.d.ts
916
+ //#region src/hooks/use-tool-host.d.ts
702
917
  type UseToolCallHostOptions = ToolCallHostOptions & {
703
918
  /** Turn the host off without unmounting. Default true. */enabled?: boolean; /** How many recent executions to keep for rendering. Default 50. */
704
919
  historyLimit?: number;
@@ -712,7 +927,7 @@ declare function useToolCallHost(handle: SessionHandle | undefined, options?: Us
712
927
  executions: ToolHostExecution[];
713
928
  };
714
929
  //#endregion
715
- //#region src/recap.d.ts
930
+ //#region src/lib/recap.d.ts
716
931
  /**
717
932
  * "What happened while you were away", counted rather than written.
718
933
  *
@@ -764,5 +979,5 @@ declare function summarizeSince(state: RecapInput, fromIndex: number): RecapSumm
764
979
  */
765
980
  declare function recapLine(summary: RecapSummary): string | undefined;
766
981
  //#endregion
767
- export { type AttachmentKind, type ConnectionState, type HostDirState, type HostTreeRow, type OpenFile, type OpenFilesAction, type OpenFilesState, type ProducedFileRef, type PromptToken, type RecapInput, type RecapSummary, type StagedAttachment, type ToolCallHostOptions, type ToolHostExecution, type ToolHostRunner, type TranscriptItem, type TranscriptState, type UseAttachmentsOptions, type UseAttachmentsResult, type UseClaudeSessionOptions, type UseClaudeSessionResult, type UseHostFileRootsResult, type UseHostFileSearchResult, type UseHostFileTreeResult, type UseOpenFilesResult, type UseSessionInfoResult, type UseToolCallHostOptions, ancestorsWithin, applyEvent, attachmentKind, createToolCallHost, currentText, flattenHostTree, initialOpenFilesState, initialTranscriptState, isDirty, openFilesReducer, rateLimitWindows, recapLine, scanPromptTokens, seedFromSessionInfo, summarizeSince, useAttachments, useClaudeSession, useHostFileRoots, useHostFileSearch, useHostFileTree, useOpenFiles, useSessionInfo, useToolCallHost };
982
+ export { type AttachmentKind, type ClientForHost, type ConnectionState, type HostDirState, type HostTreeRow, type OpenFile, type OpenFilesAction, type OpenFilesState, type ProducedFileRef, type PromptToken, REPLAY_HOLD_MAX_MS, type RecapInput, type RecapSummary, type StagedAttachment, type ToolCallHostOptions, type ToolHostExecution, type ToolHostRunner, type TranscriptItem, type TranscriptState, type UseAttachmentsOptions, type UseAttachmentsResult, type UseClaudeSessionOptions, type UseClaudeSessionResult, type UseHostFileRootsResult, type UseHostFileSearchResult, type UseHostFileTreeResult, type UseOpenFilesResult, type UseProfileUsageOptions, type UseProfileUsageResult, type UseSessionInfoResult, type UseToolCallHostOptions, ancestorsWithin, applyEvent, attachmentKind, clearTranscriptCache, createToolCallHost, currentText, flattenHostTree, hydrateToolResult, initialOpenFilesState, initialReplayTarget, initialTranscriptState, isDirty, openFilesReducer, rateLimitWindows, recapLine, scanPromptTokens, seedFromSessionInfo, staleAttach, summarizeSince, useAttachments, useClaudeSession, useHostFileRoots, useHostFileSearch, useHostFileTree, useOpenFiles, useProfileUsage, useProjectIcons, useSessionInfo, useToolCallHost };
768
983
  //# sourceMappingURL=index.d.mts.map