@khorsheed/dsh-file-preview 0.1.1 → 0.2.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.
@@ -93,7 +93,7 @@ export const TYPERT = {
93
93
  typeSymbol: '@khorsheed/dsh-file-preview/types#FilePreviewList',
94
94
  schema: _khorsheed_dsh_file_preview_filePreview_list_result$schema,
95
95
  },
96
- sourceLocation: {"file":"packages/file-preview/src/index.ts","line":316,"column":3},
96
+ sourceLocation: {"file":"packages/file-preview/src/index.ts","line":368,"column":9},
97
97
  },
98
98
  {
99
99
  id: '@khorsheed/dsh-file-preview#filePreview/read',
@@ -134,7 +134,7 @@ export const TYPERT = {
134
134
  typeSymbol: '@khorsheed/dsh-file-preview/types#FilePreviewRead',
135
135
  schema: _khorsheed_dsh_file_preview_filePreview_read_result$schema,
136
136
  },
137
- sourceLocation: {"file":"packages/file-preview/src/index.ts","line":392,"column":9},
137
+ sourceLocation: {"file":"packages/file-preview/src/index.ts","line":458,"column":9},
138
138
  },
139
139
  {
140
140
  id: '@khorsheed/dsh-file-preview#filePreview/reveal',
@@ -175,7 +175,7 @@ export const TYPERT = {
175
175
  typeSymbol: '@khorsheed/dsh-file-preview/types#FilePreviewReveal',
176
176
  schema: _khorsheed_dsh_file_preview_filePreview_reveal_result$schema,
177
177
  },
178
- sourceLocation: {"file":"packages/file-preview/src/index.ts","line":469,"column":9},
178
+ sourceLocation: {"file":"packages/file-preview/src/index.ts","line":535,"column":9},
179
179
  },
180
180
  {
181
181
  id: '@khorsheed/dsh-file-preview#filePreview/turnFiles',
@@ -205,32 +205,32 @@ export const TYPERT = {
205
205
  typeSymbol: '@khorsheed/dsh-file-preview/types#FilePreviewTurnMap',
206
206
  schema: _khorsheed_dsh_file_preview_filePreview_turnFiles_result$schema,
207
207
  },
208
- sourceLocation: {"file":"packages/file-preview/src/index.ts","line":347,"column":3},
208
+ sourceLocation: {"file":"packages/file-preview/src/index.ts","line":405,"column":9},
209
209
  },
210
210
  ],
211
211
  model: {
212
212
  "services": [
213
213
  {
214
- "description": "The `filePreview` Remote service: session-scoped read-only file inspection for web surfaces. `list` is a pure fold over the session log (no filesystem access); `read` resolves the path against the session cwd and serves current text content through `ctx.fs` (or a browser URL for images), capped by config. Image bytes ride a dedicated host route so the browser loads them natively without bloating the RPC channel.",
214
+ "description": "The `filePreview` Remote service: session-scoped read-only file inspection for web surfaces. `list` is a fold over the session log, then filtered to the paths that still exist on disk (resolved against the session cwd and stat-ed per call); `read` resolves the path against the session cwd and serves current text content through `ctx.fs` (or a browser URL for images), capped by config. Image bytes ride a dedicated host route so the browser loads them natively without bloating the RPC channel.",
215
215
  "summary": "The `filePreview` Remote service: session-scoped read-only file inspection for web surfaces.",
216
216
  "tags": [],
217
- "jsDoc": "/**\n * The `filePreview` Remote service: session-scoped read-only file inspection\n * for web surfaces. `list` is a pure fold over the session log (no filesystem\n * access); `read` resolves the path against the session cwd and serves current\n * text content through `ctx.fs` (or a browser URL for images), capped by\n * config. Image bytes ride a dedicated host route so the browser loads them\n * natively without bloating the RPC channel.\n */",
217
+ "jsDoc": "/**\n * The `filePreview` Remote service: session-scoped read-only file inspection\n * for web surfaces. `list` is a fold over the session log, then filtered to the\n * paths that still exist on disk (resolved against the session cwd and stat-ed\n * per call); `read` resolves the path against the session cwd and serves current\n * text content through `ctx.fs` (or a browser URL for images), capped by\n * config. Image bytes ride a dedicated host route so the browser loads them\n * natively without bloating the RPC channel.\n */",
218
218
  "key": "filePreview",
219
219
  "exportName": "FilePreviewService",
220
220
  "members": [
221
221
  {
222
222
  "kind": "method",
223
223
  "name": "list",
224
- "signature": "@Remote('list') list(agent: Agent): FilePreviewList",
224
+ "signature": "@Remote('list') async list(agent: Agent): Promise<FilePreviewList>",
225
225
  "summary": "List the files one session wrote or edited: the log fold plus any bash-written files the collector verified (the S2 seam), merged so a captured path the fold already knows keeps its log-derived entry.",
226
- "jsDoc": "/**\n * List the files one session wrote or edited: the log fold plus any\n * bash-written files the collector verified (the S2 seam), merged so a\n * captured path the fold already knows keeps its log-derived entry.\n * @param agent - owning live agent; its session log is the data source.\n * @returns first-seen files capped by `maxFiles`, with the log watermark.\n */"
226
+ "jsDoc": "/**\n * List the files one session wrote or edited: the log fold plus any\n * bash-written files the collector verified (the S2 seam), merged so a\n * captured path the fold already knows keeps its log-derived entry. Only\n * paths that currently exist on disk are returned — a file the session\n * wrote and later deleted is history, not a product.\n * @param agent - owning live agent; its session log is the data source.\n * @returns existing first-seen files capped by `maxFiles`, with the log watermark.\n */"
227
227
  },
228
228
  {
229
229
  "kind": "method",
230
230
  "name": "turnFiles",
231
- "signature": "@Remote('turnFiles') turnFiles(agent: Agent): FilePreviewTurnMap",
231
+ "signature": "@Remote('turnFiles') async turnFiles(agent: Agent): Promise<FilePreviewTurnMap>",
232
232
  "summary": "Every turn's file mutations for the turn-tail card — the single source of truth the card renders (the client's old write/edit-only fold retired).",
233
- "jsDoc": "/**\n * Every turn's file mutations for the turn-tail card — the single source of\n * truth the card renders (the client's old write/edit-only fold retired).\n * Built by folding the session log per turn (write/edit calls, Code Mode\n * dispatches borrowing the root call's turn, and render-intent paths from\n * result diff meta) and merging the collector's bash-written captures by\n * their own turn. The fold is cached per session and invalidated by the log\n * watermark, so repeated card fetches do not refold. A path touched in two\n * turns appears in BOTH turn groups — per-turn attribution is exact.\n * @param agent - owning live agent; its session log is the data source.\n * @returns per-turn file groups plus the scanned watermark.\n */"
233
+ "jsDoc": "/**\n * Every turn's file mutations for the turn-tail card — the single source of\n * truth the card renders (the client's old write/edit-only fold retired).\n * Built by folding the session log per turn (write/edit calls, Code Mode\n * dispatches borrowing the root call's turn, and render-intent paths from\n * result diff meta) and merging the collector's bash-written captures by\n * their own turn. The fold is cached per session and invalidated by the log\n * watermark, so repeated card fetches do not refold. A path touched in two\n * turns appears in BOTH turn groups — per-turn attribution is exact. Only\n * paths that currently exist on disk are returned (a deleted temp script is\n * history, not a product); existence is probed fresh on every call, so the\n * cached fold is filtered per request rather than cached.\n * @param agent - owning live agent; its session log is the data source.\n * @returns existing per-turn file groups plus the scanned watermark.\n */"
234
234
  },
235
235
  {
236
236
  "kind": "method",
@@ -256,9 +256,13 @@ export const TYPERT = {
256
256
  "name": "AgentCancelCause",
257
257
  "declaration": "export type AgentCancelCause = { readonly kind: 'user'; } | { readonly kind: 'parent'; } | { readonly kind: 'hook'; readonly reason: string; } | { readonly kind: 'disposed'; };"
258
258
  },
259
+ {
260
+ "name": "AgentMessageSource",
261
+ "declaration": "export interface AgentMessageSource {\n readonly kind: 'agent-message';\n readonly form: 'relay';\n readonly senderSessionId: SessionId;\n}"
262
+ },
259
263
  {
260
264
  "name": "AgentOptions",
261
- "declaration": "export interface AgentOptions {\n provider?: string;\n model?: string;\n maxTokens?: number;\n subagentDepth?: number;\n}"
265
+ "declaration": "export interface AgentOptions {\n provider?: string;\n model?: string;\n reasoningEffort?: ReasoningEffortId;\n maxTokens?: number;\n subagentDepth?: number;\n}"
262
266
  },
263
267
  {
264
268
  "name": "AgentStatus",
@@ -293,21 +297,13 @@ export const TYPERT = {
293
297
  "declaration": "export type Branded<B extends string> = string & { readonly [BRAND]: B; };"
294
298
  },
295
299
  {
296
- "name": "CallId",
297
- "declaration": "export type CallId = Branded<'CallId'>;"
300
+ "name": "BrandedNumber",
301
+ "declaration": "export type BrandedNumber<B extends string> = number & { readonly [BRAND]: B; };"
298
302
  },
299
303
  {
300
304
  "name": "CancelOptions",
301
305
  "declaration": "export interface CancelOptions {\n keepInbox?: boolean | undefined;\n}"
302
306
  },
303
- {
304
- "name": "CodeDispatchEventData",
305
- "declaration": "export interface CodeDispatchEventData extends CodeDispatchStartEventData {\n isError: boolean;\n content: ContentBlock[];\n}"
306
- },
307
- {
308
- "name": "CodeDispatchStartEventData",
309
- "declaration": "export interface CodeDispatchStartEventData {\n rootCallId: CallId;\n parentCallId: CallId;\n subCallId: CallId;\n name: string;\n arguments: unknown;\n}"
310
- },
311
307
  {
312
308
  "name": "CommandId",
313
309
  "declaration": "export type CommandId = Branded<'CommandId'>;"
@@ -342,11 +338,7 @@ export const TYPERT = {
342
338
  },
343
339
  {
344
340
  "name": "ContinuableSubagentDescriptorData",
345
- "declaration": "export interface ContinuableSubagentDescriptorData extends SubagentDescriptorBase {\n readonly mode: 'continuable';\n readonly label: string;\n readonly agentProvider?: string;\n readonly agentModel?: string;\n readonly persona?: string;\n readonly toolFilter?: ToolRestriction;\n}"
346
- },
347
- {
348
- "name": "CoordinatorMessageSource",
349
- "declaration": "export interface CoordinatorMessageSource {\n readonly kind: 'coordinator';\n readonly form: 'relay';\n readonly senderSessionId: SessionId;\n}"
341
+ "declaration": "export interface ContinuableSubagentDescriptorData extends SubagentDescriptorBase {\n readonly mode: 'continuable';\n readonly label: string;\n readonly agentProvider?: string;\n readonly agentModel?: string;\n readonly agentReasoningEffort?: ReasoningEffortId;\n readonly persona?: string;\n readonly toolFilter?: ToolRestriction;\n}"
350
342
  },
351
343
  {
352
344
  "name": "EpochHeader",
@@ -450,7 +442,7 @@ export const TYPERT = {
450
442
  },
451
443
  {
452
444
  "name": "MessageSourceMap",
453
- "declaration": "export interface MessageSourceMap {\n user: { kind: 'user'; };\n plugin: { kind: 'plugin'; plugin: string; } & ContextFormed;\n model: ModelMessageSource;\n tool: ToolMessageSource;\n coordinator: CoordinatorMessageSource;\n 'subagent-report': SubagentReportMessageSource;\n 'subagent-settled': SubagentSettledMessageSource;\n}"
445
+ "declaration": "export interface MessageSourceMap {\n user: { kind: 'user'; };\n plugin: { kind: 'plugin'; plugin: string; } & ContextFormed;\n model: ModelMessageSource;\n tool: ToolMessageSource;\n 'agent-message': AgentMessageSource;\n 'subagent-settled': SubagentSettledMessageSource;\n}"
454
446
  },
455
447
  {
456
448
  "name": "ModelMessageSource",
@@ -464,6 +456,14 @@ export const TYPERT = {
464
456
  "name": "ProviderRequestId",
465
457
  "declaration": "export type ProviderRequestId = Branded<'ProviderRequestId'>;"
466
458
  },
459
+ {
460
+ "name": "PtcDispatchEventData",
461
+ "declaration": "export interface PtcDispatchEventData extends PtcDispatchStartEventData {\n isError: boolean;\n content: ContentBlock[];\n}"
462
+ },
463
+ {
464
+ "name": "PtcDispatchStartEventData",
465
+ "declaration": "export interface PtcDispatchStartEventData {\n rootCallId: ToolCallId;\n parentCallId: ToolCallId;\n subCallId: ToolCallId;\n name: string;\n arguments: unknown;\n}"
466
+ },
467
467
  {
468
468
  "name": "ReasoningBlock",
469
469
  "declaration": "export interface ReasoningBlock {\n type: 'reasoning';\n text: string;\n}"
@@ -482,7 +482,63 @@ export const TYPERT = {
482
482
  },
483
483
  {
484
484
  "name": "RequestHeaderReason",
485
- "declaration": "export type RequestHeaderReason = 'initial' | 'resume' | 'change';"
485
+ "declaration": "export type RequestHeaderReason = 'initial' | 'resume' | 'change' | 'series';"
486
+ },
487
+ {
488
+ "name": "RoomCreatedEvent",
489
+ "declaration": "export interface RoomCreatedEvent {\n readonly version: 1;\n}"
490
+ },
491
+ {
492
+ "name": "RoomDispatchEvent",
493
+ "declaration": "export interface RoomDispatchEvent {\n readonly targets: readonly string[];\n readonly text: string;\n}"
494
+ },
495
+ {
496
+ "name": "RoomGoalEvent",
497
+ "declaration": "export interface RoomGoalEvent {\n readonly text: string;\n}"
498
+ },
499
+ {
500
+ "name": "RoomJsonValue",
501
+ "declaration": "export type RoomJsonValue = null | boolean | number | string | RoomJsonValue[] | { [key: string]: RoomJsonValue; };"
502
+ },
503
+ {
504
+ "name": "RoomMemberAddedEvent",
505
+ "declaration": "export interface RoomMemberAddedEvent {\n readonly name: string;\n readonly kind: 'main-agent' | 'cli';\n readonly provider?: string;\n readonly instructions?: string;\n readonly invitedBy: 'human' | 'agent';\n readonly cwd?: string;\n readonly childSessionId?: SessionId;\n}"
506
+ },
507
+ {
508
+ "name": "RoomMemberRemovedEvent",
509
+ "declaration": "export interface RoomMemberRemovedEvent {\n readonly name: string;\n}"
510
+ },
511
+ {
512
+ "name": "RoomMemberUpdatedEvent",
513
+ "declaration": "export interface RoomMemberUpdatedEvent {\n readonly name: string;\n readonly rename?: string;\n readonly instructions?: string | null;\n readonly cwd?: string | null;\n readonly childSessionId?: SessionId;\n}"
514
+ },
515
+ {
516
+ "name": "RoomRelayEvent",
517
+ "declaration": "export interface RoomRelayEvent {\n readonly id: string;\n readonly from: string;\n readonly to: string;\n readonly content: string;\n readonly provenance?: Record<string, RoomJsonValue>;\n}"
518
+ },
519
+ {
520
+ "name": "RoomRelayResolvedEvent",
521
+ "declaration": "export interface RoomRelayResolvedEvent {\n readonly id: string;\n readonly state: 'confirmed' | 'dismissed' | 'sent';\n}"
522
+ },
523
+ {
524
+ "name": "RoomRunStateEvent",
525
+ "declaration": "export interface RoomRunStateEvent {\n readonly member: string;\n readonly state: 'running' | 'done' | 'cancelled' | 'failed';\n readonly startedAt: number;\n readonly elapsedMs?: number;\n readonly error?: string;\n}"
526
+ },
527
+ {
528
+ "name": "RoomSpeechEvent",
529
+ "declaration": "export interface RoomSpeechEvent {\n readonly member: string;\n readonly text: string;\n readonly childSessionId?: SessionId;\n readonly durationMs?: number;\n}"
530
+ },
531
+ {
532
+ "name": "RoomTaskAddedEvent",
533
+ "declaration": "export interface RoomTaskAddedEvent {\n readonly id: string;\n readonly member: string;\n readonly title: string;\n readonly status: 'pending' | 'in_progress';\n readonly blockedBy?: string;\n}"
534
+ },
535
+ {
536
+ "name": "RoomTaskEditedEvent",
537
+ "declaration": "export interface RoomTaskEditedEvent {\n readonly id: string;\n readonly title?: string;\n readonly blockedBy?: string | null;\n}"
538
+ },
539
+ {
540
+ "name": "RoomTaskUpdatedEvent",
541
+ "declaration": "export interface RoomTaskUpdatedEvent {\n readonly id: string;\n readonly status: 'in_progress' | 'done' | 'cancelled' | 'failed';\n}"
486
542
  },
487
543
  {
488
544
  "name": "SandboxMode",
@@ -490,15 +546,15 @@ export const TYPERT = {
490
546
  },
491
547
  {
492
548
  "name": "Session",
493
- "declaration": "export class Session {\n get surface(): SessionSurface;\n readonly header: SessionHeader;\n get id(): SessionId;\n readonly firstLiveSeq: number;\n get events(): readonly SessionEvent[];\n get seq(): number;\n append<T extends SessionEventType>(type: T, data: SessionEventMap[T], ...opts: T extends SurfaceEventType ? [opts: SurfaceIntent] : []): SessionEvent<T>;\n requestHeader(): EpochHeader | undefined;\n requestContext(): RequestContext | undefined;\n deriveMessages(): Message[];\n deriveEventMessage(event: SessionEvent): Message | null;\n}"
549
+ "declaration": "export class Session {\n get surface(): SessionSurface;\n readonly header: SessionHeader;\n readonly inheritedEventCount: SessionLogOffset;\n get id(): SessionId;\n readonly firstLiveSeq: SessionLogOffset;\n eventAt(seq: SessionSeq): SessionEvent | undefined;\n snapshotEvents(fromSeq: SessionLogOffset = SessionLogOffset(0), toSeqExclusive: SessionLogOffset = this.seq): readonly SessionEvent[];\n ownEvents(): readonly SessionEvent[];\n isOwnSeq(seq: SessionSeq): boolean;\n get seq(): SessionLogOffset;\n append<T extends SessionEventType>(type: T, data: SessionEventMap[T], ...opts: T extends SurfaceEventType ? [opts: SurfaceIntent] : []): SessionEvent<T>;\n requestHeader(): EpochHeader | undefined;\n requestContext(): RequestContext | undefined;\n deriveMessages(): Message[];\n deriveEventMessage(event: SessionEvent): Message | null;\n}"
494
550
  },
495
551
  {
496
552
  "name": "SessionEvent",
497
- "declaration": "export type SessionEvent<T extends SessionEventType = SessionEventType> = { [K in SessionEventType]: { type: K; seq: number; time: number; data: SessionEventMap[K]; ignorable?: true; } & (K extends SurfaceEventType ? { sourceEventSeqs?: number[]; surfaceOp?: SurfaceOp; } : object) }[T];"
553
+ "declaration": "export type SessionEvent<T extends SessionEventType = SessionEventType> = { [K in SessionEventType]: { type: K; seq: SessionSeq; time: number; data: SessionEventMap[K]; ignorable?: true; } & (K extends SurfaceEventType ? { sourceEventSeqs?: SessionSeq[]; surfaceOp?: SurfaceOp; } : object) }[T];"
498
554
  },
499
555
  {
500
556
  "name": "SessionEventMap",
501
- "declaration": "export interface SessionEventMap {\n 'turn/start': { turn: number; };\n 'turn/end': { turn: number; reason: TurnEndReason; };\n 'step/start': { turn: number; step: number; };\n 'step/end': { turn: number; step: number; };\n 'user/message': UserMessage;\n 'assistant/chunk': { turn: number; step: number; chunk: StreamChunk; };\n 'assistant/message': { turn: number; step: number; message: AssistantMessage; usage?: TokenUsage; interrupted?: true; };\n 'tool/call': { turn: number; step: number; callId: CallId; name: string; arguments: string; };\n 'tool/result': { turn: number; step: number; message: ToolResultMessage; error?: { name: string; code: string; }; meta?: JsonValue; };\n 'todo/write': { todos: TodoItem[]; };\n 'request/header': { header: EpochHeader; reason: RequestHeaderReason; };\n 'request/context': RequestContext;\n 'session/end-seed': Record<string, never>;\n 'agent/inbox/spliced': { target: InboxTarget; start: number; removedCount?: number; inserted: UserMessage[]; outcome?: 'canceled'; };\n 'command/run': { commandId: CommandId; name: string; args?: string; source: CommandSource; };\n 'command/done': { commandId: CommandId; kind: 'success' | 'error'; text?: string; sourceEventSeq?: number; };\n 'approval/asked': { id: ApprovalRequestId; toolName: string; callId?: CallId; reason?: string; };\n 'approval/decided': { id: ApprovalRequestId; outcome: ApprovalOutcome; };\n 'approval/policy': { policy: ApprovalPolicy; source?: 'delegation'; };\n 'tool/code-dispatch-start': CodeDispatchStartEventData;\n 'tool/code-dispatch': CodeDispatchEventData;\n 'subagent/descriptor': SubagentDescriptorData;\n 'sandbox/mode': { mode: SandboxMode; source?: 'delegation'; };\n 'agent-preset/selected': { agentPreset: string; };\n}"
557
+ "declaration": "export interface SessionEventMap {\n 'turn/start': { turn: number; };\n 'turn/end': { turn: number; reason: TurnEndReason; };\n 'step/start': { turn: number; step: number; };\n 'step/end': { turn: number; step: number; };\n 'user/message': UserMessage;\n 'assistant/chunk': { turn: number; step: number; chunk: StreamChunk; };\n 'assistant/message': { turn: number; step: number; message: AssistantMessage; usage?: TokenUsage; interrupted?: true; };\n 'tool/call': { turn: number; step: number; callId: ToolCallId; name: string; arguments: string; };\n 'tool/result': { turn: number; step: number; message: ToolResultMessage; error?: { name: string; code: string; }; meta?: JsonValue; };\n 'request/header': { header: EpochHeader; reason: RequestHeaderReason; startsSeries?: true; };\n 'request/context': RequestContext;\n 'session/end-seed': Record<string, never>;\n 'agent/inbox/spliced': { target: InboxTarget; start: number; removedCount?: number; inserted: UserMessage[]; outcome?: 'canceled'; };\n 'approval/asked': { id: ApprovalRequestId; toolName: string; callId?: ToolCallId; reason?: string; };\n 'approval/decided': { id: ApprovalRequestId; outcome: ApprovalOutcome; };\n 'approval/policy': { policy: ApprovalPolicy; source?: 'delegation'; };\n 'tool/code-dispatch-start': PtcDispatchStartEventData;\n 'tool/code-dispatch': PtcDispatchEventData;\n 'command/run': { commandId: CommandId; name: string; args?: string; source: CommandSource; };\n 'command/done': { commandId: CommandId; kind: 'success' | 'error'; text?: string; sourceEventSeq?: import('@deepseek-ai/dsh-session/types').SessionSeq; };\n 'subagent/descriptor': SubagentDescriptorData;\n 'session/title': SessionTitleEventData;\n 'todo/write': { todos: TodoItem[]; };\n 'sandbox/mode': { mode: SandboxMode; source?: 'delegation'; };\n 'agent-preset/selected': { agentPreset: string; };\n 'room/created': RoomCreatedEvent;\n 'room/member-added': RoomMemberAddedEvent;\n 'room/member-updated': RoomMemberUpdatedEvent;\n 'room/member-removed': RoomMemberRemovedEvent;\n 'room/dispatch': RoomDispatchEvent;\n 'room/speech': RoomSpeechEvent;\n 'room/run-state': RoomRunStateEvent;\n 'room/relay': RoomRelayEvent;\n 'room/relay-resolved': RoomRelayResolvedEvent;\n 'room/task-added': RoomTaskAddedEvent;\n 'room/task-updated': RoomTaskUpdatedEvent;\n 'room/task-edited': RoomTaskEditedEvent;\n 'room/goal': RoomGoalEvent;\n}"
502
558
  },
503
559
  {
504
560
  "name": "SessionEventType",
@@ -506,19 +562,43 @@ export const TYPERT = {
506
562
  },
507
563
  {
508
564
  "name": "SessionHeader",
509
- "declaration": "export interface SessionHeader {\n readonly version: number;\n readonly id: SessionId;\n readonly createdAt: number;\n readonly cwd?: string;\n readonly parentSession?: SessionId;\n readonly seedLength?: number;\n readonly origin?: 'subagent';\n readonly delegationDepth?: number;\n readonly agentPreset?: string;\n}"
565
+ "declaration": "export interface SessionHeader {\n readonly version: number;\n readonly id: SessionId;\n readonly createdAt: number;\n readonly cwd?: string;\n readonly parentSession?: SessionId;\n readonly isSeeded: boolean;\n readonly origin?: 'subagent';\n readonly delegationDepth?: number;\n readonly agentPreset?: string;\n}"
510
566
  },
511
567
  {
512
568
  "name": "SessionId",
513
569
  "declaration": "export type SessionId = Branded<'SessionId'>;"
514
570
  },
571
+ {
572
+ "name": "SessionLogOffset",
573
+ "declaration": "export type SessionLogOffset = BrandedNumber<'SessionLogOffset'>;"
574
+ },
575
+ {
576
+ "name": "SessionSeq",
577
+ "declaration": "export type SessionSeq = BrandedNumber<'SessionSeq'>;"
578
+ },
515
579
  {
516
580
  "name": "SessionSurface",
517
- "declaration": "export interface SessionSurface {\n readonly nodes: readonly number[];\n readonly replaceGeneration: number;\n}"
581
+ "declaration": "export interface SessionSurface {\n readonly nodes: readonly SessionSeq[];\n readonly replaceGeneration: number;\n}"
582
+ },
583
+ {
584
+ "name": "SessionTitleEventData",
585
+ "declaration": "export interface SessionTitleEventData {\n readonly title: string;\n readonly messageSeqs: SessionSeq[];\n readonly source: SessionTitleSource;\n}"
586
+ },
587
+ {
588
+ "name": "SessionTitleModelProvenance",
589
+ "declaration": "export interface SessionTitleModelProvenance {\n readonly provider: string;\n readonly model: string;\n}"
590
+ },
591
+ {
592
+ "name": "SessionTitleProviderId",
593
+ "declaration": "export type SessionTitleProviderId = Branded<'SessionTitleProviderId'>;"
594
+ },
595
+ {
596
+ "name": "SessionTitleSource",
597
+ "declaration": "export type SessionTitleSource = { readonly kind: 'fallback'; } | { readonly kind: 'provider'; readonly provider: SessionTitleProviderId; readonly model?: SessionTitleModelProvenance; } | { readonly kind: 'user'; };"
518
598
  },
519
599
  {
520
600
  "name": "StreamChunk",
521
- "declaration": "export type StreamChunk = { type: 'block-start'; index: number; blockType: ContentBlockType; } | { type: 'text-delta'; index: number; text: string; } | { type: 'reasoning-delta'; index: number; text: string; } | { type: 'tool-call-delta'; index: number; id: CallId; name?: string; argumentsDelta: string; } | { type: 'block-end'; index: number; block: ContentBlock; } | { type: 'usage'; usage: TokenUsage; } | { type: 'finish'; reason: FinishReason; replayState?: ReplayEnvelope; };"
601
+ "declaration": "export type StreamChunk = { type: 'block-start'; index: number; blockType: ContentBlockType; } | { type: 'text-delta'; index: number; text: string; } | { type: 'reasoning-delta'; index: number; text: string; } | { type: 'tool-call-delta'; index: number; id: ToolCallId; name?: string; argumentsDelta: string; } | { type: 'block-end'; index: number; block: ContentBlock; } | { type: 'usage'; usage: TokenUsage; } | { type: 'finish'; reason: FinishReason; replayState?: ReplayEnvelope; };"
522
602
  },
523
603
  {
524
604
  "name": "SubagentDescriptorBase",
@@ -528,10 +608,6 @@ export const TYPERT = {
528
608
  "name": "SubagentDescriptorData",
529
609
  "declaration": "export type SubagentDescriptorData = OneShotSubagentDescriptorData | ContinuableSubagentDescriptorData;"
530
610
  },
531
- {
532
- "name": "SubagentReportMessageSource",
533
- "declaration": "export interface SubagentReportMessageSource {\n readonly kind: 'subagent-report';\n readonly form: 'relay';\n readonly senderSessionId: SessionId;\n}"
534
- },
535
611
  {
536
612
  "name": "SubagentSettledMessageSource",
537
613
  "declaration": "export interface SubagentSettledMessageSource {\n readonly kind: 'subagent-settled';\n readonly form: 'notice';\n readonly summary: string;\n readonly senderSessionId: SessionId;\n}"
@@ -542,11 +618,11 @@ export const TYPERT = {
542
618
  },
543
619
  {
544
620
  "name": "SurfaceIntent",
545
- "declaration": "export interface SurfaceIntent {\n surfaceOp: SurfaceOp;\n sourceEventSeqs?: number[];\n}"
621
+ "declaration": "export interface SurfaceIntent {\n surfaceOp: SurfaceOp;\n sourceEventSeqs?: SessionSeq[];\n}"
546
622
  },
547
623
  {
548
624
  "name": "SurfaceOp",
549
- "declaration": "export type SurfaceOp = 'append' | { op: 'replace'; start: number; end: number; };"
625
+ "declaration": "export type SurfaceOp = 'append' | { op: 'replace'; start: SessionSeq; end: SessionSeq; };"
550
626
  },
551
627
  {
552
628
  "name": "TextBlock",
@@ -558,15 +634,19 @@ export const TYPERT = {
558
634
  },
559
635
  {
560
636
  "name": "TokenUsage",
561
- "declaration": "export interface TokenUsage {\n inputTokens: number;\n outputTokens: number;\n cacheReadTokens?: number;\n cacheWriteTokens?: number;\n reasoningTokens?: number;\n}"
637
+ "declaration": "export interface TokenUsage {\n inputTokens: number;\n outputTokens: number;\n totalTokens?: number;\n cacheReadTokens?: number;\n cacheWriteTokens?: number;\n reasoningTokens?: number;\n}"
562
638
  },
563
639
  {
564
640
  "name": "ToolCallBlock",
565
- "declaration": "export interface ToolCallBlock {\n type: 'tool-call';\n id: CallId;\n name: string;\n arguments: string;\n}"
641
+ "declaration": "export interface ToolCallBlock {\n type: 'tool-call';\n id: ToolCallId;\n name: string;\n arguments: string;\n}"
642
+ },
643
+ {
644
+ "name": "ToolCallId",
645
+ "declaration": "export type ToolCallId = Branded<'ToolCallId'>;"
566
646
  },
567
647
  {
568
648
  "name": "ToolMessageSource",
569
- "declaration": "export interface ToolMessageSource {\n kind: 'tool';\n callId: CallId;\n}"
649
+ "declaration": "export interface ToolMessageSource {\n kind: 'tool';\n callId: ToolCallId;\n}"
570
650
  },
571
651
  {
572
652
  "name": "ToolRestriction",
@@ -574,7 +654,7 @@ export const TYPERT = {
574
654
  },
575
655
  {
576
656
  "name": "ToolResultBlock",
577
- "declaration": "export interface ToolResultBlock {\n type: 'tool-result';\n toolCallId: CallId;\n content: ContentBlock[];\n isError?: boolean;\n}"
657
+ "declaration": "export interface ToolResultBlock {\n type: 'tool-result';\n toolCallId: ToolCallId;\n content: ContentBlock[];\n isError?: boolean;\n}"
578
658
  },
579
659
  {
580
660
  "name": "ToolResultMessage",
@@ -1 +1 @@
1
- {"version":3,"file":"typert.remote-client.d.ts","names":["list","read","reveal","turnFiles"],"sources":["../src/index.ts"],"sourcesContent":[null],"mappings":";;;;;;;;;;IA2TEA,I;IA4EMC,I;IA6EAC,M;IA1HNC,S;;;IA/BAH,kB;IA4EMC,kB;IA6EAC,oB;IA1HNC,uB;;;;;;IA/BAH,wB;IA4EMC,wB;IA6EAC,0B;IA1HNC,6B","ignoreList":[]}
1
+ {"version":3,"file":"typert.remote-client.d.ts","names":["list","read","reveal","turnFiles"],"sources":["../src/index.ts"],"sourcesContent":[null],"mappings":";;;;;;;;;;IA+WQA,I;IA0FAC,I;IA6EAC,M;IAlIAC,S;;;IArCAH,kB;IA0FAC,kB;IA6EAC,oB;IAlIAC,uB;;;;;;IArCAH,wB;IA0FAC,wB;IA6EAC,0B;IAlIAC,6B","ignoreList":[]}
@@ -90,7 +90,7 @@ export const TYPERT_REMOTE = {
90
90
  typeSymbol: '@khorsheed/dsh-file-preview/types#FilePreviewList',
91
91
  schema: _khorsheed_dsh_file_preview_filePreview_list_result$schema,
92
92
  },
93
- sourceLocation: {"file":"packages/file-preview/src/index.ts","line":316,"column":3},
93
+ sourceLocation: {"file":"packages/file-preview/src/index.ts","line":368,"column":9},
94
94
  },
95
95
  {
96
96
  id: '@khorsheed/dsh-file-preview#filePreview/read',
@@ -131,7 +131,7 @@ export const TYPERT_REMOTE = {
131
131
  typeSymbol: '@khorsheed/dsh-file-preview/types#FilePreviewRead',
132
132
  schema: _khorsheed_dsh_file_preview_filePreview_read_result$schema,
133
133
  },
134
- sourceLocation: {"file":"packages/file-preview/src/index.ts","line":392,"column":9},
134
+ sourceLocation: {"file":"packages/file-preview/src/index.ts","line":458,"column":9},
135
135
  },
136
136
  {
137
137
  id: '@khorsheed/dsh-file-preview#filePreview/reveal',
@@ -172,7 +172,7 @@ export const TYPERT_REMOTE = {
172
172
  typeSymbol: '@khorsheed/dsh-file-preview/types#FilePreviewReveal',
173
173
  schema: _khorsheed_dsh_file_preview_filePreview_reveal_result$schema,
174
174
  },
175
- sourceLocation: {"file":"packages/file-preview/src/index.ts","line":469,"column":9},
175
+ sourceLocation: {"file":"packages/file-preview/src/index.ts","line":535,"column":9},
176
176
  },
177
177
  {
178
178
  id: '@khorsheed/dsh-file-preview#filePreview/turnFiles',
@@ -202,7 +202,7 @@ export const TYPERT_REMOTE = {
202
202
  typeSymbol: '@khorsheed/dsh-file-preview/types#FilePreviewTurnMap',
203
203
  schema: _khorsheed_dsh_file_preview_filePreview_turnFiles_result$schema,
204
204
  },
205
- sourceLocation: {"file":"packages/file-preview/src/index.ts","line":347,"column":3},
205
+ sourceLocation: {"file":"packages/file-preview/src/index.ts","line":405,"column":9},
206
206
  },
207
207
  ],
208
208
  }
@@ -305,7 +305,7 @@ export class BashWriteCollector {
305
305
  #replay(session) {
306
306
  this.#pending.set(session.id, new Map());
307
307
  this.#captured.set(session.id, new Map());
308
- for (const event of session.events)
308
+ for (const event of session.snapshotEvents())
309
309
  this.#onEvent(session, event);
310
310
  }
311
311
  #onEvent(session, event) {
@@ -26,7 +26,8 @@ export declare function diffsFromResultMeta(meta: unknown): readonly FilePreview
26
26
  * first-seen order and deduplicated by display path; a later occurrence
27
27
  * refreshes the entry's op and location without moving it, and each write/edit
28
28
  * tool result appends its change's diff to the entry's `diffs` in event order.
29
- * Nested Code Mode file dispatches (`tool/code-dispatch` events) count too —
29
+ * Nested Code Mode file dispatches (`tool/code-dispatch` events, or
30
+ * `tool/ptc-dispatch` on seats running the PTC rename) count too —
30
31
  * they carry no turn/step of their own, so the entry borrows the enclosing
31
32
  * root call's location.
32
33
  * @param events - the session's events in ascending seq order.
@@ -55,11 +56,12 @@ export type TurnFilesByTurn = ReadonlyMap<number, ReadonlyMap<string, TurnFileFa
55
56
  * single source of truth. Unlike {@link foldFilePreview}, this does NOT dedupe
56
57
  * a path to its last occurrence: a file touched in two turns appears in BOTH
57
58
  * turn maps, so each turn's card lists exactly what that turn mutated.
58
- * write/edit calls register with their own turn; nested Code Mode dispatches
59
- * borrow the enclosing root call's turn (dispatch events carry none); a
60
- * `tool/result` whose presentation meta carries diffs registers its paths (the
61
- * render-intent vocabulary) with the result's turn, and per-turn line deltas
62
- * are summed from the diffs. A `write` whose result carries no diffs is a
59
+ * Reads leave no card entry (the card is the mutation vocabulary — write/edit
60
+ * only), so a pure-read call never registers; write/edit calls register with
61
+ * their own turn; nested Code Mode dispatches borrow the enclosing root call's
62
+ * turn (dispatch events carry none); a `tool/result` whose presentation meta
63
+ * carries diffs registers its paths (the render-intent vocabulary) with the
64
+ * result's turn, and per-turn line deltas are summed from the diffs. A `write` whose result carries no diffs is a
63
65
  * create (the write tool records no diffs when the file had no prior content):
64
66
  * its full written content — read from the call arguments, which the log keeps
65
67
  * — is the added-line count, once per file per turn.
@@ -1 +1 @@
1
- {"version":3,"file":"fold.d.ts","sourceRoot":"","sources":["../../src/fold.ts"],"names":[],"mappings":"AAAA,8GAA8G;AAE9G,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAG5D,OAAO,KAAK,EAAqC,eAAe,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAQnG,uEAAuE;AACvE,MAAM,WAAW,qBAAqB;IACpC,uCAAuC;IACvC,QAAQ,CAAC,EAAE,EAAE,aAAa,CAAA;IAC1B,uDAAuD;IACvD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CACtB;AAED,2EAA2E;AAC3E,MAAM,MAAM,qBAAqB,GAAG;IAClC,yEAAyE;IACzE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,4DAA4D;IAC5D,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,gCAAgC;IAChC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CACzB,CAAA;AAmBD,sFAAsF;AACtF,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,qBAAqB,GAAG,SAAS,CAOvG;AAED,8EAA8E;AAC9E,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,OAAO,GAAG,SAAS,qBAAqB,EAAE,GAAG,SAAS,CAc/F;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,SAAS,YAAY,EAAE,EAAE,QAAQ,EAAE,MAAM,GAAG,eAAe,CA8DlG;AAED,kGAAkG;AAClG,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAI9C;AAED,8EAA8E;AAC9E,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,uFAAuF;IACvF,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,4DAA4D;IAC5D,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;IACvB,4FAA4F;IAC5F,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAC1B;AAED,4FAA4F;AAC5F,MAAM,MAAM,eAAe,GAAG,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAA;AAuCpF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,YAAY,EAAE,GAAG,eAAe,CAyHtF"}
1
+ {"version":3,"file":"fold.d.ts","sourceRoot":"","sources":["../../src/fold.ts"],"names":[],"mappings":"AAAA,8GAA8G;AAE9G,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAG5D,OAAO,KAAK,EAAqC,eAAe,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAiBnG,uEAAuE;AACvE,MAAM,WAAW,qBAAqB;IACpC,uCAAuC;IACvC,QAAQ,CAAC,EAAE,EAAE,aAAa,CAAA;IAC1B,uDAAuD;IACvD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CACtB;AAED,2EAA2E;AAC3E,MAAM,MAAM,qBAAqB,GAAG;IAClC,yEAAyE;IACzE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,4DAA4D;IAC5D,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,gCAAgC;IAChC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CACzB,CAAA;AAmBD,sFAAsF;AACtF,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,qBAAqB,GAAG,SAAS,CAOvG;AAED,8EAA8E;AAC9E,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,OAAO,GAAG,SAAS,qBAAqB,EAAE,GAAG,SAAS,CAc/F;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,SAAS,YAAY,EAAE,EAAE,QAAQ,EAAE,MAAM,GAAG,eAAe,CAiElG;AAED,kGAAkG;AAClG,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAI9C;AAED,8EAA8E;AAC9E,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,uFAAuF;IACvF,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,4DAA4D;IAC5D,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;IACvB,4FAA4F;IAC5F,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAC1B;AAED,4FAA4F;AAC5F,MAAM,MAAM,eAAe,GAAG,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAA;AAuCpF;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,YAAY,EAAE,GAAG,eAAe,CAiItF"}
package/lib/types/fold.js CHANGED
@@ -1,6 +1,14 @@
1
1
  /** Pure log fold over the files a session read, wrote, or edited. @module @khorsheed/dsh-file-preview/fold */
2
2
  /** Tool names whose calls record a touched file path. */
3
3
  const FILE_TOOL_NAMES = new Set(['read', 'write', 'edit']);
4
+ /**
5
+ * Settled nested-dispatch event names, matched by name (feature detection,
6
+ * never a version check): `tool/code-dispatch` is the Code Mode name every
7
+ * host through 0.1.2-rc.1 emits; `tool/ptc-dispatch` is the PTC rename later
8
+ * 0.1.2 seats move to. Both carry the same settled-dispatch payload, so one
9
+ * branch serves either.
10
+ */
11
+ const DISPATCH_EVENT_NAMES = new Set(['tool/code-dispatch', 'tool/ptc-dispatch']);
4
12
  /** The argument key carrying the touched path (shared by all three file tools). */
5
13
  const FILE_PATH_ARGUMENT = 'file_path';
6
14
  /**
@@ -57,7 +65,8 @@ export function diffsFromResultMeta(meta) {
57
65
  * first-seen order and deduplicated by display path; a later occurrence
58
66
  * refreshes the entry's op and location without moving it, and each write/edit
59
67
  * tool result appends its change's diff to the entry's `diffs` in event order.
60
- * Nested Code Mode file dispatches (`tool/code-dispatch` events) count too —
68
+ * Nested Code Mode file dispatches (`tool/code-dispatch` events, or
69
+ * `tool/ptc-dispatch` on seats running the PTC rename) count too —
61
70
  * they carry no turn/step of their own, so the entry borrows the enclosing
62
71
  * root call's location.
63
72
  * @param events - the session's events in ascending seq order.
@@ -88,16 +97,19 @@ export function foldFilePreview(events, maxFiles) {
88
97
  record(target, event.seq, event.data.turn, event.data.step);
89
98
  continue;
90
99
  }
91
- if (event.type === 'tool/code-dispatch') {
100
+ if (DISPATCH_EVENT_NAMES.has(event.type)) {
92
101
  // The dispatch event IS the settled outcome: a failed sub-call changed
93
- // nothing, so only successful file touches record.
94
- if (event.data.isError)
102
+ // nothing, so only successful file touches record. The PTC rename keeps
103
+ // the code-dispatch payload shape (the ptc name has no SessionEventMap
104
+ // row yet), so the data reads through the declared constituent.
105
+ const dispatch = event;
106
+ if (dispatch.data.isError)
95
107
  continue;
96
- const target = targetFromArguments(event.data.name, event.data.arguments);
108
+ const target = targetFromArguments(dispatch.data.name, dispatch.data.arguments);
97
109
  if (target === undefined)
98
110
  continue;
99
- const site = callSites.get(String(event.data.rootCallId)) ?? { turn: 0, step: 0 };
100
- record(target, event.seq, site.turn, site.step);
111
+ const site = callSites.get(String(dispatch.data.rootCallId)) ?? { turn: 0, step: 0 };
112
+ record(target, dispatch.seq, site.turn, site.step);
101
113
  continue;
102
114
  }
103
115
  if (event.type === 'tool/result') {
@@ -172,11 +184,12 @@ function resultCallFacts(message) {
172
184
  * single source of truth. Unlike {@link foldFilePreview}, this does NOT dedupe
173
185
  * a path to its last occurrence: a file touched in two turns appears in BOTH
174
186
  * turn maps, so each turn's card lists exactly what that turn mutated.
175
- * write/edit calls register with their own turn; nested Code Mode dispatches
176
- * borrow the enclosing root call's turn (dispatch events carry none); a
177
- * `tool/result` whose presentation meta carries diffs registers its paths (the
178
- * render-intent vocabulary) with the result's turn, and per-turn line deltas
179
- * are summed from the diffs. A `write` whose result carries no diffs is a
187
+ * Reads leave no card entry (the card is the mutation vocabulary — write/edit
188
+ * only), so a pure-read call never registers; write/edit calls register with
189
+ * their own turn; nested Code Mode dispatches borrow the enclosing root call's
190
+ * turn (dispatch events carry none); a `tool/result` whose presentation meta
191
+ * carries diffs registers its paths (the render-intent vocabulary) with the
192
+ * result's turn, and per-turn line deltas are summed from the diffs. A `write` whose result carries no diffs is a
180
193
  * create (the write tool records no diffs when the file had no prior content):
181
194
  * its full written content — read from the call arguments, which the log keeps
182
195
  * — is the added-line count, once per file per turn.
@@ -257,6 +270,11 @@ export function foldFilePreviewByTurn(events) {
257
270
  const target = pathFromToolCall(event.data.name, event.data.arguments);
258
271
  if (target === undefined)
259
272
  continue;
273
+ // The card's vocabulary is mutations only: a read call registers
274
+ // nothing (it may still anchor a nested code dispatch's location via
275
+ // callSites above).
276
+ if (target.op === 'read')
277
+ continue;
260
278
  if (target.op === 'write') {
261
279
  const content = contentFromWriteCall(event.data.arguments);
262
280
  if (content !== undefined) {
@@ -268,19 +286,24 @@ export function foldFilePreviewByTurn(events) {
268
286
  recordLocation(target.path, event.data.turn, event.seq, event.data.step);
269
287
  continue;
270
288
  }
271
- if (event.type === 'tool/code-dispatch') {
289
+ if (DISPATCH_EVENT_NAMES.has(event.type)) {
272
290
  // The dispatch event IS the settled outcome: a failed sub-call changed
273
291
  // nothing, so only successful file touches record. Code Mode writes are
274
292
  // uncountable (no result diffs reach the session), so they register the
275
- // path and poison the line-count totals (unknown wins).
276
- if (event.data.isError)
293
+ // path and poison the line-count totals (unknown wins). Same payload
294
+ // shape caveat as foldFilePreview above.
295
+ const dispatch = event;
296
+ if (dispatch.data.isError)
277
297
  continue;
278
- const target = targetFromArguments(event.data.name, event.data.arguments);
298
+ const target = targetFromArguments(dispatch.data.name, dispatch.data.arguments);
279
299
  if (target === undefined)
280
300
  continue;
281
- const site = callSites.get(String(event.data.rootCallId)) ?? { turn: 0, step: 0 };
301
+ // Reads leave no card entry here too — only mutations register.
302
+ if (target.op === 'read')
303
+ continue;
304
+ const site = callSites.get(String(dispatch.data.rootCallId)) ?? { turn: 0, step: 0 };
282
305
  sessionSeen.add(target.path);
283
- recordContribution(target.path, site.turn, event.seq, site.step, undefined, undefined, true);
306
+ recordContribution(target.path, site.turn, dispatch.seq, site.step, undefined, undefined, true);
284
307
  continue;
285
308
  }
286
309
  if (event.type === 'tool/result') {
@@ -13,8 +13,9 @@ declare module '@deepseek-ai/cordis' {
13
13
  }
14
14
  /**
15
15
  * The `filePreview` Remote service: session-scoped read-only file inspection
16
- * for web surfaces. `list` is a pure fold over the session log (no filesystem
17
- * access); `read` resolves the path against the session cwd and serves current
16
+ * for web surfaces. `list` is a fold over the session log, then filtered to the
17
+ * paths that still exist on disk (resolved against the session cwd and stat-ed
18
+ * per call); `read` resolves the path against the session cwd and serves current
18
19
  * text content through `ctx.fs` (or a browser URL for images), capped by
19
20
  * config. Image bytes ride a dedicated host route so the browser loads them
20
21
  * natively without bloating the RPC channel.
@@ -55,14 +56,28 @@ export declare class FilePreviewService extends TypertRemoteService {
55
56
  * @param res - the response to fill with bytes or an error status.
56
57
  */
57
58
  private serveImage;
59
+ /** Resolve the session's recorded display paths against its cwd and keep only
60
+ * those that currently exist as a regular file. The products surfaces fold
61
+ * the session log (which is history, not disk state): a path the log wrote
62
+ * may have been cleaned up since (a temp script the turn deleted), and such
63
+ * a path is not a product to list. Existence is checked fresh on every call
64
+ * (never cached), so a deletion that lands after a fold is visible on the
65
+ * next fetch. Unresolvable/unstat-able paths are treated as absent.
66
+ * @param agent - owning live agent; its session cwd anchors relative paths.
67
+ * @param paths - the display paths to probe.
68
+ * @returns the subset that resolves to an existing regular file.
69
+ */
70
+ private retainExisting;
58
71
  /**
59
72
  * List the files one session wrote or edited: the log fold plus any
60
73
  * bash-written files the collector verified (the S2 seam), merged so a
61
- * captured path the fold already knows keeps its log-derived entry.
74
+ * captured path the fold already knows keeps its log-derived entry. Only
75
+ * paths that currently exist on disk are returned — a file the session
76
+ * wrote and later deleted is history, not a product.
62
77
  * @param agent - owning live agent; its session log is the data source.
63
- * @returns first-seen files capped by `maxFiles`, with the log watermark.
78
+ * @returns existing first-seen files capped by `maxFiles`, with the log watermark.
64
79
  */
65
- list(agent: Agent): FilePreviewList;
80
+ list(agent: Agent): Promise<FilePreviewList>;
66
81
  /**
67
82
  * Every turn's file mutations for the turn-tail card — the single source of
68
83
  * truth the card renders (the client's old write/edit-only fold retired).
@@ -71,11 +86,14 @@ export declare class FilePreviewService extends TypertRemoteService {
71
86
  * result diff meta) and merging the collector's bash-written captures by
72
87
  * their own turn. The fold is cached per session and invalidated by the log
73
88
  * watermark, so repeated card fetches do not refold. A path touched in two
74
- * turns appears in BOTH turn groups — per-turn attribution is exact.
89
+ * turns appears in BOTH turn groups — per-turn attribution is exact. Only
90
+ * paths that currently exist on disk are returned (a deleted temp script is
91
+ * history, not a product); existence is probed fresh on every call, so the
92
+ * cached fold is filtered per request rather than cached.
75
93
  * @param agent - owning live agent; its session log is the data source.
76
- * @returns per-turn file groups plus the scanned watermark.
94
+ * @returns existing per-turn file groups plus the scanned watermark.
77
95
  */
78
- turnFiles(agent: Agent): FilePreviewTurnMap;
96
+ turnFiles(agent: Agent): Promise<FilePreviewTurnMap>;
79
97
  /**
80
98
  * Read the current content of one recorded file, resolved against the
81
99
  * session cwd and capped by `maxReadBytes`.