dsh-context 0.55.0 → 0.56.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/lib/index.d.ts CHANGED
@@ -35,17 +35,6 @@ interface HeadersState {
35
35
  headers: StoredHeaderRecord[];
36
36
  }
37
37
  //#endregion
38
- //#region src/host/logShapes.d.ts
39
- /**
40
- * The decode bucket a stream's `block-start.blockType` names: the model's
41
- * thinking, the answer text, or the tool-call arguments. Undefined for an
42
- * unknown/hostile marker, whose interval then stays unattributed rather than
43
- * poisoning a bucket.
44
- */
45
- type DecodeKind = 'reasoning' | 'text' | 'toolarg';
46
- /** Per-kind count of opened decode blocks (see {@link decodeTallyOfStream}). */
47
- type DecodeCounts = Record<DecodeKind, number>;
48
- //#endregion
49
38
  //#region src/host/fold.d.ts
50
39
  /**
51
40
  * History retention bounds (configurable since 0.11 — see config.ts; these
@@ -63,9 +52,8 @@ interface TimelineState {
63
52
  sums: Record<Category, number>;
64
53
  systemTokens: number;
65
54
  /**
66
- * The live system-prompt nodes, oldest first — a V3 log's `system/message`
67
- * surface nodes, or the single entry a V0/V2 `request/header.header.system`
68
- * envelope defines. `systemTokens` is the LAST entry with tokens > 0 (the
55
+ * The live system-prompt nodes, oldest first — a log's `system/message`
56
+ * surface nodes. `systemTokens` is the LAST entry with tokens > 0 (the
69
57
  * harness's own "last nonempty surviving system" rule), so an empty dormant
70
58
  * node keeps its position without clearing the prompt. Bounded by
71
59
  * SYSTEM_NODES_MAX. ABSENT on rows folded before this field existed — the
@@ -73,16 +61,6 @@ interface TimelineState {
73
61
  * epoch's own envelope figure.
74
62
  */
75
63
  systems?: SystemPromptNode[];
76
- /**
77
- * Whether `systems` was built from the V0/V2 request ENVELOPE
78
- * (`header.system`) rather than from V3 `system/message` events. Only then
79
- * may a system-less header CLEAR the list: its canonical V0 meaning is
80
- * "this request has no system prompt", while a V3 header never carries one
81
- * (its prompt lives in the message history). Absent = log-sourced, and
82
- * never materialized as an `undefined`-valued property (plain-JSON
83
- * precondition — see the note above `model`).
84
- */
85
- systemsFromHeader?: true;
86
64
  toolsTokens: number;
87
65
  /**
88
66
  * The projection-cache precondition is plain JSON: a property whose value
@@ -162,31 +140,16 @@ interface TimelineState {
162
140
  /**
163
141
  * The open step's start instant, armed by `step/start` and consumed by the
164
142
  * `assistant/message` (TTFT/generation split) and `step/end` (wall time)
165
- * that follow it; `assistant/chunk` stamps `firstToken` on the step's first
166
- * token delta — absent when the stream carried none (legacy or aborted
167
- * steps), which leaves that call's model time unattributed. One slot, not a
168
- * map: steps are sequential in the log, so the newest `step/start` is the
169
- * one those events close — a hostile interleaved log degrades to skipped
170
- * durations, never to unbounded state. Same arm/remove lifecycle as
171
- * `pendingShadowedSeqs`.
172
- *
173
- * `decode`, `blocks` and `block` carry the generation split (reasoning /
174
- * answer text / tool arguments — see TimingTotals): a V0 log's
175
- * `assistant/chunk` `block-start` markers open `block`, close the previous
176
- * one into `decode`, and count the opened bucket into `blocks` (the card's
177
- * per-slice tally); a V2+ log carries no such events, so `decode` stays
178
- * absent and `assistant/message` reads the spans and counts off its embedded
179
- * stream instead.
143
+ * that follow it; the message's embedded stream stamps `firstToken` —
144
+ * absent when the stream carried none (an aborted step), which leaves that
145
+ * call's model time unattributed. One slot, not a map: steps are sequential
146
+ * in the log, so the newest `step/start` is the one those events close — a
147
+ * hostile interleaved log degrades to skipped durations, never to
148
+ * unbounded state. Same arm/remove lifecycle as `pendingShadowedSeqs`.
180
149
  */
181
150
  stepStart?: {
182
151
  time: number;
183
152
  firstToken?: number;
184
- decode?: Record<DecodeKind, number>;
185
- blocks?: DecodeCounts;
186
- block?: {
187
- kind: DecodeKind;
188
- since: number;
189
- };
190
153
  };
191
154
  /**
192
155
  * Tool callId → the call's name, start instant, and raw arguments, armed by
@@ -292,8 +255,7 @@ type Category = 'user' | 'inject' | 'skill' | 'assistant' | 'tool';
292
255
  /**
293
256
  * One live system-prompt node (Snapshot.systems) — the harness models the
294
257
  * system prompt as a surface node, so its TEXT is fetched on demand from the
295
- * event at `seq`: a V3 `system/message` event, or the V0/V2 `request/header`
296
- * whose envelope carried `header.system`. `tokens` is the node's heuristic
258
+ * `system/message` event at `seq`. `tokens` is the node's heuristic
297
259
  * price (0 for a dormant empty node, which the harness reads as "no system
298
260
  * prompt"); the effective figure is the LAST node with `tokens > 0`.
299
261
  */
@@ -452,9 +414,9 @@ interface Snapshot {
452
414
  timing?: TimingTotals;
453
415
  /**
454
416
  * The live system-prompt nodes, oldest first — the browser's per-step source
455
- * for the System section. Absent when the log carried no system prompt, and
456
- * on older plugin builds (the client then falls back to the header epoch's
457
- * own `systemTokens`, the pre-V3 shape).
417
+ * for the System section. Absent on rows folded before this field existed
418
+ * (older plugin builds; the client then falls back to the header epoch's
419
+ * own `systemTokens`, the legacy wire shape those builds served).
458
420
  */
459
421
  systems?: SystemPromptNode[];
460
422
  /**
@@ -536,7 +498,7 @@ interface ContextTimelineDetail {
536
498
  * One executed file operation (a settled file-tool call with a resolved
537
499
  * target), folded host-side from the durable tool lifecycle: the call's
538
500
  * name+arguments (`tool/call`), the result's presentation meta and error
539
- * (`tool/result`), or a nested Code-Mode settle (`tool/code-dispatch`,
501
+ * (`tool/result`), or a nested Code-Mode settle (`tool/ptc-dispatch`,
540
502
  * located on its parent run_code result via `parent` + `program`).
541
503
  *
542
504
  * `gone` is NOT host-stamped: the client joins it from the detail's archive
@@ -604,10 +566,9 @@ interface ToolTimingTotals {
604
566
  * Whole-session timing totals, host-folded from the durable `step/start` /
605
567
  * `step/end` / `tool/call` / `tool/result` lifecycle plus the model call's
606
568
  * first token (running totals over the COMPLETE session log — the same
607
- * never-trimmed framing as `cost`). The first token comes from a V0
608
- * `assistant/chunk` delta or from the call's own embedded stream
609
- * (`assistant/message.data.stream` / `assistant/attempt.data.stream`, the
610
- * V2+ settlement) — whichever the log carries, matching the harness's own
569
+ * never-trimmed framing as `cost`). The first token comes from the call's
570
+ * own embedded stream (`assistant/message.data.stream` /
571
+ * `assistant/attempt.data.stream`), matching the harness's own
611
572
  * session-stats fold. Durations are wall-clock milliseconds: `wallMs` sums
612
573
  * whole steps, `ttftMs` the step-start → first-token slice (the model wait)
613
574
  * and `genMs` the first-token → assistant-message slice (the generation) —
@@ -878,7 +839,33 @@ export interface Config {
878
839
  insightsEntry?: InsightsEntry;
879
840
  }
880
841
  /** The cordis `Config` validator and the Config-form generation's served schema. */
881
- export declare const Config: z$1<Config>;
842
+ export declare const Config: z$1<Schemastery.ObjectS<NoInfer<{
843
+ maxRequestSteps: z$1<number, number, Mode extends "volatile" | "volatile-defined" ? "volatile-defined" : "defined">;
844
+ maxKeptTurns: z$1<number, number, Mode extends "volatile" | "volatile-defined" ? "volatile-defined" : "defined">;
845
+ maxEvents: z$1<number, number, Mode extends "volatile" | "volatile-defined" ? "volatile-defined" : "defined">;
846
+ maxNodes: z$1<number, number, Mode extends "volatile" | "volatile-defined" ? "volatile-defined" : "defined">;
847
+ maxArchiveNodes: z$1<number, number, Mode extends "volatile" | "volatile-defined" ? "volatile-defined" : "defined">;
848
+ maxFileOps: z$1<number, number, Mode extends "volatile" | "volatile-defined" ? "volatile-defined" : "defined">;
849
+ defaultPlacement: z$1<"all" | "sidebar" | "tab", "all" | "sidebar" | "tab", Mode>;
850
+ defaultGranularity: z$1<"step" | "turn", "step" | "turn", Mode>;
851
+ defaultTrendMode: z$1<"delta" | "total", "delta" | "total", Mode>;
852
+ defaultToolSort: z$1<"count" | "name" | "size", "count" | "name" | "size", Mode>;
853
+ defaultFileSort: z$1<"count" | "latest" | "path", "count" | "latest" | "path", Mode>;
854
+ insightsEntry: z$1<"hide" | "show", "hide" | "show", Mode>;
855
+ }>>, Schemastery.ObjectT<NoInfer<{
856
+ maxRequestSteps: z$1<number, number, Mode extends "volatile" | "volatile-defined" ? "volatile-defined" : "defined">;
857
+ maxKeptTurns: z$1<number, number, Mode extends "volatile" | "volatile-defined" ? "volatile-defined" : "defined">;
858
+ maxEvents: z$1<number, number, Mode extends "volatile" | "volatile-defined" ? "volatile-defined" : "defined">;
859
+ maxNodes: z$1<number, number, Mode extends "volatile" | "volatile-defined" ? "volatile-defined" : "defined">;
860
+ maxArchiveNodes: z$1<number, number, Mode extends "volatile" | "volatile-defined" ? "volatile-defined" : "defined">;
861
+ maxFileOps: z$1<number, number, Mode extends "volatile" | "volatile-defined" ? "volatile-defined" : "defined">;
862
+ defaultPlacement: z$1<"all" | "sidebar" | "tab", "all" | "sidebar" | "tab", Mode>;
863
+ defaultGranularity: z$1<"step" | "turn", "step" | "turn", Mode>;
864
+ defaultTrendMode: z$1<"delta" | "total", "delta" | "total", Mode>;
865
+ defaultToolSort: z$1<"count" | "name" | "size", "count" | "name" | "size", Mode>;
866
+ defaultFileSort: z$1<"count" | "latest" | "path", "count" | "latest" | "path", Mode>;
867
+ insightsEntry: z$1<"hide" | "show", "hide" | "show", Mode>;
868
+ }>>, "plain">;
882
869
  //#endregion
883
870
  //#region src/host/index.d.ts
884
871
  export declare const name = "dsh-context";
package/lib/index.js CHANGED
@@ -330,30 +330,28 @@ function isInjection(source) {
330
330
  //#region src/host/logShapes.ts
331
331
  /**
332
332
  * Shape-driven readers over the durable session-event vocabulary — the ONE
333
- * place the plugin reconciles the two supported log generations:
333
+ * place the plugin's log spellings meet. The supported range (dsh
334
+ * 0.1.5-rc.1+, session formats V3/V4) speaks ONE dialect:
335
+ * `system/message` surface nodes, `assistant/message.data.stream` /
336
+ * `assistant/attempt.data.stream` (packed delta runs plus raw chunk
337
+ * records), `SurfaceOp { startSeq, endSeq }`, `tool/ptc-dispatch`.
334
338
  *
335
- * - V0 (dsh 0.1.2-rc.1): `request/header.header.system`, `assistant/chunk`
336
- * stream events, `SurfaceOp { start, end }`, `tool/code-dispatch`.
337
- * - V3 (dsh 0.1.5-alpha.x+): `system/message` surface nodes,
338
- * `assistant/message.data.stream` / `assistant/attempt.data.stream`,
339
- * `SurfaceOp { startSeq, endSeq }`, `tool/ptc-dispatch`.
340
- *
341
- * The fold reads SHAPES, never a detected harness version: a session log is
342
- * written by exactly one generation, the two spellings are mutually
343
- * exclusive within it, and a deployment's version probe can be wrong (a
344
- * healed profile mirror may name a different release than the running
345
- * harness). Every reader is total over untrusted input — a malformed record
346
- * yields "nothing here", never a throw (the projection registry drives the
347
- * fold without an error boundary; one throw stalls the unit's push feed and
348
- * the browser waits on "loading" forever).
339
+ * The fold still reads SHAPES, never a detected harness version: the raw log
340
+ * is untrusted input at every layer, and the supported harness refuses —
341
+ * never rewrites — a legacy-format log, so anything that reaches these
342
+ * readers is current-dialect or hostile. Every reader is total over
343
+ * untrusted input — a malformed record yields "nothing here", never a throw
344
+ * (the projection registry drives the fold without an error boundary; one
345
+ * throw stalls the unit's push feed and the browser waits on "loading"
346
+ * forever).
349
347
  *
350
348
  * @module dsh-context/host/log-shapes
351
349
  */
352
350
  /**
353
- * Whether one raw stream chunk carries a token delta — the first-token marker
354
- * both generations share. Mirrors dsh-llm's `isTokenDelta` (a non-empty text
355
- * or reasoning fragment, or any Tool-call delta carrying arguments or a name);
356
- * a malformed chunk is simply not a token.
351
+ * Whether one raw stream chunk carries a token delta — the first-token
352
+ * marker, mirroring dsh-llm's `isTokenDelta` (a non-empty text or reasoning
353
+ * fragment, or any Tool-call delta carrying arguments or a name); a
354
+ * malformed chunk is simply not a token.
357
355
  */
358
356
  function isTokenChunk(chunk) {
359
357
  if (chunk === null || typeof chunk !== "object") return false;
@@ -375,9 +373,7 @@ function decodeKindOfBlock(blockType) {
375
373
  * Per-kind decode spans AND counted `block-start` markers inside one embedded
376
374
  * assistant stream, tiling [first block-start, endTime]: each `block-start`
377
375
  * record owns the interval up to the next one, the last one up to `endTime`.
378
- * This is the V2+ shape, whose timed stream rides the settlement
379
- * (`assistant/message.data.stream`) instead of separate `assistant/chunk`
380
- * events. Total over untrusted input — a malformed record is skipped whole (a
376
+ * Total over untrusted input — a malformed record is skipped whole (a
381
377
  * marker with an unusable time anchors no span and counts nothing), a
382
378
  * non-finite boundary yields zero, and a stream with no marker (or not an
383
379
  * array) yields all zeros.
@@ -441,9 +437,8 @@ function runFirstTokenTime(record) {
441
437
  }
442
438
  /**
443
439
  * The first token's instant inside an embedded assistant stream
444
- * (`assistant/message.data.stream`, `assistant/attempt.data.stream` — the V2+
445
- * settlement that replaced the V0 `assistant/chunk` events), or undefined
446
- * when the stream carries no token. Mirrors dsh-llm's
440
+ * (`assistant/message.data.stream`, `assistant/attempt.data.stream`), or
441
+ * undefined when the stream carries no token. Mirrors dsh-llm's
447
442
  * `assistantStreamFirstTokenTime` over the compact record union.
448
443
  */
449
444
  function firstTokenTimeOfStream(stream) {
@@ -463,16 +458,14 @@ function firstTokenTimeOfStream(stream) {
463
458
  /**
464
459
  * The inclusive surface range a replacement op covers, or null for `append`
465
460
  * and for any unrecognized/hostile op (which the fold treats as an append).
466
- * Reads BOTH endpoint spellings: V3's `startSeq`/`endSeq` first, then V0's
467
- * `start`/`end` — each accepted only as a finite number, so a hostile op
468
- * with one good and one malformed endpoint degrades to append.
461
+ * The `startSeq`/`endSeq` endpoints are each accepted only as a finite
462
+ * number, so a hostile op with one malformed endpoint degrades to append.
469
463
  */
470
464
  function replaceRangeOf(surfaceOp) {
471
465
  if (surfaceOp === null || typeof surfaceOp !== "object") return null;
472
466
  const op = surfaceOp;
473
467
  if (op.op !== "replace") return null;
474
- const start = typeof op.startSeq === "number" ? op.startSeq : op.start;
475
- const end = typeof op.endSeq === "number" ? op.endSeq : op.end;
468
+ const { startSeq: start, endSeq: end } = op;
476
469
  if (typeof start !== "number" || !Number.isFinite(start)) return null;
477
470
  if (typeof end !== "number" || !Number.isFinite(end)) return null;
478
471
  return {
@@ -903,8 +896,10 @@ function removeSurfaceSeqs(st, claimed, goneSeq) {
903
896
  /**
904
897
  * The message nested under an event payload's `message` field
905
898
  * (`system/message`, `assistant/message`, `tool/result`) — read structurally
906
- * rather than through `deriveEventMessage`, whose 0.1.2-rc.1 generation knows
907
- * nothing of the V3 `system/message` variant. A malformed payload reads null.
899
+ * because the fold needs a TOTAL read over untrusted payloads: a malformed
900
+ * message reads null here, never throws or guesses a shape. Purely a type
901
+ * cast: `deriveEventMessage` returns `event.data` for a user/message (no
902
+ * `data.message` indirection), so its result feeds every other case.
908
903
  */
909
904
  function messageOf$1(data) {
910
905
  const message = data?.message;
@@ -1257,20 +1252,6 @@ function applyTimeline(state, event, bounds) {
1257
1252
  const tools = Array.isArray(header.tools) ? header.tools : [];
1258
1253
  const s = ensure(["events"]);
1259
1254
  s.toolsTokens = estimateToolsTotal(tools);
1260
- const systemText = header.system;
1261
- if (typeof systemText === "string" && systemText !== "") {
1262
- s.systems = [{
1263
- seq: event.seq,
1264
- time: event.time,
1265
- tokens: estimateSystemTokens(systemText)
1266
- }];
1267
- s.systemsFromHeader = true;
1268
- s.systemTokens = systemTokensOf(s.systems);
1269
- } else if (s.systemsFromHeader === true) {
1270
- s.systems = [];
1271
- delete s.systemsFromHeader;
1272
- s.systemTokens = 0;
1273
- }
1274
1255
  if (header.config && typeof header.config.model === "string") s.model = header.config.model;
1275
1256
  if (header.config && typeof header.config.provider === "string") s.provider = header.config.provider;
1276
1257
  if ((data?.reason === "change" || data?.reason === "resume") && s.model && s.lastModel && s.model !== s.lastModel) {
@@ -1301,7 +1282,6 @@ function applyTimeline(state, event, bounds) {
1301
1282
  for (const n of s.surface) if (n.seq >= op.start && n.seq <= op.end) claimed.add(n.seq);
1302
1283
  if (removeSurfaceSeqs(s, claimed, event.seq).length > 0) bumpDetailRev(s);
1303
1284
  }
1304
- delete s.systemsFromHeader;
1305
1285
  pushSystem(s, {
1306
1286
  seq: event.seq,
1307
1287
  time: event.time,
@@ -1327,7 +1307,6 @@ function applyTimeline(state, event, bounds) {
1327
1307
  };
1328
1308
  }
1329
1309
  break;
1330
- case "tool/code-dispatch":
1331
1310
  case "tool/ptc-dispatch": {
1332
1311
  const rootCallId = data?.rootCallId;
1333
1312
  const name = data?.name;
@@ -1344,47 +1323,6 @@ function applyTimeline(state, event, bounds) {
1344
1323
  }
1345
1324
  break;
1346
1325
  }
1347
- case "assistant/chunk": {
1348
- const start = state.stepStart;
1349
- if (start === void 0) return state;
1350
- const chunk = data?.chunk;
1351
- if (chunk !== null && typeof chunk === "object" && chunk.type === "block-start") {
1352
- const kind = decodeKindOfBlock(chunk.blockType);
1353
- if (start.block === void 0 && kind === void 0) return state;
1354
- const s = ensure([]);
1355
- const decode = { ...start.decode ?? {
1356
- reasoning: 0,
1357
- text: 0,
1358
- toolarg: 0
1359
- } };
1360
- if (start.block !== void 0) decode[start.block.kind] += durOf(start.block.since, event.time);
1361
- const blocks = { ...start.blocks ?? {
1362
- reasoning: 0,
1363
- text: 0,
1364
- toolarg: 0
1365
- } };
1366
- if (kind !== void 0) blocks[kind] += 1;
1367
- s.stepStart = {
1368
- time: start.time,
1369
- ...start.firstToken !== void 0 ? { firstToken: start.firstToken } : {},
1370
- decode,
1371
- blocks,
1372
- ...kind !== void 0 ? { block: {
1373
- kind,
1374
- since: event.time
1375
- } } : {}
1376
- };
1377
- break;
1378
- }
1379
- if (start.firstToken !== void 0) return state;
1380
- if (!isTokenChunk(data?.chunk)) return state;
1381
- const s = ensure([]);
1382
- s.stepStart = {
1383
- ...start,
1384
- firstToken: event.time
1385
- };
1386
- break;
1387
- }
1388
1326
  case "assistant/attempt": {
1389
1327
  const start = state.stepStart;
1390
1328
  if (start === void 0 || start.firstToken !== void 0) return state;
@@ -1426,7 +1364,7 @@ function applyTimeline(state, event, bounds) {
1426
1364
  seq: event.seq,
1427
1365
  time: event.time,
1428
1366
  kind: "inject",
1429
- form: source.form || "context",
1367
+ form: typeof source.form === "string" && source.form !== "" ? source.form : "context",
1430
1368
  tokens: node.tokens
1431
1369
  };
1432
1370
  if (source.kind === "skill-invocation") {
@@ -1565,14 +1503,8 @@ function applyTimeline(state, event, bounds) {
1565
1503
  timing.speedMs = (timing.speedMs ?? 0) + durOf(firstToken, event.time);
1566
1504
  timing.speedTokens = (timing.speedTokens ?? 0) + output;
1567
1505
  }
1568
- if (stepStart.decode !== void 0) {
1569
- const decode = { ...stepStart.decode };
1570
- if (stepStart.block !== void 0) decode[stepStart.block.kind] += durOf(stepStart.block.since, event.time);
1571
- for (const kind of DECODE_KINDS) addDecode(timing, kind, decode[kind], stepStart.blocks?.[kind] ?? 0);
1572
- } else {
1573
- const tally = decodeTallyOfStream(data?.stream, event.time);
1574
- for (const kind of DECODE_KINDS) addDecode(timing, kind, tally.spans[kind], tally.blocks[kind]);
1575
- }
1506
+ const tally = decodeTallyOfStream(data?.stream, event.time);
1507
+ for (const kind of DECODE_KINDS) addDecode(timing, kind, tally.spans[kind], tally.blocks[kind]);
1576
1508
  }
1577
1509
  }
1578
1510
  const asstMsg = deriveEventMessage(event);
@@ -2345,10 +2277,29 @@ function headerOf(record) {
2345
2277
  if (typeof header.id !== "string" || header.id === "") return null;
2346
2278
  return header;
2347
2279
  }
2280
+ /** The probe keys: the projection keys the cache must already serve. */
2281
+ const PROBE_KEYS = ["contextActivity", "contextTimeline"];
2282
+ /**
2283
+ * Probe the cache through the face the running generation serves. The older
2284
+ * spelling is tried first and the newer one answers the fallback: on a
2285
+ * 0.1.7-rc.2 cache the 3-arg call binds the branded offset onto `keys`,
2286
+ * where `new Set(0)` throws as soon as a served record is reached — while a
2287
+ * record-less session returns `undefined` without throwing, which is the
2288
+ * correct "not served" either way. On 0.1.5-rc.1 the 3-arg face answers
2289
+ * directly; if it ever throws there, the 2-arg retry degrades to the same
2290
+ * "not served" verdict through the caller's catch.
2291
+ */
2292
+ function cachedSnapshotOf(cache, header) {
2293
+ try {
2294
+ return cache.cachedSnapshot(header, SessionLogOffset(0), PROBE_KEYS);
2295
+ } catch {
2296
+ return cache.cachedSnapshot(header, PROBE_KEYS);
2297
+ }
2298
+ }
2348
2299
  /** Whether the cache already serves BOTH projection rows for this header (nothing to backfill). */
2349
2300
  function servesRows(cache, header) {
2350
2301
  try {
2351
- const values = asRecord(asRecord(cache.cachedSnapshot(header, SessionLogOffset(0), ["contextActivity", "contextTimeline"]))?.values);
2302
+ const values = asRecord(asRecord(cachedSnapshotOf(cache, header))?.values);
2352
2303
  return values !== null && values.contextActivity !== void 0 && values.contextTimeline !== void 0;
2353
2304
  } catch {
2354
2305
  return false;
@@ -2693,7 +2644,7 @@ function watchDetailChannel(ctx, bounds) {
2693
2644
  * (host/fallback.ts) instead of the real folds.
2694
2645
  */
2695
2646
  /** The oldest supported dsh release (see the matrix note above). */
2696
- const BASELINE_DSH_VERSION = "0.1.2-rc.1";
2647
+ const BASELINE_DSH_VERSION = "0.1.5-rc.1";
2697
2648
  /**
2698
2649
  * Release-channel rank at an equal X.Y.Z: a final release outranks its
2699
2650
  * release candidates, which outrank betas, which outrank alphas
@@ -2815,11 +2766,11 @@ const contextHeadersSchema = z.object({ headers: z.array(z.object({
2815
2766
  }).strict()) }).strict();
2816
2767
  function recordOf(event) {
2817
2768
  if (event.type !== "request/header") return null;
2818
- const rawHeader = event.data.header;
2769
+ const rawHeader = event.data?.header;
2819
2770
  if (rawHeader === null || rawHeader === void 0 || typeof rawHeader !== "object") return null;
2820
2771
  const header = rawHeader;
2821
2772
  const tools = Array.isArray(header.tools) ? header.tools : [];
2822
- const record = {
2773
+ return {
2823
2774
  seq: event.seq,
2824
2775
  time: event.time,
2825
2776
  tools: tools.map((t) => {
@@ -2832,8 +2783,6 @@ function recordOf(event) {
2832
2783
  return entry;
2833
2784
  })
2834
2785
  };
2835
- if (typeof header.system === "string" && header.system.length > 0) record.systemTokens = estimateSystemTokens(header.system);
2836
- return record;
2837
2786
  }
2838
2787
  /**
2839
2788
  * The context-headers projection unit; registered alongside the timeline unit (host/index.ts); clients read it through
@@ -3115,7 +3064,6 @@ const timelineStateSchema = z.object({
3115
3064
  }).strict(),
3116
3065
  systemTokens: z.number().int().nonnegative(),
3117
3066
  systems: z.array(systemPromptNodeSchema).optional(),
3118
- systemsFromHeader: z.literal(true).optional(),
3119
3067
  toolsTokens: z.number().int().nonnegative(),
3120
3068
  model: z.string().optional(),
3121
3069
  provider: z.string().optional(),
@@ -3132,25 +3080,7 @@ const timelineStateSchema = z.object({
3132
3080
  lastUser: z.string().optional(),
3133
3081
  stepStart: z.object({
3134
3082
  time: z.number(),
3135
- firstToken: z.number().optional(),
3136
- decode: z.object({
3137
- reasoning: z.number(),
3138
- text: z.number(),
3139
- toolarg: z.number()
3140
- }).strict().optional(),
3141
- blocks: z.object({
3142
- reasoning: z.number().int(),
3143
- text: z.number().int(),
3144
- toolarg: z.number().int()
3145
- }).strict().optional(),
3146
- block: z.object({
3147
- kind: z.enum([
3148
- "reasoning",
3149
- "text",
3150
- "toolarg"
3151
- ]),
3152
- since: z.number()
3153
- }).strict().optional()
3083
+ firstToken: z.number().optional()
3154
3084
  }).strict().optional(),
3155
3085
  callNames: z.record(z.string(), z.object({
3156
3086
  name: z.string(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-context",
3
- "version": "0.55.0",
3
+ "version": "0.56.0",
4
4
  "description": "A DeepSeek Harness plugin for context insight and management, with context dashboard and context command, for understanding how the context is made of, and how it evolves.",
5
5
  "icon": "icon.svg",
6
6
  "author": "bowenliang123",
@@ -68,10 +68,8 @@
68
68
  },
69
69
  "compatibility": {
70
70
  "dshReleases": {
71
- "0.1.2-rc.1": "compatible",
72
- "0.1.3-alpha.2": "compatible",
73
71
  "0.1.5-rc.1": "compatible",
74
- "0.1.7-alpha.2": "compatible"
72
+ "0.1.7-rc.2": "compatible"
75
73
  }
76
74
  }
77
75
  },
@@ -90,9 +88,9 @@
90
88
  },
91
89
  "peerDependencies": {
92
90
  "@deepseek-ai/cordis": "^4.0.2",
93
- "@deepseek-ai/dsh-client-ui-primitives": ">=0.1.2-rc.1",
94
- "@deepseek-ai/dsh-session": ">=0.1.2-rc.1",
95
- "@deepseek-ai/dsh-settings": ">=0.1.2-rc.1",
91
+ "@deepseek-ai/dsh-client-ui-primitives": ">=0.1.5-rc.1",
92
+ "@deepseek-ai/dsh-session": ">=0.1.5-rc.1",
93
+ "@deepseek-ai/dsh-settings": ">=0.1.5-rc.1",
96
94
  "@deepseek-ai/schemastery": "^3.18.2",
97
95
  "react": "^18.3.1"
98
96
  },
@@ -106,15 +104,16 @@
106
104
  },
107
105
  "devDependencies": {
108
106
  "@deepseek-ai/cordis": "^4.0.2",
109
- "@deepseek-ai/dsh-client-ui-primitives": "0.1.2-rc.1",
110
- "@deepseek-ai/dsh-invariants": "0.1.2-rc.1",
111
- "@deepseek-ai/dsh-scope": "0.1.2-rc.1",
112
- "@deepseek-ai/dsh-session": "0.1.2-rc.1",
113
- "@deepseek-ai/dsh-session-projection": "0.1.2-rc.1",
114
- "@deepseek-ai/dsh-settings": "0.1.2-rc.1",
107
+ "@deepseek-ai/dsh-client-ui-primitives": "0.1.5-rc.1",
108
+ "@deepseek-ai/dsh-invariants": "0.1.5-rc.1",
109
+ "@deepseek-ai/dsh-scope": "0.1.5-rc.1",
110
+ "@deepseek-ai/dsh-session": "0.1.5-rc.1",
111
+ "@deepseek-ai/dsh-session-projection": "0.1.5-rc.1",
112
+ "@deepseek-ai/dsh-settings": "0.1.5-rc.1",
115
113
  "@deepseek-ai/dsh-util-workspace-path": "0.1.5-rc.1",
116
114
  "@deepseek-ai/schemastery": "^3.18.4",
117
115
  "@opencode-ai/models": "^0.0.72",
116
+ "@shikijs/langs": "^4.3.1",
118
117
  "@stylistic/eslint-plugin": "^5.10.0",
119
118
  "@tailwindcss/node": "4.3.3",
120
119
  "@tailwindcss/oxide": "4.3.3",
@@ -122,15 +121,30 @@
122
121
  "@types/react": "^18.3.31",
123
122
  "@types/react-dom": "^18.3.7",
124
123
  "@vitest/coverage-v8": "^4.1.11",
124
+ "anser": "^2.3.5",
125
+ "clsx": "^2.0.0",
125
126
  "eslint-plugin-sonarjs": "^4.2.0",
126
127
  "husky": "^9.1.7",
127
128
  "jsdom": "^30.0.1",
129
+ "katex": "^0.16.47",
128
130
  "lightningcss": "1.32.0",
131
+ "mdast-util-from-markdown": "^2.0.3",
132
+ "mdast-util-gfm": "^3.1.0",
133
+ "mdast-util-math": "^3.0.0",
134
+ "micromark-core-commonmark": "^2.0.3",
135
+ "micromark-extension-gfm": "^3.0.0",
136
+ "micromark-extension-math": "^3.1.0",
137
+ "micromark-factory-space": "^2.0.1",
138
+ "micromark-util-character": "^2.1.1",
139
+ "micromark-util-classify-character": "^2.0.1",
140
+ "micromark-util-sanitize-uri": "^2.0.1",
141
+ "micromark-util-symbol": "^2.0.1",
129
142
  "oxlint": "1.82.0",
130
143
  "oxlint-tsgolint": "7.0.2001",
131
144
  "playwright-core": "^1.62.1",
132
145
  "react": "^18.3.1",
133
146
  "react-dom": "^18.3.1",
147
+ "shiki": "^4.3.1",
134
148
  "simple-icons": "16.31.0",
135
149
  "tailwindcss": "4.3.3",
136
150
  "tsdown": "^0.23.0",