dsh-context 0.43.0 → 0.44.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.
Files changed (4) hide show
  1. package/lib/client.js +1044 -562
  2. package/lib/index.d.ts +171 -24
  3. package/lib/index.js +830 -251
  4. package/package.json +6 -4
package/lib/index.d.ts CHANGED
@@ -16,6 +16,8 @@ interface Config {
16
16
  maxNodes?: number;
17
17
  /** Removed (shadowed) surface nodes kept for per-step reconstruction. */
18
18
  maxArchiveNodes?: number;
19
+ /** Fold-derived file-operation records kept (the File Activity card's raw material). */
20
+ maxFileOps?: number;
19
21
  }
20
22
  /**
21
23
  * The cordis `Config` validator: strict on keys, defaults on the schema fields; tolerates `undefined` (a patch row without a `config:`
@@ -27,6 +29,7 @@ declare const Config: z.ZodPreprocess<z.ZodObject<{
27
29
  maxEvents: z.ZodDefault<z.ZodNumber>;
28
30
  maxNodes: z.ZodDefault<z.ZodNumber>;
29
31
  maxArchiveNodes: z.ZodDefault<z.ZodNumber>;
32
+ maxFileOps: z.ZodDefault<z.ZodNumber>;
30
33
  }, z.core.$strict>>;
31
34
  //#endregion
32
35
  //#region src/host/headers.d.ts
@@ -103,6 +106,15 @@ interface TimelineState {
103
106
  */
104
107
  cost?: SessionCostUsage;
105
108
  archiveFloor?: number;
109
+ /**
110
+ * The detail collections' revision marker (see ContextTimelineDetail):
111
+ * bumped by every fold that mutates the request records, context events,
112
+ * live surface, or the removed-node archive — the slim wire head carries
113
+ * it so an open tab knows its fetched detail went stale. Absent until the
114
+ * first detail fold (undefined reads as 0; never materialize an
115
+ * `undefined`-valued property — the plain-JSON precondition above).
116
+ */
117
+ detailRev?: number;
106
118
  /**
107
119
  * Whole-session timing totals (see TimingTotals) — running sums over the
108
120
  * COMPLETE session log, like `cost`. Absent until the first step or tool
@@ -126,16 +138,18 @@ interface TimelineState {
126
138
  firstToken?: number;
127
139
  };
128
140
  /**
129
- * Tool callId → the call's name and start instant, armed by `tool/call` and
130
- * DELETED when its `tool/result` folds in (one result per call, in log
131
- * order) — the map stays at pending-call size instead of growing for the
132
- * session's whole lifetime (it is persisted state, shallow-copied by every
133
- * fold step). The start instant prices the call's duration into
134
- * `timing.toolsMs` when the result arrives.
141
+ * Tool callId → the call's name, start instant, and raw arguments, armed by
142
+ * `tool/call` and DELETED when its `tool/result` folds in (one result per
143
+ * call, in log order) — the map stays at pending-call size instead of
144
+ * growing for the session's whole lifetime (it is persisted state,
145
+ * shallow-copied by every fold step). The start instant prices the call's
146
+ * duration into `timing.toolsMs` when the result arrives; the raw arguments
147
+ * feed the file-op derivation (shared/fileOps.ts) at that same moment.
135
148
  */
136
149
  callNames: Record<string, {
137
150
  name: string;
138
151
  start: number;
152
+ argsRaw?: string;
139
153
  }>;
140
154
  /**
141
155
  * Seq list of the surface nodes the next replacement will shadow, armed by
@@ -156,16 +170,39 @@ interface TimelineState {
156
170
  * arm/remove lifecycle as `pendingShadowedSeqs`.
157
171
  */
158
172
  pendingShadowEventSeq?: number;
173
+ /**
174
+ * The fold-derived file-operation log (the File Activity card's raw
175
+ * material, shared/fileOps.ts): one record per executed file op, appended
176
+ * in log order — at `tool/result` (the armed call's arguments + the
177
+ * result's meta) and at a run_code result's flush of its nested
178
+ * dispatches. Bounded by `maxFileOps`; the trim stamps `fileOpsFloor`.
179
+ */
180
+ fileOps: FileOpRecord[];
181
+ /** The newest dropped op's seq (the card's coverage floor for the served op log). */
182
+ fileOpsFloor?: number;
183
+ /**
184
+ * Nested Code-Mode ops buffered by their top run_code call id until the
185
+ * parent's result folds (the dispatch events land BEFORE it, and the ops'
186
+ * locate target is that result's seq). Flushed (and the key deleted) when
187
+ * the result with that callId folds; absent until the first dispatch books
188
+ * an op. Bounded by PENDING_CODE_OPS_MAX — a hostile log that never
189
+ * settles a run_code cannot grow it.
190
+ */
191
+ pendingCodeOps?: Record<string, FileOpRecord[]>;
159
192
  }
160
193
  //#endregion
161
194
  //#region src/shared/types.d.ts
162
195
  declare module '@deepseek-ai/dsh-session-projection/types' {
163
196
  interface SessionProjectionMap {
164
197
  /**
165
- * The plugin's whole-value context timeline: current composition,
166
- * per-request history, context events, and the model-visible surface.
167
- * The Host folds it from the session log; clients receive the finished
168
- * value (key absence = the plugin's host half is not composed).
198
+ * The plugin's context timeline: current composition, counters, and the
199
+ * headline anchor. Since the split generation the wire value is the SLIM
200
+ * head (every delivery channel session.list rows, control baselines,
201
+ * push frames carries it whole); the per-request history, context
202
+ * events, and the surface/archive collections ride the on-demand detail
203
+ * channel ({@link ContextTimelineDetail}, host/detail.ts). Channel-less
204
+ * hosts keep the inline generation (the collections stay in the value).
205
+ * Key absence = the plugin's host half is not composed.
169
206
  */
170
207
  contextTimeline: ContextTimeline;
171
208
  /**
@@ -184,6 +221,31 @@ declare module '@deepseek-ai/dsh-session-projection/types' {
184
221
  }
185
222
  }
186
223
  type Category = 'user' | 'inject' | 'assistant' | 'tool';
224
+ /**
225
+ * The stats board's count figures, precomputed host-side over the RETAINED
226
+ * request/event records (the same set the detail payload serves). Carried by
227
+ * the split-generation wire head so the board — and the Agent card's
228
+ * per-session request tally — never need the collections themselves.
229
+ * `steps` doubles as the retained request-record count.
230
+ */
231
+ interface TimelineCounts {
232
+ turns: number;
233
+ steps: number;
234
+ injects: number;
235
+ compactions: number;
236
+ prunes: number;
237
+ }
238
+ /**
239
+ * The newest retained request record's billing summary — the headline's
240
+ * derived-occupancy anchor (`prompt + surface movement since`), carried by
241
+ * the split-generation wire head so the headline never needs the request
242
+ * records themselves.
243
+ */
244
+ interface TimelineLast {
245
+ seq: number;
246
+ total: number;
247
+ prompt?: number;
248
+ }
187
249
  interface Snapshot {
188
250
  ok: boolean;
189
251
  /**
@@ -209,19 +271,6 @@ interface Snapshot {
209
271
  tool: number;
210
272
  total: number;
211
273
  };
212
- /**
213
- * Provider-anchored occupancy of the NEXT request. LEGACY since 0.11: the
214
- * Host no longer folds this — the Client reads the official token-meter
215
- * `contextPressure` projection key (`useProjection('contextPressure')`)
216
- * instead. Kept optional for wire compatibility with older clients.
217
- */
218
- occupancy?: {
219
- pressureTokens?: number;
220
- surfaceTokens: number;
221
- sampledSurfaceTokens?: number;
222
- projectedTokens?: number;
223
- contextWindow?: number;
224
- };
225
274
  /**
226
275
  * Image blocks live in the CURRENT context (user uploads plus tool-result
227
276
  * images, nested blocks included) — the sum over the live surface nodes'
@@ -236,6 +285,23 @@ interface Snapshot {
236
285
  * hosts; clients treat absence as zero.
237
286
  */
238
287
  toolCalls?: number;
288
+ /**
289
+ * Split-generation head fields — present exactly when the host serves the
290
+ * SLIM head (the heavy collections moved to the on-demand detail channel,
291
+ * host/detail.ts) and absent on the inline generation (older or
292
+ * channel-less hosts serve the collections in place). `detailRev` is the
293
+ * detail's revision marker: it bumps whenever the detail collections
294
+ * change, so an open tab refetches on the push alone.
295
+ */
296
+ counts?: TimelineCounts;
297
+ last?: TimelineLast;
298
+ detailRev?: number;
299
+ /**
300
+ * The per-request history / context-event collections. On the split
301
+ * generation these stay ABSENT from the wire value (every session.list row,
302
+ * control baseline, and push frame would carry them whole otherwise); the
303
+ * client fills them from the detail channel ({@link ContextTimelineDetail}).
304
+ */
239
305
  requests: RequestRecord[];
240
306
  events: ContextEventRecord[];
241
307
  /**
@@ -276,6 +342,87 @@ interface Snapshot {
276
342
  * nodes (the browser shows the reconstruction as approximate).
277
343
  */
278
344
  archiveFloor?: number;
345
+ /**
346
+ * The fold-derived file-operation log and its trim floor — present on the
347
+ * INLINE wire value (channel-less hosts) and on the detail payload
348
+ * (ContextTimelineDetail), absent from the slim head (they ride the detail
349
+ * channel there).
350
+ */
351
+ fileOps?: FileOpRecord[];
352
+ fileOpsFloor?: number;
353
+ }
354
+ /**
355
+ * The on-demand DETAIL payload of the split `contextTimeline` generation —
356
+ * the heavy collections (per-request records, context events, the served
357
+ * surface window, and the removed-node archive) that the slim wire head no
358
+ * longer carries through every delivery channel. The host serves it off the
359
+ * live fold state at the `/dsh-context` `detail` endpoint (host/detail.ts);
360
+ * `rev` mirrors the head's `detailRev` at build time and acts as the
361
+ * client's latest-wins cursor.
362
+ */
363
+ interface ContextTimelineDetail {
364
+ rev: number;
365
+ requests: RequestRecord[];
366
+ events: ContextEventRecord[];
367
+ nodes: SurfaceNode[];
368
+ droppedNodes: number;
369
+ archive: SurfaceNode[];
370
+ surfaceFloor?: number;
371
+ archiveFloor?: number;
372
+ /**
373
+ * The fold-derived file-operation log (shared/fileOps.ts): one record per
374
+ * executed file op, newest-retained, covering the full log (never
375
+ * window-bound like the client-side join derivation it replaces on this
376
+ * generation). Code-Mode nested dispatches book ops located on their
377
+ * parent run_code result (`parent`).
378
+ */
379
+ fileOps?: FileOpRecord[];
380
+ /** The newest dropped op's seq when the op log trimmed (coverage honesty, same family as archiveFloor). */
381
+ fileOpsFloor?: number;
382
+ }
383
+ /**
384
+ * One executed file operation (a settled file-tool call with a resolved
385
+ * target), folded host-side from the durable tool lifecycle: the call's
386
+ * name+arguments (`tool/call`), the result's presentation meta and error
387
+ * (`tool/result`), or a nested Code-Mode settle (`tool/code-dispatch`,
388
+ * located on its parent run_code result via `parent` + `program`).
389
+ *
390
+ * `gone` is NOT host-stamped: the client joins it from the detail's archive
391
+ * at render time (the op's result node leaving the live surface marks where
392
+ * its content is still viewable). Line deltas are estimates read off the
393
+ * call ARGUMENTS (an edit's old/new strings, a write's content), never off
394
+ * result payloads.
395
+ */
396
+ interface FileOpRecord {
397
+ seq: number;
398
+ /** The op's file; for a pathless search the searched PATTERN (`pattern: true`). */
399
+ path: string;
400
+ kind: 'read' | 'write' | 'search';
401
+ tool: string;
402
+ time?: number;
403
+ err: boolean;
404
+ added: number;
405
+ removed: number;
406
+ /** What was searched for, when a search named both a path and a pattern. */
407
+ detail?: string;
408
+ /** Meta-attributed search op only: matched lines the result reported for this file. */
409
+ hits?: number;
410
+ /** Read ops only: the exact 1-based window the result meta reported, else the `limit`-argument estimate (`est: true`). */
411
+ read?: {
412
+ start: number;
413
+ count: number;
414
+ } | {
415
+ count: number;
416
+ est: true;
417
+ };
418
+ /** Nested Code-Mode op only: the run_code result node the op ran under (the locate target). */
419
+ parent?: number;
420
+ /** Nested Code-Mode op only: the run_code program's model-authored description. */
421
+ program?: string;
422
+ /** The searched-pattern marker: `path` is a pattern, not a file — display must not relativize it. */
423
+ pattern?: true;
424
+ /** Client-joined archive stamp (see the type note); absent on the wire. */
425
+ gone?: number;
279
426
  }
280
427
  /**
281
428
  * The `contextTimeline` projection's whole value — the same snapshot the Client has always rendered. `ok` is always `true` here (a
@@ -461,4 +608,4 @@ declare const name = "dsh-context";
461
608
  declare const inject: string[];
462
609
  declare function apply(ctx: Context, config: Config): void;
463
610
  //#endregion
464
- export { type Category, Config, type ContextEventRecord, type ContextHeaders, type ContextTimeline, type HeaderRecord, type HeaderTool, type HeadersState, type RequestRecord, type Snapshot, type SurfaceNode, type TimelineState, apply, inject, name };
611
+ export { type Category, Config, type ContextEventRecord, type ContextHeaders, type ContextTimeline, type ContextTimelineDetail, type HeaderRecord, type HeaderTool, type HeadersState, type RequestRecord, type Snapshot, type SurfaceNode, type TimelineCounts, type TimelineLast, type TimelineState, apply, inject, name };