dsh-context 0.46.0 → 0.47.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
@@ -72,6 +72,27 @@ interface TimelineState {
72
72
  surface: SurfaceNode[];
73
73
  sums: Record<Category, number>;
74
74
  systemTokens: number;
75
+ /**
76
+ * The live system-prompt nodes, oldest first — a V3 log's `system/message`
77
+ * surface nodes, or the single entry a V0/V2 `request/header.header.system`
78
+ * envelope defines. `systemTokens` is the LAST entry with tokens > 0 (the
79
+ * harness's own "last nonempty surviving system" rule), so an empty dormant
80
+ * node keeps its position without clearing the prompt. Bounded by
81
+ * SYSTEM_NODES_MAX. ABSENT on rows folded before this field existed — the
82
+ * wire then serves no `systems` and the client falls back to the header
83
+ * epoch's own envelope figure.
84
+ */
85
+ systems?: SystemPromptNode[];
86
+ /**
87
+ * Whether `systems` was built from the V0/V2 request ENVELOPE
88
+ * (`header.system`) rather than from V3 `system/message` events. Only then
89
+ * may a system-less header CLEAR the list: its canonical V0 meaning is
90
+ * "this request has no system prompt", while a V3 header never carries one
91
+ * (its prompt lives in the message history). Absent = log-sourced, and
92
+ * never materialized as an `undefined`-valued property (plain-JSON
93
+ * precondition — see the note above `model`).
94
+ */
95
+ systemsFromHeader?: true;
75
96
  toolsTokens: number;
76
97
  /**
77
98
  * The projection-cache precondition is plain JSON: a property whose value
@@ -221,6 +242,19 @@ declare module '@deepseek-ai/dsh-session-projection/types' {
221
242
  }
222
243
  }
223
244
  type Category = 'user' | 'inject' | 'assistant' | 'tool';
245
+ /**
246
+ * One live system-prompt node (Snapshot.systems) — the harness models the
247
+ * system prompt as a surface node, so its TEXT is fetched on demand from the
248
+ * event at `seq`: a V3 `system/message` event, or the V0/V2 `request/header`
249
+ * whose envelope carried `header.system`. `tokens` is the node's heuristic
250
+ * price (0 for a dormant empty node, which the harness reads as "no system
251
+ * prompt"); the effective figure is the LAST node with `tokens > 0`.
252
+ */
253
+ interface SystemPromptNode {
254
+ seq: number;
255
+ time: number;
256
+ tokens: number;
257
+ }
224
258
  /**
225
259
  * The stats board's count figures, precomputed host-side over the RETAINED
226
260
  * request/event records (the same set the detail payload serves). Carried by
@@ -316,6 +350,13 @@ interface Snapshot {
316
350
  * one — clients treat absence as an empty timing card).
317
351
  */
318
352
  timing?: TimingTotals;
353
+ /**
354
+ * The live system-prompt nodes, oldest first — the browser's per-step source
355
+ * for the System section. Absent when the log carried no system prompt, and
356
+ * on older plugin builds (the client then falls back to the header epoch's
357
+ * own `systemTokens`, the pre-V3 shape).
358
+ */
359
+ systems?: SystemPromptNode[];
319
360
  /**
320
361
  * The served live surface: the newest `maxNodes` tail PLUS every live inject node older than the tail (injections land first and are
321
362
  * few,
@@ -450,9 +491,13 @@ interface ToolTimingTotals {
450
491
  }
451
492
  /**
452
493
  * Whole-session timing totals, host-folded from the durable `step/start` /
453
- `step/end` / `assistant/chunk` / `tool/call` / `tool/result` lifecycle
454
- * (running totals over the COMPLETE session log — the same never-trimmed
455
- * framing as `cost`). Durations are wall-clock milliseconds: `wallMs` sums
494
+ * `step/end` / `tool/call` / `tool/result` lifecycle plus the model call's
495
+ * first token (running totals over the COMPLETE session log — the same
496
+ * never-trimmed framing as `cost`). The first token comes from a V0
497
+ * `assistant/chunk` delta or from the call's own embedded stream
498
+ * (`assistant/message.data.stream` / `assistant/attempt.data.stream`, the
499
+ * V2+ settlement) — whichever the log carries, matching the harness's own
500
+ * session-stats fold. Durations are wall-clock milliseconds: `wallMs` sums
456
501
  * whole steps, `ttftMs` the step-start → first-token slice (the model wait)
457
502
  * and `genMs` the first-token → assistant-message slice (the generation) —
458
503
  * both only over calls whose stream carried a token delta, `toolsMs` the sum
package/lib/index.js CHANGED
@@ -308,6 +308,30 @@ function estimateSystemTokens(text) {
308
308
  if (typeof text !== "string" || text.length === 0) return 0;
309
309
  return Math.ceil(text.length / CHARS_PER_TOKEN$1) + ROLE_OVERHEAD$1;
310
310
  }
311
+ /**
312
+ * Price a `system/message` payload's content exactly like the harness's
313
+ * token-meter (`estimateSystemMessage`): text density over EVERY text block
314
+ * plus role framing, with no per-block overhead — an adapter serializes the
315
+ * prompt as plain text, so a text block costs its characters alone. Any other
316
+ * block (or a hostile element) falls back to its JSON length. 0 for empty
317
+ * content, which the harness reads as "no system prompt".
318
+ */
319
+ function estimateSystemContent(blocks) {
320
+ if (!Array.isArray(blocks) || blocks.length === 0) return 0;
321
+ let characters = 0;
322
+ for (const block of blocks) {
323
+ const text = block !== null && typeof block === "object" && block.type === "text" ? block.text : void 0;
324
+ if (typeof text === "string") {
325
+ characters += text.length;
326
+ continue;
327
+ }
328
+ try {
329
+ const json = JSON.stringify(block);
330
+ if (typeof json === "string") characters += json.length;
331
+ } catch {}
332
+ }
333
+ return Math.ceil(characters / CHARS_PER_TOKEN$1) + ROLE_OVERHEAD$1;
334
+ }
311
335
  //#endregion
312
336
  //#region src/shared/imageTokens.ts
313
337
  /**
@@ -565,6 +589,111 @@ function isInjection(source) {
565
589
  return source !== null && source !== void 0 && (typeof source.kind === "string" && source.kind !== "" && source.kind !== "user" || typeof source.form === "string");
566
590
  }
567
591
  //#endregion
592
+ //#region src/host/logShapes.ts
593
+ /**
594
+ * Shape-driven readers over the durable session-event vocabulary — the ONE
595
+ * place the plugin reconciles the two supported log generations:
596
+ *
597
+ * - V0 (dsh 0.1.2-rc.1): `request/header.header.system`, `assistant/chunk`
598
+ * stream events, `SurfaceOp { start, end }`, `tool/code-dispatch`.
599
+ * - V3 (dsh 0.1.5-alpha.1+): `system/message` surface nodes,
600
+ * `assistant/message.data.stream` / `assistant/attempt.data.stream`,
601
+ * `SurfaceOp { startSeq, endSeq }`, `tool/ptc-dispatch`.
602
+ *
603
+ * The fold reads SHAPES, never a detected harness version: a session log is
604
+ * written by exactly one generation, the two spellings are mutually
605
+ * exclusive within it, and a deployment's version probe can be wrong (a
606
+ * healed profile mirror may name a different release than the running
607
+ * harness). Every reader is total over untrusted input — a malformed record
608
+ * yields "nothing here", never a throw (the projection registry drives the
609
+ * fold without an error boundary; one throw stalls the unit's push feed and
610
+ * the browser waits on "loading" forever).
611
+ *
612
+ * @module dsh-context/host/log-shapes
613
+ */
614
+ /**
615
+ * Whether one raw stream chunk carries a token delta — the first-token marker
616
+ * both generations share. Mirrors dsh-llm's `isTokenDelta` (a non-empty text
617
+ * or reasoning fragment, or any Tool-call delta carrying arguments or a name);
618
+ * a malformed chunk is simply not a token.
619
+ */
620
+ function isTokenChunk(chunk) {
621
+ if (chunk === null || typeof chunk !== "object") return false;
622
+ const c = chunk;
623
+ switch (c.type) {
624
+ case "text-delta":
625
+ case "reasoning-delta": return typeof c.text === "string" && c.text !== "";
626
+ case "tool-call-delta": return typeof c.argumentsDelta === "string" && c.argumentsDelta !== "" || c.name !== void 0;
627
+ default: return false;
628
+ }
629
+ }
630
+ /**
631
+ * The first token's instant inside one PACKED delta run (`text-chunks` /
632
+ * `reasoning-chunks` / `tool-call-chunks`): the run's base time plus the
633
+ * accumulated inter-member deltas, taken at the first qualifying member —
634
+ * a name-bearing Tool-call run starts at its first member. Mirrors dsh-llm's
635
+ * `runFirstTokenTime`; a non-finite base or delta yields undefined rather
636
+ * than a NaN instant.
637
+ */
638
+ function runFirstTokenTime(record) {
639
+ const time0 = record.time0;
640
+ if (typeof time0 !== "number" || !Number.isFinite(time0)) return void 0;
641
+ if (record.type === "tool-call-chunks" && record.name !== void 0) return time0;
642
+ const fragments = record.type === "tool-call-chunks" ? record.args : record.texts;
643
+ if (!Array.isArray(fragments)) return void 0;
644
+ const dt = Array.isArray(record.dt) ? record.dt : [];
645
+ let time = time0;
646
+ for (const [index, fragment] of fragments.entries()) {
647
+ if (index > 0) {
648
+ const step = dt[index - 1];
649
+ if (typeof step !== "number" || !Number.isFinite(step)) return void 0;
650
+ time += step;
651
+ }
652
+ if (typeof fragment === "string" && fragment !== "") return time;
653
+ }
654
+ }
655
+ /**
656
+ * The first token's instant inside an embedded assistant stream
657
+ * (`assistant/message.data.stream`, `assistant/attempt.data.stream` — the V2+
658
+ * settlement that replaced the V0 `assistant/chunk` events), or undefined
659
+ * when the stream carries no token. Mirrors dsh-llm's
660
+ * `assistantStreamFirstTokenTime` over the compact record union.
661
+ */
662
+ function firstTokenTimeOfStream(stream) {
663
+ if (!Array.isArray(stream)) return void 0;
664
+ for (const record of stream) {
665
+ if (record === null || typeof record !== "object") continue;
666
+ const r = record;
667
+ if (r.type === "chunk") {
668
+ const time = r.time;
669
+ if (typeof time === "number" && Number.isFinite(time) && isTokenChunk(r.chunk)) return time;
670
+ continue;
671
+ }
672
+ const time = runFirstTokenTime(r);
673
+ if (time !== void 0) return time;
674
+ }
675
+ }
676
+ /**
677
+ * The inclusive surface range a replacement op covers, or null for `append`
678
+ * and for any unrecognized/hostile op (which the fold treats as an append).
679
+ * Reads BOTH endpoint spellings: V3's `startSeq`/`endSeq` first, then V0's
680
+ * `start`/`end` — each accepted only as a finite number, so a hostile op
681
+ * with one good and one malformed endpoint degrades to append.
682
+ */
683
+ function replaceRangeOf(surfaceOp) {
684
+ if (surfaceOp === null || typeof surfaceOp !== "object") return null;
685
+ const op = surfaceOp;
686
+ if (op.op !== "replace") return null;
687
+ const start = typeof op.startSeq === "number" ? op.startSeq : op.start;
688
+ const end = typeof op.endSeq === "number" ? op.endSeq : op.end;
689
+ if (typeof start !== "number" || !Number.isFinite(start)) return null;
690
+ if (typeof end !== "number" || !Number.isFinite(end)) return null;
691
+ return {
692
+ start,
693
+ end
694
+ };
695
+ }
696
+ //#endregion
568
697
  //#region src/shared/fileOps.ts
569
698
  /** Parse a call's raw JSON arguments; non-string/malformed/non-record inputs yield null. */
570
699
  function parseCallArgs(raw) {
@@ -873,6 +1002,24 @@ function bumpDetailRev(st) {
873
1002
  st.detailRev = (st.detailRev ?? 0) + 1;
874
1003
  }
875
1004
  /**
1005
+ * Bound on the live system-prompt nodes (TimelineState.systems). The
1006
+ * effective figure is the LAST nonempty node, so dropping the oldest can only
1007
+ * under-report a pathological log whose newest SYSTEM_NODES_MAX nodes are all
1008
+ * empty while an older one still carried text.
1009
+ */
1010
+ const SYSTEM_NODES_MAX = 8;
1011
+ /** The effective system-prompt price: the last nonempty node, else 0 (the harness's own rule). */
1012
+ function systemTokensOf(systems) {
1013
+ for (let i = systems.length - 1; i >= 0; i--) if (systems[i].tokens > 0) return systems[i].tokens;
1014
+ return 0;
1015
+ }
1016
+ /** Append one system-prompt node, bounding the list (see SYSTEM_NODES_MAX). */
1017
+ function pushSystem(st, node) {
1018
+ const systems = [...st.systems ?? [], node];
1019
+ st.systems = systems.length > SYSTEM_NODES_MAX ? systems.slice(-8) : systems;
1020
+ st.systemTokens = systemTokensOf(st.systems);
1021
+ }
1022
+ /**
876
1023
  * Bound on the buffered nested Code-Mode ops (TimelineState.pendingCodeOps)
877
1024
  * — a hostile log that dispatches without settling the parent run_code
878
1025
  * cannot grow the persisted state past this.
@@ -919,6 +1066,35 @@ function archiveRemoved(st, removed, goneSeq) {
919
1066
  });
920
1067
  }
921
1068
  /**
1069
+ * Remove every live surface node whose seq the replacement claims, keeping the
1070
+ * per-category sums equal to the surviving nodes and archiving the removals.
1071
+ * Removal follows the SEQ list, not the declared range: pruned replacement
1072
+ * nodes keep their own seqs beyond the range end, so a range-based removal
1073
+ * would leave them behind and overcount. Returns the removed nodes.
1074
+ */
1075
+ function removeSurfaceSeqs(st, claimed, goneSeq) {
1076
+ if (claimed.size === 0) return [];
1077
+ const kept = [];
1078
+ const removed = [];
1079
+ for (const n of st.surface) if (claimed.has(n.seq)) {
1080
+ st.sums[n.cat] -= n.tokens;
1081
+ removed.push(n);
1082
+ } else kept.push(n);
1083
+ archiveRemoved(st, removed, goneSeq);
1084
+ st.surface = kept;
1085
+ return removed;
1086
+ }
1087
+ /**
1088
+ * The message nested under an event payload's `message` field
1089
+ * (`system/message`, `assistant/message`, `tool/result`) — read structurally
1090
+ * rather than through `deriveEventMessage`, whose 0.1.2-rc.1 generation knows
1091
+ * nothing of the V3 `system/message` variant. A malformed payload reads null.
1092
+ */
1093
+ function messageOf(data) {
1094
+ const message = data?.message;
1095
+ return message !== null && typeof message === "object" ? message : null;
1096
+ }
1097
+ /**
922
1098
  * The first full text block, recursing through nested content blocks (a tool
923
1099
  * result wraps its text in a `tool-result` block). Unlike `firstText` this
924
1100
  * must NOT truncate/normalize: the skill name is matched off the raw
@@ -1002,18 +1178,10 @@ function applySurface(st, ev, type, data, message) {
1002
1178
  const shadowEventSeq = st.pendingShadowEventSeq;
1003
1179
  delete st.pendingShadowedSeqs;
1004
1180
  delete st.pendingShadowEventSeq;
1005
- const op = ev.surfaceOp;
1006
- if (op !== null && typeof op === "object" && op.op === "replace") {
1181
+ const op = replaceRangeOf(ev.surfaceOp);
1182
+ if (op !== null) {
1007
1183
  if (Array.isArray(shadowedSeqs) && shadowedSeqs.length > 0) {
1008
- const shadowed = new Set(shadowedSeqs);
1009
- const kept = [];
1010
- const removed = [];
1011
- for (const n of st.surface) if (shadowed.has(n.seq)) {
1012
- st.sums[n.cat] -= n.tokens;
1013
- removed.push(n);
1014
- } else kept.push(n);
1015
- archiveRemoved(st, removed, ev.seq);
1016
- st.surface = kept;
1184
+ const removed = removeSurfaceSeqs(st, new Set(shadowedSeqs), ev.seq);
1017
1185
  st.sums[cat] += node.tokens;
1018
1186
  st.surface.push(node);
1019
1187
  if (shadowEventSeq !== void 0) {
@@ -1138,21 +1306,6 @@ function durOf(from, to) {
1138
1306
  return Math.max(0, to - from);
1139
1307
  }
1140
1308
  /**
1141
- * Whether a stream chunk carries a non-empty token delta — the first-token
1142
- * marker the TTFT fold waits for (the same rule as the harness's own
1143
- * session-stats fold). Shape-guarded: a malformed chunk is just not a token.
1144
- */
1145
- function isTokenDelta(chunk) {
1146
- if (chunk === null || typeof chunk !== "object") return false;
1147
- const c = chunk;
1148
- switch (c.type) {
1149
- case "text-delta":
1150
- case "reasoning-delta": return typeof c.text === "string" && c.text !== "";
1151
- case "tool-call-delta": return typeof c.argumentsDelta === "string" && c.argumentsDelta !== "" || c.name !== void 0;
1152
- default: return false;
1153
- }
1154
- }
1155
- /**
1156
1309
  * The fold's private timing accumulator: created on first use, and CLONED on
1157
1310
  * every later ensure() (see `applyTimeline`) — the object left in the
1158
1311
  * persisted previous state is never written into in place.
@@ -1225,7 +1378,20 @@ function applyTimeline(state, event, bounds) {
1225
1378
  const tools = Array.isArray(header.tools) ? header.tools : [];
1226
1379
  const s = ensure();
1227
1380
  s.toolsTokens = estimateToolsTotal(tools);
1228
- s.systemTokens = estimateSystemTokens(header.system);
1381
+ const systemText = header.system;
1382
+ if (typeof systemText === "string" && systemText !== "") {
1383
+ s.systems = [{
1384
+ seq: event.seq,
1385
+ time: event.time,
1386
+ tokens: estimateSystemTokens(systemText)
1387
+ }];
1388
+ s.systemsFromHeader = true;
1389
+ s.systemTokens = systemTokensOf(s.systems);
1390
+ } else if (s.systemsFromHeader === true) {
1391
+ s.systems = [];
1392
+ delete s.systemsFromHeader;
1393
+ s.systemTokens = 0;
1394
+ }
1229
1395
  if (header.config && typeof header.config.model === "string") s.model = header.config.model;
1230
1396
  if (header.config && typeof header.config.provider === "string") s.provider = header.config.provider;
1231
1397
  if ((data?.reason === "change" || data?.reason === "resume") && s.model && s.lastModel && s.model !== s.lastModel) {
@@ -1241,6 +1407,25 @@ function applyTimeline(state, event, bounds) {
1241
1407
  if (s.model) s.lastModel = s.model;
1242
1408
  break;
1243
1409
  }
1410
+ case "system/message": {
1411
+ const s = ensure();
1412
+ delete s.pendingShadowedSeqs;
1413
+ delete s.pendingShadowEventSeq;
1414
+ const op = replaceRangeOf(event.surfaceOp);
1415
+ if (op !== null) {
1416
+ s.systems = (s.systems ?? []).filter((n) => n.seq < op.start || n.seq > op.end);
1417
+ const claimed = /* @__PURE__ */ new Set();
1418
+ for (const n of s.surface) if (n.seq >= op.start && n.seq <= op.end) claimed.add(n.seq);
1419
+ if (removeSurfaceSeqs(s, claimed, event.seq).length > 0) bumpDetailRev(s);
1420
+ }
1421
+ delete s.systemsFromHeader;
1422
+ pushSystem(s, {
1423
+ seq: event.seq,
1424
+ time: event.time,
1425
+ tokens: estimateSystemContent(messageOf(data)?.content)
1426
+ });
1427
+ break;
1428
+ }
1244
1429
  case "request/context": {
1245
1430
  const s = ensure();
1246
1431
  if (data && typeof data.contextWindow === "number") s.contextWindow = data.contextWindow;
@@ -1259,7 +1444,8 @@ function applyTimeline(state, event, bounds) {
1259
1444
  };
1260
1445
  }
1261
1446
  break;
1262
- case "tool/code-dispatch": {
1447
+ case "tool/code-dispatch":
1448
+ case "tool/ptc-dispatch": {
1263
1449
  const rootCallId = data?.rootCallId;
1264
1450
  const name = data?.name;
1265
1451
  if (typeof rootCallId === "string" && typeof name === "string") {
@@ -1277,7 +1463,7 @@ function applyTimeline(state, event, bounds) {
1277
1463
  case "assistant/chunk": {
1278
1464
  const start = state.stepStart;
1279
1465
  if (start === void 0 || start.firstToken !== void 0) return state;
1280
- if (!isTokenDelta(data?.chunk)) return state;
1466
+ if (!isTokenChunk(data?.chunk)) return state;
1281
1467
  const s = ensure();
1282
1468
  s.stepStart = {
1283
1469
  time: start.time,
@@ -1285,6 +1471,18 @@ function applyTimeline(state, event, bounds) {
1285
1471
  };
1286
1472
  break;
1287
1473
  }
1474
+ case "assistant/attempt": {
1475
+ const start = state.stepStart;
1476
+ if (start === void 0 || start.firstToken !== void 0) return state;
1477
+ const first = firstTokenTimeOfStream(data?.stream);
1478
+ if (first === void 0) return state;
1479
+ const s = ensure();
1480
+ s.stepStart = {
1481
+ time: start.time,
1482
+ firstToken: first
1483
+ };
1484
+ break;
1485
+ }
1288
1486
  case "step/start": {
1289
1487
  const s = ensure();
1290
1488
  s.stepStart = { time: event.time };
@@ -1410,9 +1608,12 @@ function applyTimeline(state, event, bounds) {
1410
1608
  const timing = ensureTiming(s);
1411
1609
  timing.calls += 1;
1412
1610
  const stepStart = state.stepStart;
1413
- if (stepStart !== void 0 && stepStart.firstToken !== void 0) {
1414
- timing.ttftMs += durOf(stepStart.time, stepStart.firstToken);
1415
- timing.genMs += durOf(stepStart.firstToken, event.time);
1611
+ if (stepStart !== void 0) {
1612
+ const firstToken = stepStart.firstToken ?? firstTokenTimeOfStream(data?.stream);
1613
+ if (firstToken !== void 0) {
1614
+ timing.ttftMs += durOf(stepStart.time, firstToken);
1615
+ timing.genMs += durOf(firstToken, event.time);
1616
+ }
1416
1617
  }
1417
1618
  const asstMsg = deriveEventMessage(event);
1418
1619
  applySurface(s, event, event.type, data, asstMsg);
@@ -1514,6 +1715,7 @@ function headFieldsOf(state) {
1514
1715
  tools
1515
1716
  };
1516
1717
  }
1718
+ if (state.systems !== void 0 && state.systems.length > 0) result.systems = state.systems.map((n) => ({ ...n }));
1517
1719
  return result;
1518
1720
  }
1519
1721
  /**
@@ -1951,6 +2153,12 @@ const surfaceNodeSchema = z.object({
1951
2153
  skill: z.string().optional(),
1952
2154
  calls: z.array(z.string()).optional()
1953
2155
  }).strict();
2156
+ /** One live system-prompt node (shared/types.ts SystemPromptNode). */
2157
+ const systemPromptNodeSchema = z.object({
2158
+ seq: z.number().int().nonnegative(),
2159
+ time: z.number(),
2160
+ tokens: z.number().int().nonnegative()
2161
+ }).strict();
1954
2162
  const requestRecordSchema = z.object({
1955
2163
  turn: z.number().optional(),
1956
2164
  step: z.number().optional(),
@@ -2097,6 +2305,7 @@ const contextTimelineSchema = z.object({
2097
2305
  pro: costFamilySchema.optional()
2098
2306
  }).strict().optional(),
2099
2307
  timing: timingTotalsSchema.optional(),
2308
+ systems: z.array(systemPromptNodeSchema).optional(),
2100
2309
  nodes: z.array(surfaceNodeSchema).optional(),
2101
2310
  droppedNodes: z.number().int().nonnegative().optional(),
2102
2311
  archive: z.array(surfaceNodeSchema).optional(),
@@ -2120,6 +2329,8 @@ const timelineStateSchema = z.object({
2120
2329
  tool: z.number().int().nonnegative()
2121
2330
  }).strict(),
2122
2331
  systemTokens: z.number().int().nonnegative(),
2332
+ systems: z.array(systemPromptNodeSchema).optional(),
2333
+ systemsFromHeader: z.literal(true).optional(),
2123
2334
  toolsTokens: z.number().int().nonnegative(),
2124
2335
  model: z.string().optional(),
2125
2336
  provider: z.string().optional(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-context",
3
- "version": "0.46.0",
3
+ "version": "0.47.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
  "author": "bowenliang123",
6
6
  "repository": {
@@ -57,13 +57,16 @@
57
57
  "@deepseek-ai/dsh-client-connection",
58
58
  "@deepseek-ai/dsh-client-locale",
59
59
  "@deepseek-ai/dsh-client-ui-conversation",
60
- "@deepseek-ai/dsh-client-ui-settings"
60
+ "@deepseek-ai/dsh-client-ui-settings",
61
+ "@deepseek-ai/dsh-client-ui-sidebar-right"
61
62
  ],
62
63
  "platform": "web"
63
64
  },
64
65
  "compatibility": {
65
66
  "dshReleases": {
66
- "0.1.2-rc.1": "compatible"
67
+ "0.1.2-rc.1": "compatible",
68
+ "0.1.3-alpha.2": "compatible",
69
+ "0.1.5-alpha.1": "compatible"
67
70
  }
68
71
  }
69
72
  },