dsh-context 0.26.1 → 0.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -69,7 +69,7 @@ In **Step** granularity, hovering any bar shows that single step's context info
69
69
 
70
70
  ### ⚡ Context events — when and why the window changed
71
71
 
72
- Every compaction, tool-output prune, skill or plugin context injection, and model switch — each with its token delta, turn/step attribution, and timestamp. Filter by category (**Inject / Compact / Prune / Switch**) to see exactly when each kind of event happened and its impact — e.g. when a skill was injected, when instructions were added, or how much a compaction reclaimed:
72
+ Every compaction, tool-output prune, skill or plugin context injection, model switch, and plan-mode toggle — each labeled with its producer source (instruction file paths, plugin id, skill name), its token delta (compactions/prunes show the **net** reclaimed amount, matching the chart's drop), turn/step attribution, and timestamp. Filter by category (**Inject / Compact / Prune / Switch / Mode**) to see exactly when each kind of event happened and its impact — e.g. when a skill was injected, when instructions were added, or how much a compaction reclaimed:
73
73
 
74
74
  ![Context events and messages](https://raw.githubusercontent.com/bowenliang123/dsh-context/main/docs/context-events.png)
75
75
 
package/lib/client.js CHANGED
@@ -20,12 +20,13 @@ window.__ModuleLoader__.load({
20
20
  "overview.ofUsed": "占已用上下文",
21
21
  "overview.compactReserve": "自动压缩预留:占用达 {pct}% 窗口时触发压缩,此区域一般不实际占用",
22
22
  "stats.title": "上下文统计",
23
- "stats.hint": "统计当前保留的历史窗口(与趋势图一致)",
23
+ "stats.hint": "当前上下文存在和包含的内容",
24
24
  "stats.turns": "轮次",
25
25
  "stats.steps": "步数",
26
26
  "stats.injects": "注入",
27
27
  "stats.compactions": "压缩",
28
28
  "stats.prunes": "剪枝",
29
+ "stats.toolCalls": "工具调用",
29
30
  "stats.images": "图片",
30
31
  "stats.cacheHit": "缓存命中",
31
32
  "stats.cost": "预估费用",
@@ -63,6 +64,7 @@ window.__ModuleLoader__.load({
63
64
  "kind.compaction": "压缩",
64
65
  "kind.prune": "剪枝",
65
66
  "kind.model": "切换",
67
+ "kind.mode": "模式",
66
68
  "nodes.title": "消息构成",
67
69
  "nodes.hint": "当前模型可见的消息,最新在前",
68
70
  "nodes.more": "… 更早的 {n} 条消息已省略",
@@ -80,6 +82,8 @@ window.__ModuleLoader__.load({
80
82
  "ev.prune": "剪枝工具输出",
81
83
  "ev.skill": "Skill 注入({name})",
82
84
  "ev.model": "模型切换:{a} → {b}",
85
+ "ev.mode.plan.on": "进入计划模式",
86
+ "ev.mode.plan.off": "退出计划模式",
83
87
  "form.instructions": "指令注入",
84
88
  "form.catalog": "目录更新",
85
89
  "form.snapshot": "状态快照",
@@ -125,6 +129,8 @@ window.__ModuleLoader__.load({
125
129
  "attach.other": "其他内容",
126
130
  "attach.image": "图片",
127
131
  "attach.open": "查看原图",
132
+ "attach.preview": "图片预览",
133
+ "attach.close": "关闭",
128
134
  "attach.loading": "…",
129
135
  "attach.loadFailed": "加载失败 · 点击重试",
130
136
  "attach.raw": "原图",
@@ -147,12 +153,13 @@ window.__ModuleLoader__.load({
147
153
  "overview.ofUsed": "of used context",
148
154
  "overview.compactReserve": "Auto-compaction reserve: auto-compaction triggers at {pct}% of the window — this area is normally kept as headroom, not actually used",
149
155
  "stats.title": "Context Stats",
150
- "stats.hint": "Over the retained history window (same as the History chart)",
156
+ "stats.hint": "Present in the current context",
151
157
  "stats.turns": "Turns",
152
158
  "stats.steps": "Steps",
153
159
  "stats.injects": "Injections",
154
160
  "stats.compactions": "Compactions",
155
161
  "stats.prunes": "Prunes",
162
+ "stats.toolCalls": "Tool Calls",
156
163
  "stats.images": "Images",
157
164
  "stats.cacheHit": "Cache Hit",
158
165
  "stats.cost": "Cost",
@@ -190,6 +197,7 @@ window.__ModuleLoader__.load({
190
197
  "kind.compaction": "Compact",
191
198
  "kind.prune": "Prune",
192
199
  "kind.model": "Switch",
200
+ "kind.mode": "Mode",
193
201
  "nodes.title": "Messages",
194
202
  "nodes.hint": "currently model-visible, newest first",
195
203
  "nodes.more": "… {n} earlier messages omitted",
@@ -207,6 +215,8 @@ window.__ModuleLoader__.load({
207
215
  "ev.prune": "Tool output pruned",
208
216
  "ev.skill": "Skill injected ({name})",
209
217
  "ev.model": "Model switched: {a} → {b}",
218
+ "ev.mode.plan.on": "Plan mode on",
219
+ "ev.mode.plan.off": "Plan mode off",
210
220
  "form.instructions": "Instructions",
211
221
  "form.catalog": "Catalog Update",
212
222
  "form.snapshot": "State Snapshot",
@@ -252,6 +262,8 @@ window.__ModuleLoader__.load({
252
262
  "attach.other": "Other content",
253
263
  "attach.image": "Image",
254
264
  "attach.open": "Open full image",
265
+ "attach.preview": "Image preview",
266
+ "attach.close": "Close",
255
267
  "attach.loading": "…",
256
268
  "attach.loadFailed": "Load failed · click to retry",
257
269
  "attach.raw": "Raw",
@@ -541,6 +553,7 @@ window.__ModuleLoader__.load({
541
553
  nodes: objectsOf(data.nodes),
542
554
  droppedNodes: numOf(data.droppedNodes),
543
555
  ...typeof data.images === "number" ? { images: data.images } : {},
556
+ ...typeof data.toolCalls === "number" ? { toolCalls: data.toolCalls } : {},
544
557
  archive: objectsOf(data.archive),
545
558
  ...cost !== void 0 ? { cost } : {},
546
559
  ...typeof data.surfaceFloor === "number" ? { surfaceFloor: data.surfaceFloor } : {},
@@ -649,6 +662,7 @@ window.__ModuleLoader__.load({
649
662
  //#region src/client/react.ts
650
663
  const React = require("react");
651
664
  const h = React.createElement;
665
+ const ReactDOM = require("react-dom");
652
666
  //#endregion
653
667
  //#region src/client/components/nodes.tsx
654
668
  /** One-line preview of a surface node (shared by the node list and the Context browser's element rows). */
@@ -873,12 +887,58 @@ window.__ModuleLoader__.load({
873
887
  };
874
888
  }
875
889
  /**
876
- * One attachment card: a 64px cover tile (click opens the full image in a
877
- * new tab; load failures retry on click) beside a metadata column — display
878
- * name, then one labeled row per known fact: Raw (the pre-normalization
879
- * raster dsh 0.1.1 records when normalization reduced the image), Sent (the
880
- * normalized raster the model receives, with its stored byte size), and the
881
- * estimated provider-billed tokens. Unknown facts leave no row behind.
890
+ * Document-level original-image preview the chat history's ImageLightbox
891
+ * recipe (dsh ui-attachment, which the browser module table does not seed)
892
+ * ported onto the plugin's lc-* classes: body portal so a transformed or
893
+ * filtered ancestor cannot trap the fixed backdrop, blurred mask layer,
894
+ * contain-fit image, circular close control, Escape/mask close, and focus
895
+ * restored to the opener on unmount.
896
+ */
897
+ function AttachmentLightbox(props) {
898
+ const { src, alt, labels, onClose } = props;
899
+ const closeRef = React.useRef(null);
900
+ const restoreRef = React.useRef(null);
901
+ React.useEffect(() => {
902
+ restoreRef.current = document.activeElement instanceof HTMLElement ? document.activeElement : null;
903
+ closeRef.current?.focus();
904
+ const onKeyDown = (event) => {
905
+ if (event.key === "Escape") onClose();
906
+ };
907
+ window.addEventListener("keydown", onKeyDown);
908
+ return () => {
909
+ window.removeEventListener("keydown", onKeyDown);
910
+ restoreRef.current?.focus();
911
+ };
912
+ }, [onClose]);
913
+ return ReactDOM.createPortal(/* @__PURE__ */ React.createElement("div", {
914
+ className: "lc-att-lightbox",
915
+ role: "dialog",
916
+ "aria-modal": "true",
917
+ "aria-label": labels.dialog
918
+ }, /* @__PURE__ */ React.createElement("div", {
919
+ className: "lc-att-lightbox-mask",
920
+ "aria-hidden": "true",
921
+ onMouseDown: onClose
922
+ }), /* @__PURE__ */ React.createElement("img", {
923
+ className: "lc-att-lightbox-img",
924
+ src,
925
+ alt
926
+ }), /* @__PURE__ */ React.createElement("button", {
927
+ ref: closeRef,
928
+ type: "button",
929
+ className: "lc-att-lightbox-close",
930
+ "aria-label": labels.close,
931
+ onClick: onClose
932
+ }, /* @__PURE__ */ React.createElement(_deepseek_ai_dsh_client_ui_primitives.IconCloseOutline16, { size: 16 }))), document.body);
933
+ }
934
+ /**
935
+ * One attachment card: the WHOLE card is the click target — a 64px cover
936
+ * tile beside a metadata column (display name, then one labeled row per
937
+ * known fact: Raw, the pre-normalization raster dsh 0.1.1 records when
938
+ * normalization reduced the image; Sent, the normalized raster the model
939
+ * receives, with its stored byte size; and the estimated provider-billed
940
+ * tokens). Clicking opens the chat-style lightbox preview (load failures
941
+ * retry on click instead). Unknown facts leave no row behind.
882
942
  */
883
943
  function makeImageCard(kit) {
884
944
  const { t, fmt } = kit;
@@ -887,6 +947,10 @@ window.__ModuleLoader__.load({
887
947
  const [src, setSrc] = React.useState(null);
888
948
  const [error, setError] = React.useState(false);
889
949
  const [attempt, setAttempt] = React.useState(0);
950
+ const [preview, setPreview] = React.useState(false);
951
+ const closePreview = React.useCallback(() => {
952
+ setPreview(false);
953
+ }, []);
890
954
  React.useEffect(() => {
891
955
  if (load === void 0) return;
892
956
  let live = true;
@@ -924,30 +988,37 @@ window.__ModuleLoader__.load({
924
988
  value: `≈${fmt(tokens)}`,
925
989
  tip: t("attach.tokensTip")
926
990
  });
927
- const open = () => {
928
- if (src === null) return;
929
- try {
930
- window.open(src, "_blank", "noopener");
931
- } catch {}
991
+ const activate = () => {
992
+ if (error) {
993
+ setAttempt((a) => a + 1);
994
+ return;
995
+ }
996
+ if (src !== null) setPreview(true);
932
997
  };
933
- return /* @__PURE__ */ React.createElement("div", { className: "lc-att-item" }, /* @__PURE__ */ React.createElement("button", {
998
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("button", {
934
999
  type: "button",
935
- className: "lc-att-thumb",
1000
+ className: "lc-att-item",
936
1001
  title: error ? t("attach.loadFailed") : t("attach.open"),
937
- onClick: error ? () => {
938
- setAttempt((a) => a + 1);
939
- } : open
940
- }, src !== null ? /* @__PURE__ */ React.createElement("img", {
1002
+ onClick: activate
1003
+ }, /* @__PURE__ */ React.createElement("span", { className: "lc-att-thumb" }, src !== null ? /* @__PURE__ */ React.createElement("img", {
941
1004
  src,
942
1005
  alt: name
943
- }) : /* @__PURE__ */ React.createElement("span", { className: error ? "lc-att-err" : "lc-att-ph" }, error ? "⚠" : load === void 0 ? "🖼" : t("attach.loading"))), /* @__PURE__ */ React.createElement("div", { className: "lc-att-meta" }, /* @__PURE__ */ React.createElement("span", {
1006
+ }) : /* @__PURE__ */ React.createElement("span", { className: error ? "lc-att-err" : "lc-att-ph" }, error ? "⚠" : load === void 0 ? "🖼" : t("attach.loading"))), /* @__PURE__ */ React.createElement("span", { className: "lc-att-meta" }, /* @__PURE__ */ React.createElement("span", {
944
1007
  className: "lc-att-name",
945
1008
  title: name
946
1009
  }, name), rows.map((r) => /* @__PURE__ */ React.createElement("span", {
947
1010
  key: r.label,
948
1011
  className: "lc-att-row",
949
1012
  title: r.tip
950
- }, /* @__PURE__ */ React.createElement("b", { className: "lc-att-row-label" }, r.label), r.value))));
1013
+ }, /* @__PURE__ */ React.createElement("b", { className: "lc-att-row-label" }, r.label), r.value)))), preview && src !== null && /* @__PURE__ */ React.createElement(AttachmentLightbox, {
1014
+ src,
1015
+ alt: name,
1016
+ labels: {
1017
+ dialog: t("attach.preview"),
1018
+ close: t("attach.close")
1019
+ },
1020
+ onClose: closePreview
1021
+ }));
951
1022
  };
952
1023
  }
953
1024
  //#endregion
@@ -1864,7 +1935,8 @@ window.__ModuleLoader__.load({
1864
1935
  compaction: "✂",
1865
1936
  prune: "✂",
1866
1937
  inject: "+",
1867
- model: "⇄"
1938
+ model: "⇄",
1939
+ mode: "⇄"
1868
1940
  };
1869
1941
  /** Build the event text helpers bound to the translate function. */
1870
1942
  function makeEventText(t) {
@@ -1875,9 +1947,12 @@ window.__ModuleLoader__.load({
1875
1947
  a: ev.from || "?",
1876
1948
  b: ev.to || "?"
1877
1949
  });
1950
+ if (ev.kind === "mode") return t("ev.mode." + (ev.name || "?"));
1878
1951
  if (ev.sub === "skill") return t("ev.skill", { name: ev.name || "?" });
1879
1952
  const base = t("form." + (ev.form || "context"));
1880
- return ev.name ? base + " · " + ev.name : base;
1953
+ let label = ev.name ? base + " · " + ev.name : base;
1954
+ if (ev.detail) label += " · " + ev.detail;
1955
+ return label;
1881
1956
  }
1882
1957
  /**
1883
1958
  * Where this event sits in the request timeline, as a label or null.
@@ -2001,7 +2076,7 @@ window.__ModuleLoader__.load({
2001
2076
  return function PluginInfo() {
2002
2077
  const [latest, setLatest] = React.useState(null);
2003
2078
  React.useEffect(() => {
2004
- if ("0.26.1".includes("-dev")) return;
2079
+ if ("0.28.0".includes("-dev")) return;
2005
2080
  let on = true;
2006
2081
  fetchLatestVersion().then((v) => {
2007
2082
  if (on && v) setLatest(v);
@@ -2010,8 +2085,8 @@ window.__ModuleLoader__.load({
2010
2085
  on = false;
2011
2086
  };
2012
2087
  }, []);
2013
- const update = latest !== null && isNewerVersion(latest, "0.26.1") ? latest : null;
2014
- const nameValue = ["dsh-context (v0.26.1)"];
2088
+ const update = latest !== null && isNewerVersion(latest, "0.28.0") ? latest : null;
2089
+ const nameValue = ["dsh-context (v0.28.0)"];
2015
2090
  if (update) nameValue.push(/* @__PURE__ */ React.createElement("span", {
2016
2091
  key: "update",
2017
2092
  className: "lc-pi-update"
@@ -2210,7 +2285,7 @@ window.__ModuleLoader__.load({
2210
2285
  className: "lc-stat-tip",
2211
2286
  role: "tooltip"
2212
2287
  }, tip));
2213
- return /* @__PURE__ */ React.createElement("div", { className: "lc-card lc-col lc-col-stats" }, /* @__PURE__ */ React.createElement("div", { className: "lc-card-title" }, /* @__PURE__ */ React.createElement("span", { className: "lc-card-title-text" }, t("stats.title")), /* @__PURE__ */ React.createElement("span", { className: "lc-card-sub" }, t("stats.hint"))), /* @__PURE__ */ React.createElement("div", { className: "lc-stats" }, cell(t("stats.turns"), fmt(turns.size)), cell(t("stats.steps"), fmt(steps)), cell(t("stats.injects"), fmt(injects)), cell(t("stats.compactions"), fmt(compactions)), cell(t("stats.prunes"), fmt(prunes)), cell(t("stats.images"), fmt(props.images ?? 0)), cell(t("stats.cacheHit"), hit === null ? "—" : hit + "%"), cell(t("stats.cost"), cost === null ? "—" : formatCost(cost, currency), costTip)));
2288
+ return /* @__PURE__ */ React.createElement("div", { className: "lc-card lc-col lc-col-stats" }, /* @__PURE__ */ React.createElement("div", { className: "lc-card-title" }, /* @__PURE__ */ React.createElement("span", { className: "lc-card-title-text" }, t("stats.title")), /* @__PURE__ */ React.createElement("span", { className: "lc-card-sub" }, t("stats.hint"))), /* @__PURE__ */ React.createElement("div", { className: "lc-stats" }, cell(t("stats.turns"), fmt(turns.size)), cell(t("stats.steps"), fmt(steps)), cell(t("stats.injects"), fmt(injects)), cell(t("stats.compactions"), fmt(compactions)), cell(t("stats.prunes"), fmt(prunes)), cell(t("stats.toolCalls"), fmt(props.toolCalls ?? 0)), cell(t("stats.images"), fmt(props.images ?? 0)), cell(t("stats.cacheHit"), hit === null ? "—" : hit + "%"), cell(t("stats.cost"), cost === null ? "—" : formatCost(cost, currency), costTip)));
2214
2289
  };
2215
2290
  }
2216
2291
  //#endregion
@@ -2463,7 +2538,8 @@ window.__ModuleLoader__.load({
2463
2538
  "inject",
2464
2539
  "compaction",
2465
2540
  "prune",
2466
- "model"
2541
+ "model",
2542
+ "mode"
2467
2543
  ];
2468
2544
  function makeContextView(ctx, kit) {
2469
2545
  const { t } = kit;
@@ -2576,6 +2652,7 @@ window.__ModuleLoader__.load({
2576
2652
  requests,
2577
2653
  events,
2578
2654
  usage,
2655
+ toolCalls: data.toolCalls,
2579
2656
  images: data.images,
2580
2657
  cost: data.cost,
2581
2658
  locale: activeLocale
@@ -2674,7 +2751,7 @@ window.__ModuleLoader__.load({
2674
2751
  }
2675
2752
  //#endregion
2676
2753
  //#region \0dsh-global-css:/home/runner/work/dsh-context/dsh-context/src/client/styles.css.mjs
2677
- const css = ".lc-root{box-sizing:border-box;height:100%;color:var(--dsw-alias-label-primary);padding:16px 20px 32px;font-size:13px;overflow-y:auto}.lc-card{background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);border-radius:10px;margin-bottom:14px;padding:14px 16px}.lc-card-title{align-items:baseline;gap:8px;margin-bottom:10px;font-weight:600;display:flex}.lc-card-title-text{white-space:nowrap;flex:none}.lc-stats{grid-template-columns:repeat(auto-fit,minmax(76px,1fr));gap:8px;display:grid}.lc-stat{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:8px;flex-direction:column;gap:2px;min-width:0;padding:8px;display:flex}.lc-stat-label{color:var(--dsw-alias-label-secondary);white-space:nowrap;text-overflow:ellipsis;font-size:11px;font-weight:600;overflow:hidden}.lc-stat-value{color:var(--dsw-alias-label-primary);white-space:nowrap;text-overflow:ellipsis;text-align:center;font-size:14px;font-weight:600;overflow:hidden}.lc-stat-sub{color:var(--dsw-alias-label-secondary);white-space:nowrap;text-overflow:ellipsis;font-size:11px;overflow:hidden}.lc-stat-tipped{position:relative}.lc-stat-q{text-align:center;width:11px;height:11px;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);cursor:help;border-radius:50%;margin-left:4px;font-size:9px;font-style:normal;font-weight:700;line-height:11px;display:inline-block}.lc-stat-tipped:hover .lc-stat-q{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-primary)}.lc-stat-tip{z-index:6;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);width:max-content;max-width:280px;color:var(--dsw-alias-label-primary);pointer-events:none;opacity:0;border-radius:6px;padding:6px 10px;font-size:12px;font-weight:400;line-height:1.5;transition:opacity .12s;position:absolute;top:calc(100% + 6px);left:0;box-shadow:0 2px 8px #0000002e}.lc-stat-tipped:hover .lc-stat-tip{opacity:1}.lc-stat-tip-prices{border-top:1px dashed var(--dsw-alias-border-l1);margin-top:5px;padding-top:5px;display:block}.lc-stat-tip-head{font-weight:600;display:block}.lc-stat-tip-row{margin-top:2px;display:block}.lc-stat-tip-model{color:var(--dsw-alias-label-primary)}.lc-card-sub{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:400}.lc-gran,.lc-kinds{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:6px;gap:2px;margin-left:auto;padding:1px;display:flex}.lc-trend-ctl{align-items:center;gap:6px;margin-left:auto;display:flex}.lc-trend-ctl .lc-gran{margin-left:0}.lc-gran-btn{color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;border-radius:5px;padding:3px 8px;font-family:inherit;font-size:11px;line-height:1}.lc-gran-btn:hover{color:var(--dsw-alias-label-primary)}.lc-gran-on,.lc-gran-on:hover{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground)}.lc-overview-num{align-items:baseline;gap:6px;margin-bottom:8px;display:flex}.lc-overview-num>b{font-size:20px}.lc-overview-num span{color:var(--dsw-alias-label-secondary)}.lc-overview-pct{margin-left:auto;font-size:11px}.lc-overview-pct b{color:var(--dsw-alias-label-primary);margin-right:4px;font-size:20px}.lc-stacked-wrap{width:100%;position:relative}.lc-stacked{background:#8080802e;border-radius:5px;width:100%;display:flex;position:relative;overflow:hidden}.lc-occupied-box{border:2px solid var(--dsw-alias-label-tertiary);box-sizing:border-box;pointer-events:none;opacity:0;box-shadow:0 0 0 1px var(--dsw-alias-bg-layer-2);border-radius:5px;transition:opacity .12s;position:absolute;top:0;bottom:0;left:0}.lc-occupied-box-on{opacity:1}.lc-bar-tip{z-index:5;white-space:nowrap;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);pointer-events:none;opacity:0;border-radius:6px;padding:3px 8px;font-size:12px;transition:opacity .12s;position:absolute;bottom:calc(100% + 6px);transform:translate(-50%);box-shadow:0 2px 8px #0000002e}.lc-bar-tip-on{opacity:1}.lc-stacked>div{height:100%}.lc-stacked-seg{transition:filter .12s,opacity .12s}.lc-stacked-free{box-sizing:border-box;transition:box-shadow .12s,opacity .12s}.lc-stacked-seg-on{filter:brightness(1.18)}.lc-reserve{z-index:1;pointer-events:auto;cursor:help;background:repeating-linear-gradient(45deg, color-mix(in srgb, var(--dsw-alias-state-warn-primary) 24%, transparent) 0 5px, transparent 5px 10px);position:absolute;top:0;bottom:0}.lc-stacked-free-on{border:2px dashed var(--dsw-alias-label-secondary);border-radius:3px}.lc-stacked-dim .lc-stacked-seg{opacity:.35}.lc-stacked-dim .lc-stacked-seg-on{opacity:1}.lc-stacked-dim .lc-stacked-free{opacity:.35}.lc-stacked-dim .lc-stacked-free-on{opacity:1}.lc-legend{grid-template-columns:repeat(auto-fill,minmax(160px,1fr));gap:6px 14px;margin-top:10px;display:grid}.lc-chip{min-width:0;color:var(--dsw-alias-label-primary);cursor:pointer;border-radius:6px;align-items:center;gap:5px;padding:1px 6px;transition:background-color .12s;display:flex}.lc-chip-label{white-space:nowrap;text-overflow:ellipsis;min-width:0;font-weight:600;overflow:hidden}.lc-chip-nums{white-space:nowrap;flex:none;align-items:baseline;gap:6px;margin-left:auto;display:inline-flex}.lc-chip i,.lc-detail-row i,.lc-node i{border-radius:2px;width:8px;height:8px;display:inline-block}.lc-chip i{transition:box-shadow .12s}.lc-chip em{color:var(--dsw-alias-label-secondary);font-style:normal}.lc-chip-on{background:var(--dsw-alias-interactive-bg-hover);font-weight:600}.lc-chip-on i{box-shadow:0 0 0 1px var(--dsw-alias-brand-primary)}.lc-tools{color:var(--dsw-alias-label-secondary);flex-wrap:wrap;align-items:center;gap:6px;margin-top:10px;display:flex}.lc-tools-label,.lc-tools-more{color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;padding:0;font-family:inherit;font-size:12px}.lc-tools-label:hover,.lc-tools-more:hover{text-decoration:underline}.lc-tool-chip{background:var(--dsw-alias-bg-layer-2);font:inherit;color:var(--dsw-alias-label-primary);cursor:pointer;border:0;border-radius:4px;padding:1px 7px;font-size:12px}.lc-tool-chip:hover{text-decoration:underline}.lc-chartrow{align-items:stretch;gap:6px;display:flex}.lc-axis{box-sizing:border-box;width:40px;height:150px;color:var(--dsw-alias-label-secondary);padding-top:18px;font-size:11px;position:relative}.lc-axis span{line-height:1;position:absolute;right:0}.lc-axis-top{top:13px}.lc-axis-mid{top:69px}.lc-axis-bot{top:125px}.lc-chart-scroll{scrollbar-width:thin;flex:1;min-width:0;padding-bottom:8px;position:relative;overflow:auto hidden}.lc-chart-fade{pointer-events:none;z-index:2;width:26px;position:absolute;top:0;bottom:0}.lc-chart-fade-l{background:linear-gradient(to right, var(--dsw-alias-bg-layer-1), transparent);left:0}.lc-chart-fade-r{background:linear-gradient(to left, var(--dsw-alias-bg-layer-1), transparent);right:0}.lc-chart{box-sizing:border-box;align-items:flex-end;gap:2px;width:max-content;min-width:100%;height:130px;padding-top:18px;display:flex;position:relative}.lc-grid{border-top:1px dashed var(--dsw-alias-border-l1);pointer-events:none;position:absolute;left:0;right:0}.lc-grid-top{top:18px}.lc-grid-mid{top:74px}.lc-bar{cursor:pointer;border-radius:2px;flex:none;align-items:flex-end;width:14px;height:100%;transition:opacity .12s,background-color .12s;display:flex;position:relative}.lc-chart-dim .lc-bar{opacity:.35}.lc-chart-dim .lc-bar-in-turn{opacity:1}.lc-chart-dim .lc-turn{opacity:.35}.lc-chart-dim .lc-turn-on{opacity:1}.lc-chart-tip{z-index:5;white-space:nowrap;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);pointer-events:none;border-radius:6px;padding:3px 8px;font-size:12px;position:absolute;top:0;transform:translate(-50%);box-shadow:0 2px 8px #0000002e}.lc-bar:hover{background:var(--dsw-alias-bg-layer-2)}.lc-bar-hovered{outline:1px dashed var(--dsw-alias-brand-primary);outline-offset:1px}.lc-bar-selected{outline:2px solid var(--dsw-alias-label-primary);outline-offset:1px}.lc-bar-in-turn{background:#80808024}.lc-bar-stack{flex-direction:column-reverse;width:100%;display:flex}.lc-bar-stack>div{width:100%}.lc-bar-marker{color:var(--dsw-alias-state-warn-primary);font-size:11px;position:absolute;top:-16px;left:50%;transform:translate(-50%)}.lc-turns{gap:2px;width:max-content;min-width:100%;margin-top:4px;display:flex}.lc-turn{box-sizing:border-box;text-align:center;color:var(--dsw-alias-label-secondary);white-space:nowrap;text-overflow:ellipsis;cursor:pointer;border-radius:3px;flex:none;height:14px;font-size:10px;font-weight:600;line-height:14px;transition:filter .12s,opacity .12s;overflow:hidden}.lc-turn-on{filter:brightness(1.35);color:var(--dsw-alias-label-primary)}.lc-detail{border-top:1px solid var(--dsw-alias-border-l1);margin-top:12px;padding-top:12px}.lc-detail-head{color:var(--dsw-alias-label-secondary);flex-wrap:wrap;gap:6px 16px;margin-bottom:8px;display:flex}.lc-detail-head b{color:var(--dsw-alias-label-primary)}.lc-detail-marker{color:var(--dsw-alias-state-warn-primary);background:var(--dsw-alias-bg-layer-2);border-radius:6px;padding:1px 7px;font-size:11px}.lc-detail-head .lc-actual{color:var(--dsw-alias-state-success-primary)}.lc-detail-tag{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-secondary);border-radius:4px;padding:0 6px;font-size:11px}.lc-detail-rows{grid-template-columns:1fr 1fr;gap:4px 24px;margin-top:10px;display:grid}.lc-detail-row{align-items:center;gap:8px;display:flex}.lc-detail-label{white-space:nowrap;min-width:70px;color:var(--dsw-alias-label-secondary)}.lc-bar-track{background:#8080802e;border-radius:3px;flex:1;height:5px;display:block;overflow:hidden}.lc-bar-fill{border-radius:3px;height:100%;display:block}.lc-detail-num{text-align:right;width:44px}.lc-detail-pct{text-align:right;width:34px;color:var(--dsw-alias-label-secondary)}.lc-cols{flex-wrap:wrap;gap:14px;margin-bottom:14px;display:flex}.lc-col{flex:1;min-width:280px}.lc-cols>.lc-card,.lc-col>.lc-card:last-child{margin-bottom:0}.lc-col-browser{flex-direction:column;display:flex}.lc-col-browser>.lc-card{flex:1}.lc-head>.lc-card:first-child{flex:7 1 0;min-width:360px}.lc-head>.lc-card:last-child{flex:3 1 0;min-width:220px}.lc-pi-grid{grid-template-columns:1fr;gap:8px;display:grid}.lc-pi-row{min-width:0;color:inherit;flex-direction:row;justify-content:space-between;align-items:baseline;gap:12px;text-decoration:none;display:flex}.lc-pi-row:hover .lc-pi-value{text-decoration:underline}.lc-pi-update{color:var(--dsw-alias-state-warn-primary);white-space:nowrap;margin-left:6px;font-size:11px}.lc-pi-label{color:var(--dsw-alias-label-secondary);white-space:nowrap;text-overflow:ellipsis;flex:none;font-size:11px;font-weight:600;overflow:hidden}.lc-pi-value{min-width:0;color:var(--dsw-alias-label-primary);white-space:nowrap;text-overflow:ellipsis;text-align:right;font-size:13px;font-weight:600;overflow:hidden}.lc-events,.lc-nodes{flex-direction:column;gap:2px;max-height:320px;display:flex;overflow-y:auto}.lc-event{align-items:center;gap:8px;padding:3px 0;display:flex}.lc-event-icon{text-align:center;width:18px;color:var(--dsw-alias-state-warn-primary)}.lc-event-icon.lc-event-inject{color:#a855f7}.lc-event-icon.lc-event-model{color:var(--dsw-alias-brand-primary)}.lc-kind{white-space:nowrap;border-radius:4px;flex:none;padding:1px 6px;font-size:10px;font-weight:600}.lc-kind-inject{background:color-mix(in srgb, var(--dsw-alias-state-success-primary) 15%, transparent);color:var(--dsw-alias-state-success-primary)}.lc-kind-compaction{background:color-mix(in srgb, var(--dsw-alias-state-error-primary) 15%, transparent);color:var(--dsw-alias-state-error-primary)}.lc-kind-prune{color:#8b5cf6;background:#8b5cf626}.lc-kind-model{background:color-mix(in srgb, var(--dsw-alias-brand-primary) 15%, transparent);color:var(--dsw-alias-brand-primary)}.lc-event-label{text-overflow:ellipsis;white-space:nowrap;flex:1;overflow:hidden}.lc-event-at{color:var(--dsw-alias-label-secondary);white-space:nowrap;flex:none;font-size:11px}.lc-event-tokens{color:var(--dsw-alias-state-success-primary);white-space:nowrap;font-weight:600}.lc-event-tokens.lc-up{color:var(--dsw-alias-state-warn-primary)}.lc-event-time{color:var(--dsw-alias-label-secondary);font-size:12px}.lc-node{align-items:center;gap:8px;padding:3px 0;display:flex}.lc-node-preview{text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-primary);flex:1;overflow:hidden}.lc-node-time{color:var(--dsw-alias-label-secondary);text-align:right;min-width:54px;font-size:12px}.lc-node-tokens{color:var(--dsw-alias-label-secondary)}.lc-nodes-more{color:var(--dsw-alias-label-secondary);padding:3px 0}.lc-empty{color:var(--dsw-alias-label-secondary);text-align:center;padding:18px 0}.lc-error{flex-direction:column;align-items:center;gap:8px;padding:40px 16px;display:flex}.lc-error-msg{color:var(--dsw-alias-state-error-primary);background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);overflow-wrap:anywhere;border-radius:6px;max-width:100%;padding:4px 8px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px}.lc-error-retry{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;border-radius:6px;padding:4px 14px;font-size:12px}.lc-error-retry:hover{border-color:var(--dsw-alias-label-primary)}.lc-foot{color:var(--dsw-alias-label-secondary);margin-top:4px;font-size:12px}.lc-modal-backdrop{z-index:200;background:#00000073;justify-content:center;align-items:center;display:flex;position:fixed;inset:0}.lc-modal-card{box-sizing:border-box;background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);width:min(720px,100vw - 48px);max-height:min(82vh,760px);box-shadow:var(--dsw-shadow-lv3,0 12px 32px #0006);color:var(--dsw-alias-label-primary);border-radius:12px;padding:16px 18px 18px;font-size:13px;overflow-y:auto}.lc-modal-head{align-items:baseline;gap:8px;margin-bottom:12px;display:flex}.lc-modal-title{font-size:14px;font-weight:600}.lc-modal-close{color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;border-radius:6px;margin-left:auto;padding:2px 6px;font-family:inherit;font-size:18px;line-height:1}.lc-modal-close:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2)}.lc-br-hint{color:var(--dsw-alias-label-secondary);white-space:nowrap;margin-left:auto;font-size:11px;font-weight:400}.lc-br-pick{font:inherit;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:6px;max-width:240px;padding:3px 6px;font-size:12px}.lc-br-meta{color:var(--dsw-alias-label-secondary);flex-wrap:wrap;gap:6px 16px;margin-bottom:8px;display:flex}.lc-br-meta b{color:var(--dsw-alias-label-primary)}.lc-br-meta .lc-actual{color:var(--dsw-alias-state-success-primary)}.lc-br-note{color:var(--dsw-alias-label-secondary);margin-top:8px;font-size:12px}.lc-br-cats{flex-direction:column;gap:4px;margin-top:10px;display:flex}.lc-br-cat{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-2);border-radius:8px;overflow:hidden}.lc-br-cat-empty{opacity:.55}.lc-br-cat-row{width:100%;color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;text-align:left;background:0 0;border:0;align-items:center;gap:8px;padding:7px 10px;transition:background-color .12s;display:flex}.lc-br-cat-row:hover,.lc-br-cat-on{background:var(--dsw-alias-interactive-bg-hover)}.lc-br-cat-on i{box-shadow:0 0 0 1px var(--dsw-alias-brand-primary)}.lc-br-cat-row i{border-radius:2px;flex:none;width:8px;height:8px;transition:box-shadow .12s;display:inline-block}.lc-br-cat-label{font-weight:600}.lc-br-cat-count{color:var(--dsw-alias-label-secondary);white-space:nowrap;font-size:12px}.lc-br-count-grp{flex:1;align-items:center;gap:4px;min-width:0;display:inline-flex}.lc-br-chev{width:12px;color:var(--dsw-alias-label-secondary);flex:none;transition:transform .12s}.lc-br-chev-on{transform:rotate(90deg)}.lc-br-tokens{color:var(--dsw-alias-label-secondary);flex:none;font-size:12px}.lc-br-delta,.lc-br-tdelta{white-space:nowrap;border-radius:4px;flex:none;padding:0 5px;font-size:11px;font-weight:600}.lc-br-delta-up,.lc-br-tdelta-up{color:var(--dsw-alias-state-success-primary);background:color-mix(in srgb, var(--dsw-alias-state-success-primary) 15%, transparent)}.lc-br-delta-down,.lc-br-tdelta-down{color:var(--dsw-alias-state-error-primary);background:color-mix(in srgb, var(--dsw-alias-state-error-primary) 15%, transparent)}.lc-br-tokens-grp{flex:none;align-items:center;gap:4px;min-width:0;display:inline-flex}.lc-br-pct{text-align:right;width:36px;color:var(--dsw-alias-label-secondary);flex:none;font-size:12px}.lc-br-body{border-top:1px solid var(--dsw-alias-border-l1);flex-direction:column;gap:2px;padding:4px 6px;display:flex}.lc-br-elem{border-radius:6px}.lc-br-elem-on{background:var(--dsw-alias-interactive-bg-active)}.lc-br-elem-row{width:100%;color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;text-align:left;background:0 0;border:0;border-radius:6px;align-items:center;gap:8px;padding:5px 6px;font-size:12px;transition:background-color .12s;display:flex}.lc-br-elem-row:hover{background:var(--dsw-alias-interactive-bg-hover)}.lc-br-tag{color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);text-overflow:ellipsis;white-space:nowrap;border-radius:4px;flex:none;max-width:220px;padding:0 6px;font-size:11px;overflow:hidden}.lc-br-preview{text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;overflow:hidden}.lc-br-time{color:var(--dsw-alias-label-secondary);flex:none;font-size:11px}.lc-br-content{flex-direction:column;gap:6px;padding:2px 6px 8px 26px;display:flex}.lc-br-dim{color:var(--dsw-alias-label-secondary)}.lc-ts-card{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:6px;overflow:hidden}.lc-ts-card-head{color:var(--dsw-alias-label-secondary);border-bottom:1px solid var(--dsw-alias-border-l1);align-items:center;gap:8px;padding:6px 10px;font-size:11px;font-weight:600;display:flex}.lc-ts-card-head b{color:var(--dsw-alias-label-primary)}.lc-ts-call-name{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:13px}.lc-ts-card-count{margin-left:auto}.lc-ts-desc-body{color:var(--dsw-alias-label-primary);white-space:pre-wrap;word-break:break-word;scrollbar-width:thin;max-height:320px;margin:0;padding:8px 10px;font-size:12px;line-height:1.55;overflow-y:auto}.lc-ts-param-row{border-top:1px solid var(--dsw-alias-border-l1);grid-template-columns:140px 90px 56px 1fr;align-items:baseline;gap:2px 10px;padding:6px 10px;font-size:12px;display:grid}.lc-ts-param-row:first-of-type{border-top:0}.lc-ts-param-name{color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;font-weight:600;overflow:hidden}.lc-ts-param-type{color:var(--dsw-alias-label-secondary);text-overflow:ellipsis;white-space:nowrap;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px;overflow:hidden}.lc-ts-param-req{color:var(--dsw-alias-state-warn-primary);font-size:11px;font-weight:600}.lc-ts-param-req-off{color:var(--dsw-alias-label-secondary);font-size:11px}.lc-ts-param-desc{color:var(--dsw-alias-label-secondary);grid-column:1/-1;line-height:1.5}.lc-ts-params-empty{color:var(--dsw-alias-label-secondary);padding:8px 10px;font-size:12px}.lc-ts-arg-row{border-top:1px solid var(--dsw-alias-border-l1);grid-template-columns:minmax(0,96px) 1fr;align-items:start;column-gap:12px;padding:6px 10px;font-size:12px;display:grid}.lc-ts-arg-row:first-of-type{border-top:0}.lc-ts-arg-row .lc-ts-param-name{text-overflow:unset;white-space:normal;overflow-wrap:anywhere;overflow:visible}.lc-ts-arg-val{color:var(--dsw-alias-label-primary);white-space:pre-wrap;word-break:break-word;scrollbar-width:thin;max-height:200px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;line-height:1.55;overflow-y:auto}.lc-ts-json{flex-direction:column;gap:4px;display:flex}.lc-ts-json-toggle{color:var(--dsw-alias-label-secondary);font:inherit;cursor:pointer;background:0 0;border:0;align-self:flex-start;padding:0;font-size:11px}.lc-ts-json-toggle:hover{color:var(--dsw-alias-label-primary);text-decoration:underline}.lc-rich-seg{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:6px;gap:2px;margin-left:auto;padding:1px;display:flex}.lc-rich-seg-btn{color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;border-radius:5px;padding:3px 8px;font-family:inherit;font-size:11px;line-height:1}.lc-rich-seg-btn:hover{color:var(--dsw-alias-label-primary)}.lc-rich-seg-on,.lc-rich-seg-on:hover{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground)}.lc-ts-desc-md{color:var(--dsw-alias-label-primary);word-break:break-word;scrollbar-width:thin;max-height:320px;padding:4px 10px;font-size:12px;line-height:1.55;overflow-y:auto}.lc-ts-desc-md>div{font-size:13px;line-height:1.55}.lc-ts-desc-md div :is(h1,h2,h3,h4,h5,h6){margin:10px 0 4px;font-size:13px;font-weight:600}.lc-ts-desc-md div p,.lc-ts-desc-md div pre{margin:6px 0}.lc-ts-desc-md div :not(pre)>code{box-decoration-break:clone;padding:1px 5px;line-height:1.3;font-size:1em!important}.lc-ts-desc-md div table code{font-size:inherit}.lc-att-grid{grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;padding:8px 10px;display:grid}.lc-att-item{align-items:center;gap:8px;min-width:0;display:flex}.lc-att-thumb{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);cursor:pointer;width:64px;height:64px;font:inherit;border-radius:6px;flex:none;justify-content:center;align-items:center;padding:0;display:flex;overflow:hidden}.lc-att-thumb img{object-fit:cover;width:100%;height:100%;display:block}.lc-att-ph,.lc-att-err{color:var(--dsw-alias-label-secondary);text-align:center;padding:2px;font-size:10px}.lc-att-meta{flex-direction:column;gap:2px;min-width:0;display:flex}.lc-att-name{color:var(--dsw-alias-label-primary);overflow-wrap:anywhere;word-break:break-word;font-size:12px;line-height:1.3}.lc-att-row{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;font-size:11px}.lc-att-row-label{min-width:3.2em;font-weight:400;display:inline-block}[data-conversation-scroll]:has(.lc-root)>[data-composer-seat]:not(:has([data-approval-key],[data-question-key],[data-plan-review-key])){display:none}";
2754
+ const css = ".lc-root{box-sizing:border-box;height:100%;color:var(--dsw-alias-label-primary);padding:16px 20px 32px;font-size:13px;overflow-y:auto}.lc-card{background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);border-radius:10px;margin-bottom:14px;padding:14px 16px}.lc-card-title{align-items:baseline;gap:8px;margin-bottom:10px;font-weight:600;display:flex}.lc-card-title-text{white-space:nowrap;flex:none}.lc-stats{grid-template-columns:repeat(auto-fit,minmax(62px,1fr));gap:6px;display:grid}.lc-stat{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:8px;flex-direction:column;gap:2px;min-width:0;padding:6px;display:flex}.lc-stat-label{color:var(--dsw-alias-label-secondary);white-space:nowrap;text-overflow:ellipsis;font-size:11px;font-weight:600;overflow:hidden}.lc-stat-value{color:var(--dsw-alias-label-primary);white-space:nowrap;text-overflow:ellipsis;text-align:center;font-size:14px;font-weight:600;overflow:hidden}.lc-stat-sub{color:var(--dsw-alias-label-secondary);white-space:nowrap;text-overflow:ellipsis;font-size:11px;overflow:hidden}.lc-stat-tipped{position:relative}.lc-stat-q{text-align:center;width:11px;height:11px;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);cursor:help;border-radius:50%;margin-left:4px;font-size:9px;font-style:normal;font-weight:700;line-height:11px;display:inline-block}.lc-stat-tipped:hover .lc-stat-q{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-primary)}.lc-stat-tip{z-index:6;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);width:max-content;max-width:280px;color:var(--dsw-alias-label-primary);pointer-events:none;opacity:0;border-radius:6px;padding:6px 10px;font-size:12px;font-weight:400;line-height:1.5;transition:opacity .12s;position:absolute;top:calc(100% + 6px);left:0;box-shadow:0 2px 8px #0000002e}.lc-stat-tipped:hover .lc-stat-tip{opacity:1}.lc-stat-tip-prices{border-top:1px dashed var(--dsw-alias-border-l1);margin-top:5px;padding-top:5px;display:block}.lc-stat-tip-head{font-weight:600;display:block}.lc-stat-tip-row{margin-top:2px;display:block}.lc-stat-tip-model{color:var(--dsw-alias-label-primary)}.lc-card-sub{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:400}.lc-gran,.lc-kinds{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:6px;gap:2px;margin-left:auto;padding:1px;display:flex}.lc-trend-ctl{align-items:center;gap:6px;margin-left:auto;display:flex}.lc-trend-ctl .lc-gran{margin-left:0}.lc-gran-btn{color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;border-radius:5px;padding:3px 8px;font-family:inherit;font-size:11px;line-height:1}.lc-gran-btn:hover{color:var(--dsw-alias-label-primary)}.lc-gran-on,.lc-gran-on:hover{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground)}.lc-overview-num{align-items:baseline;gap:6px;margin-bottom:8px;display:flex}.lc-overview-num>b{font-size:20px}.lc-overview-num span{color:var(--dsw-alias-label-secondary)}.lc-overview-pct{margin-left:auto;font-size:11px}.lc-overview-pct b{color:var(--dsw-alias-label-primary);margin-right:4px;font-size:20px}.lc-stacked-wrap{width:100%;position:relative}.lc-stacked{background:#8080802e;border-radius:5px;width:100%;display:flex;position:relative;overflow:hidden}.lc-occupied-box{border:2px solid var(--dsw-alias-label-tertiary);box-sizing:border-box;pointer-events:none;opacity:0;box-shadow:0 0 0 1px var(--dsw-alias-bg-layer-2);border-radius:5px;transition:opacity .12s;position:absolute;top:0;bottom:0;left:0}.lc-occupied-box-on{opacity:1}.lc-bar-tip{z-index:5;white-space:nowrap;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);pointer-events:none;opacity:0;border-radius:6px;padding:3px 8px;font-size:12px;transition:opacity .12s;position:absolute;bottom:calc(100% + 6px);transform:translate(-50%);box-shadow:0 2px 8px #0000002e}.lc-bar-tip-on{opacity:1}.lc-stacked>div{height:100%}.lc-stacked-seg{transition:filter .12s,opacity .12s}.lc-stacked-free{box-sizing:border-box;transition:box-shadow .12s,opacity .12s}.lc-stacked-seg-on{filter:brightness(1.18)}.lc-reserve{z-index:1;pointer-events:auto;cursor:help;background:repeating-linear-gradient(45deg, color-mix(in srgb, var(--dsw-alias-state-warn-primary) 24%, transparent) 0 5px, transparent 5px 10px);position:absolute;top:0;bottom:0}.lc-stacked-free-on{border:2px dashed var(--dsw-alias-label-secondary);border-radius:3px}.lc-stacked-dim .lc-stacked-seg{opacity:.35}.lc-stacked-dim .lc-stacked-seg-on{opacity:1}.lc-stacked-dim .lc-stacked-free{opacity:.35}.lc-stacked-dim .lc-stacked-free-on{opacity:1}.lc-legend{grid-template-columns:repeat(auto-fill,minmax(160px,1fr));gap:6px 14px;margin-top:10px;display:grid}.lc-chip{min-width:0;color:var(--dsw-alias-label-primary);cursor:pointer;border-radius:6px;align-items:center;gap:5px;padding:1px 6px;transition:background-color .12s;display:flex}.lc-chip-label{white-space:nowrap;text-overflow:ellipsis;min-width:0;font-weight:600;overflow:hidden}.lc-chip-nums{white-space:nowrap;flex:none;align-items:baseline;gap:6px;margin-left:auto;display:inline-flex}.lc-chip i,.lc-detail-row i,.lc-node i{border-radius:2px;width:8px;height:8px;display:inline-block}.lc-chip i{transition:box-shadow .12s}.lc-chip em{color:var(--dsw-alias-label-secondary);font-style:normal}.lc-chip-on{background:var(--dsw-alias-interactive-bg-hover);font-weight:600}.lc-chip-on i{box-shadow:0 0 0 1px var(--dsw-alias-brand-primary)}.lc-tools{color:var(--dsw-alias-label-secondary);flex-wrap:wrap;align-items:center;gap:6px;margin-top:10px;display:flex}.lc-tools-label,.lc-tools-more{color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;padding:0;font-family:inherit;font-size:12px}.lc-tools-label:hover,.lc-tools-more:hover{text-decoration:underline}.lc-tool-chip{background:var(--dsw-alias-bg-layer-2);font:inherit;color:var(--dsw-alias-label-primary);cursor:pointer;border:0;border-radius:4px;padding:1px 7px;font-size:12px}.lc-tool-chip:hover{text-decoration:underline}.lc-chartrow{align-items:stretch;gap:6px;display:flex}.lc-axis{box-sizing:border-box;width:40px;height:150px;color:var(--dsw-alias-label-secondary);padding-top:18px;font-size:11px;position:relative}.lc-axis span{line-height:1;position:absolute;right:0}.lc-axis-top{top:13px}.lc-axis-mid{top:69px}.lc-axis-bot{top:125px}.lc-chart-scroll{scrollbar-width:thin;flex:1;min-width:0;padding-bottom:8px;position:relative;overflow:auto hidden}.lc-chart-fade{pointer-events:none;z-index:2;width:26px;position:absolute;top:0;bottom:0}.lc-chart-fade-l{background:linear-gradient(to right, var(--dsw-alias-bg-layer-1), transparent);left:0}.lc-chart-fade-r{background:linear-gradient(to left, var(--dsw-alias-bg-layer-1), transparent);right:0}.lc-chart{box-sizing:border-box;align-items:flex-end;gap:2px;width:max-content;min-width:100%;height:130px;padding-top:18px;display:flex;position:relative}.lc-grid{border-top:1px dashed var(--dsw-alias-border-l1);pointer-events:none;position:absolute;left:0;right:0}.lc-grid-top{top:18px}.lc-grid-mid{top:74px}.lc-bar{cursor:pointer;border-radius:2px;flex:none;align-items:flex-end;width:14px;height:100%;transition:opacity .12s,background-color .12s;display:flex;position:relative}.lc-chart-dim .lc-bar{opacity:.35}.lc-chart-dim .lc-bar-in-turn{opacity:1}.lc-chart-dim .lc-turn{opacity:.35}.lc-chart-dim .lc-turn-on{opacity:1}.lc-chart-tip{z-index:5;white-space:nowrap;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);pointer-events:none;border-radius:6px;padding:3px 8px;font-size:12px;position:absolute;top:0;transform:translate(-50%);box-shadow:0 2px 8px #0000002e}.lc-bar:hover{background:var(--dsw-alias-bg-layer-2)}.lc-bar-hovered{outline:1px dashed var(--dsw-alias-brand-primary);outline-offset:1px}.lc-bar-selected{outline:2px solid var(--dsw-alias-label-primary);outline-offset:1px}.lc-bar-in-turn{background:#80808024}.lc-bar-stack{flex-direction:column-reverse;width:100%;display:flex}.lc-bar-stack>div{width:100%}.lc-bar-marker{color:var(--dsw-alias-state-warn-primary);font-size:11px;position:absolute;top:-16px;left:50%;transform:translate(-50%)}.lc-turns{gap:2px;width:max-content;min-width:100%;margin-top:4px;display:flex}.lc-turn{box-sizing:border-box;text-align:center;color:var(--dsw-alias-label-secondary);white-space:nowrap;text-overflow:ellipsis;cursor:pointer;border-radius:3px;flex:none;height:14px;font-size:10px;font-weight:600;line-height:14px;transition:filter .12s,opacity .12s;overflow:hidden}.lc-turn-on{filter:brightness(1.35);color:var(--dsw-alias-label-primary)}.lc-detail{border-top:1px solid var(--dsw-alias-border-l1);margin-top:12px;padding-top:12px}.lc-detail-head{color:var(--dsw-alias-label-secondary);flex-wrap:wrap;gap:6px 16px;margin-bottom:8px;display:flex}.lc-detail-head b{color:var(--dsw-alias-label-primary)}.lc-detail-marker{color:var(--dsw-alias-state-warn-primary);background:var(--dsw-alias-bg-layer-2);border-radius:6px;padding:1px 7px;font-size:11px}.lc-detail-head .lc-actual{color:var(--dsw-alias-state-success-primary)}.lc-detail-tag{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-secondary);border-radius:4px;padding:0 6px;font-size:11px}.lc-detail-rows{grid-template-columns:1fr 1fr;gap:4px 24px;margin-top:10px;display:grid}.lc-detail-row{align-items:center;gap:8px;display:flex}.lc-detail-label{white-space:nowrap;min-width:70px;color:var(--dsw-alias-label-secondary)}.lc-bar-track{background:#8080802e;border-radius:3px;flex:1;height:5px;display:block;overflow:hidden}.lc-bar-fill{border-radius:3px;height:100%;display:block}.lc-detail-num{text-align:right;width:44px}.lc-detail-pct{text-align:right;width:34px;color:var(--dsw-alias-label-secondary)}.lc-cols{flex-wrap:wrap;gap:14px;margin-bottom:14px;display:flex}.lc-col{flex:1;min-width:280px}.lc-cols>.lc-card,.lc-col>.lc-card:last-child{margin-bottom:0}.lc-col-browser{flex-direction:column;display:flex}.lc-col-browser>.lc-card{flex:1}.lc-head>.lc-card:first-child{flex:7 1 0;min-width:360px}.lc-head>.lc-card:last-child{flex:3 1 0;min-width:220px}.lc-pi-grid{grid-template-columns:1fr;gap:8px;display:grid}.lc-pi-row{min-width:0;color:inherit;flex-direction:row;justify-content:space-between;align-items:baseline;gap:12px;text-decoration:none;display:flex}.lc-pi-row:hover .lc-pi-value{text-decoration:underline}.lc-pi-update{color:var(--dsw-alias-state-warn-primary);white-space:nowrap;margin-left:6px;font-size:11px}.lc-pi-label{color:var(--dsw-alias-label-secondary);white-space:nowrap;text-overflow:ellipsis;flex:none;font-size:11px;font-weight:600;overflow:hidden}.lc-pi-value{min-width:0;color:var(--dsw-alias-label-primary);white-space:nowrap;text-overflow:ellipsis;text-align:right;font-size:13px;font-weight:600;overflow:hidden}.lc-events,.lc-nodes{flex-direction:column;gap:2px;max-height:320px;display:flex;overflow-y:auto}.lc-event{align-items:center;gap:8px;padding:3px 0;display:flex}.lc-event-icon{text-align:center;width:18px;color:var(--dsw-alias-state-warn-primary)}.lc-event-icon.lc-event-inject{color:#a855f7}.lc-event-icon.lc-event-model{color:var(--dsw-alias-brand-primary)}.lc-event-icon.lc-event-mode{color:var(--dsw-alias-label-secondary)}.lc-kind{white-space:nowrap;border-radius:4px;flex:none;padding:1px 6px;font-size:10px;font-weight:600}.lc-kind-inject{background:color-mix(in srgb, var(--dsw-alias-state-success-primary) 15%, transparent);color:var(--dsw-alias-state-success-primary)}.lc-kind-compaction{background:color-mix(in srgb, var(--dsw-alias-state-error-primary) 15%, transparent);color:var(--dsw-alias-state-error-primary)}.lc-kind-prune{color:#8b5cf6;background:#8b5cf626}.lc-kind-model{background:color-mix(in srgb, var(--dsw-alias-brand-primary) 15%, transparent);color:var(--dsw-alias-brand-primary)}.lc-kind-mode{background:color-mix(in srgb, var(--dsw-alias-label-secondary) 15%, transparent);color:var(--dsw-alias-label-secondary)}.lc-event-label{text-overflow:ellipsis;white-space:nowrap;flex:1;overflow:hidden}.lc-event-at{color:var(--dsw-alias-label-secondary);white-space:nowrap;flex:none;font-size:11px}.lc-event-tokens{color:var(--dsw-alias-state-success-primary);white-space:nowrap;font-weight:600}.lc-event-tokens.lc-up{color:var(--dsw-alias-state-warn-primary)}.lc-event-time{color:var(--dsw-alias-label-secondary);font-size:12px}.lc-node{align-items:center;gap:8px;padding:3px 0;display:flex}.lc-node-preview{text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-primary);flex:1;overflow:hidden}.lc-node-time{color:var(--dsw-alias-label-secondary);text-align:right;min-width:54px;font-size:12px}.lc-node-tokens{color:var(--dsw-alias-label-secondary)}.lc-nodes-more{color:var(--dsw-alias-label-secondary);padding:3px 0}.lc-empty{color:var(--dsw-alias-label-secondary);text-align:center;padding:18px 0}.lc-error{flex-direction:column;align-items:center;gap:8px;padding:40px 16px;display:flex}.lc-error-msg{color:var(--dsw-alias-state-error-primary);background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);overflow-wrap:anywhere;border-radius:6px;max-width:100%;padding:4px 8px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px}.lc-error-retry{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;border-radius:6px;padding:4px 14px;font-size:12px}.lc-error-retry:hover{border-color:var(--dsw-alias-label-primary)}.lc-foot{color:var(--dsw-alias-label-secondary);margin-top:4px;font-size:12px}.lc-modal-backdrop{z-index:200;background:#00000073;justify-content:center;align-items:center;display:flex;position:fixed;inset:0}.lc-modal-card{box-sizing:border-box;background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);width:min(720px,100vw - 48px);max-height:min(82vh,760px);box-shadow:var(--dsw-shadow-lv3,0 12px 32px #0006);color:var(--dsw-alias-label-primary);border-radius:12px;padding:16px 18px 18px;font-size:13px;overflow-y:auto}.lc-modal-head{align-items:baseline;gap:8px;margin-bottom:12px;display:flex}.lc-modal-title{font-size:14px;font-weight:600}.lc-modal-close{color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;border-radius:6px;margin-left:auto;padding:2px 6px;font-family:inherit;font-size:18px;line-height:1}.lc-modal-close:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2)}.lc-br-hint{color:var(--dsw-alias-label-secondary);white-space:nowrap;margin-left:auto;font-size:11px;font-weight:400}.lc-br-pick{font:inherit;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:6px;max-width:240px;padding:3px 6px;font-size:12px}.lc-br-meta{color:var(--dsw-alias-label-secondary);flex-wrap:wrap;gap:6px 16px;margin-bottom:8px;display:flex}.lc-br-meta b{color:var(--dsw-alias-label-primary)}.lc-br-meta .lc-actual{color:var(--dsw-alias-state-success-primary)}.lc-br-note{color:var(--dsw-alias-label-secondary);margin-top:8px;font-size:12px}.lc-br-cats{flex-direction:column;gap:4px;margin-top:10px;display:flex}.lc-br-cat{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-2);border-radius:8px;overflow:hidden}.lc-br-cat-empty{opacity:.55}.lc-br-cat-row{width:100%;color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;text-align:left;background:0 0;border:0;align-items:center;gap:8px;padding:7px 10px;transition:background-color .12s;display:flex}.lc-br-cat-row:hover,.lc-br-cat-on{background:var(--dsw-alias-interactive-bg-hover)}.lc-br-cat-on i{box-shadow:0 0 0 1px var(--dsw-alias-brand-primary)}.lc-br-cat-row i{border-radius:2px;flex:none;width:8px;height:8px;transition:box-shadow .12s;display:inline-block}.lc-br-cat-label{font-weight:600}.lc-br-cat-count{color:var(--dsw-alias-label-secondary);white-space:nowrap;font-size:12px}.lc-br-count-grp{flex:1;align-items:center;gap:4px;min-width:0;display:inline-flex}.lc-br-chev{width:12px;color:var(--dsw-alias-label-secondary);flex:none;transition:transform .12s}.lc-br-chev-on{transform:rotate(90deg)}.lc-br-tokens{color:var(--dsw-alias-label-secondary);flex:none;font-size:12px}.lc-br-delta,.lc-br-tdelta{white-space:nowrap;border-radius:4px;flex:none;padding:0 5px;font-size:11px;font-weight:600}.lc-br-delta-up,.lc-br-tdelta-up{color:var(--dsw-alias-state-success-primary);background:color-mix(in srgb, var(--dsw-alias-state-success-primary) 15%, transparent)}.lc-br-delta-down,.lc-br-tdelta-down{color:var(--dsw-alias-state-error-primary);background:color-mix(in srgb, var(--dsw-alias-state-error-primary) 15%, transparent)}.lc-br-tokens-grp{flex:none;align-items:center;gap:4px;min-width:0;display:inline-flex}.lc-br-pct{text-align:right;width:36px;color:var(--dsw-alias-label-secondary);flex:none;font-size:12px}.lc-br-body{border-top:1px solid var(--dsw-alias-border-l1);flex-direction:column;gap:2px;padding:4px 6px;display:flex}.lc-br-elem{border-radius:6px}.lc-br-elem-on{background:var(--dsw-alias-interactive-bg-active)}.lc-br-elem-row{width:100%;color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;text-align:left;background:0 0;border:0;border-radius:6px;align-items:center;gap:8px;padding:5px 6px;font-size:12px;transition:background-color .12s;display:flex}.lc-br-elem-row:hover{background:var(--dsw-alias-interactive-bg-hover)}.lc-br-tag{color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);text-overflow:ellipsis;white-space:nowrap;border-radius:4px;flex:none;max-width:220px;padding:0 6px;font-size:11px;overflow:hidden}.lc-br-preview{text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;overflow:hidden}.lc-br-time{color:var(--dsw-alias-label-secondary);flex:none;font-size:11px}.lc-br-content{flex-direction:column;gap:6px;padding:2px 6px 8px 26px;display:flex}.lc-br-dim{color:var(--dsw-alias-label-secondary)}.lc-ts-card{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:6px;overflow:hidden}.lc-ts-card-head{color:var(--dsw-alias-label-secondary);border-bottom:1px solid var(--dsw-alias-border-l1);align-items:center;gap:8px;padding:6px 10px;font-size:11px;font-weight:600;display:flex}.lc-ts-card-head b{color:var(--dsw-alias-label-primary)}.lc-ts-call-name{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:13px}.lc-ts-card-count{margin-left:auto}.lc-ts-desc-body{color:var(--dsw-alias-label-primary);white-space:pre-wrap;word-break:break-word;scrollbar-width:thin;max-height:320px;margin:0;padding:8px 10px;font-size:12px;line-height:1.55;overflow-y:auto}.lc-ts-param-row{border-top:1px solid var(--dsw-alias-border-l1);grid-template-columns:140px 90px 56px 1fr;align-items:baseline;gap:2px 10px;padding:6px 10px;font-size:12px;display:grid}.lc-ts-param-row:first-of-type{border-top:0}.lc-ts-param-name{color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;font-weight:600;overflow:hidden}.lc-ts-param-type{color:var(--dsw-alias-label-secondary);text-overflow:ellipsis;white-space:nowrap;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px;overflow:hidden}.lc-ts-param-req{color:var(--dsw-alias-state-warn-primary);font-size:11px;font-weight:600}.lc-ts-param-req-off{color:var(--dsw-alias-label-secondary);font-size:11px}.lc-ts-param-desc{color:var(--dsw-alias-label-secondary);grid-column:1/-1;line-height:1.5}.lc-ts-params-empty{color:var(--dsw-alias-label-secondary);padding:8px 10px;font-size:12px}.lc-ts-arg-row{border-top:1px solid var(--dsw-alias-border-l1);grid-template-columns:minmax(0,96px) 1fr;align-items:start;column-gap:12px;padding:6px 10px;font-size:12px;display:grid}.lc-ts-arg-row:first-of-type{border-top:0}.lc-ts-arg-row .lc-ts-param-name{text-overflow:unset;white-space:normal;overflow-wrap:anywhere;overflow:visible}.lc-ts-arg-val{color:var(--dsw-alias-label-primary);white-space:pre-wrap;word-break:break-word;scrollbar-width:thin;max-height:200px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;line-height:1.55;overflow-y:auto}.lc-ts-json{flex-direction:column;gap:4px;display:flex}.lc-ts-json-toggle{color:var(--dsw-alias-label-secondary);font:inherit;cursor:pointer;background:0 0;border:0;align-self:flex-start;padding:0;font-size:11px}.lc-ts-json-toggle:hover{color:var(--dsw-alias-label-primary);text-decoration:underline}.lc-rich-seg{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:6px;gap:2px;margin-left:auto;padding:1px;display:flex}.lc-rich-seg-btn{color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;border-radius:5px;padding:3px 8px;font-family:inherit;font-size:11px;line-height:1}.lc-rich-seg-btn:hover{color:var(--dsw-alias-label-primary)}.lc-rich-seg-on,.lc-rich-seg-on:hover{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground)}.lc-ts-desc-md{color:var(--dsw-alias-label-primary);word-break:break-word;scrollbar-width:thin;max-height:320px;padding:4px 10px;font-size:12px;line-height:1.55;overflow-y:auto}.lc-ts-desc-md>div{font-size:13px;line-height:1.55}.lc-ts-desc-md div :is(h1,h2,h3,h4,h5,h6){margin:10px 0 4px;font-size:13px;font-weight:600}.lc-ts-desc-md div p,.lc-ts-desc-md div pre{margin:6px 0}.lc-ts-desc-md div :not(pre)>code{box-decoration-break:clone;padding:1px 5px;line-height:1.3;font-size:1em!important}.lc-ts-desc-md div table code{font-size:inherit}.lc-att-grid{grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;padding:8px 10px;display:grid}.lc-att-item{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l1);width:100%;min-width:0;font:inherit;text-align:left;cursor:pointer;background:0 0;border-radius:8px;align-items:center;gap:8px;padding:6px;display:flex}.lc-att-item:hover{border-color:var(--dsw-alias-border-l2,var(--dsw-alias-border-l1));background:var(--dsw-alias-interactive-bg-hover,var(--dsw-alias-bg-layer-2))}.lc-att-thumb{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);border-radius:6px;flex:none;justify-content:center;align-items:center;width:64px;height:64px;padding:0;display:flex;overflow:hidden}.lc-att-thumb img{object-fit:cover;width:100%;height:100%;display:block}.lc-att-ph,.lc-att-err{color:var(--dsw-alias-label-secondary);text-align:center;padding:2px;font-size:10px}.lc-att-meta{flex-direction:column;gap:2px;min-width:0;display:flex}.lc-att-name{color:var(--dsw-alias-label-primary);overflow-wrap:anywhere;word-break:break-word;font-size:12px;line-height:1.3}.lc-att-row{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;font-size:11px}.lc-att-row-label{min-width:3.2em;font-weight:400;display:inline-block}.lc-att-lightbox{z-index:1000;place-items:center;padding:40px;display:grid;position:fixed;inset:0}.lc-att-lightbox-mask{background:var(--dsw-alias-bg-mask-1,#00000073);backdrop-filter:var(--dsw-mask-blur,blur(2px));position:absolute;inset:0}.lc-att-lightbox-img{object-fit:contain;background:var(--dsw-specific-input-major,var(--dsw-alias-bg-layer-1));max-width:min(100%,1600px);max-height:calc(100vh - 80px);box-shadow:var(--dsw-shadow-lv3,0 12px 32px #0006);border-radius:12px;position:relative}.lc-att-lightbox-close{z-index:1;border:1px solid var(--dsw-alias-border-l2-darkmode-thin,var(--dsw-alias-border-l1));background:var(--dsw-specific-input-major,var(--dsw-alias-bg-layer-1));width:36px;height:36px;color:var(--dsw-alias-label-primary);cursor:pointer;border-radius:999px;place-items:center;padding:0;display:grid;position:fixed;top:20px;right:20px}[data-conversation-scroll]:has(.lc-root)>[data-composer-seat]:not(:has([data-approval-key],[data-question-key],[data-plan-review-key])){display:none}";
2678
2755
  const tagId = "dsh-context/styles.css";
2679
2756
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
2680
2757
  const tag = document.createElement("style");
package/lib/index.d.ts CHANGED
@@ -109,11 +109,19 @@ interface Snapshot {
109
109
  tokens: number;
110
110
  }[];
111
111
  /**
112
- * Cumulative image-block count over the COMPLETE session log (user uploads
113
- * plus tool-result images) — never trimmed, like `cost`. Absent from older
114
- * hosts; clients treat absence as zero.
112
+ * Image blocks live in the CURRENT context (user uploads plus tool-result
113
+ * images, nested blocks included) — the sum over the live surface nodes'
114
+ * `imgs`, so compaction/prune shrink it. Absent from older hosts; clients
115
+ * treat absence as zero.
115
116
  */
116
117
  images?: number;
118
+ /**
119
+ * Tool calls whose result is live in the CURRENT context (one `tool/result`
120
+ * folds to one `tool` surface node). Calls still in flight and results
121
+ * compacted/pruned out of the surface are not counted. Absent from older
122
+ * hosts; clients treat absence as zero.
123
+ */
124
+ toolCalls?: number;
117
125
  requests: RequestRecord[];
118
126
  events: ContextEventRecord[];
119
127
  /**
@@ -198,6 +206,8 @@ interface SurfaceNode {
198
206
  time?: number;
199
207
  cat: Category;
200
208
  tokens: number;
209
+ /** Image blocks inside this node's message (absent when zero). */
210
+ imgs?: number;
201
211
  /**
202
212
  * Removal marker, present only on `archive` entries: the seq of the
203
213
  * replacement surface event that shadowed this node (compaction/prune).
@@ -243,12 +253,14 @@ interface RequestRecord {
243
253
  interface ContextEventRecord {
244
254
  seq: number;
245
255
  time: number;
246
- kind: 'compaction' | 'prune' | 'inject' | 'model';
256
+ kind: 'compaction' | 'prune' | 'inject' | 'model' | 'mode';
247
257
  form?: string;
248
258
  tokens?: number;
249
259
  count?: number;
250
260
  sub?: string;
251
261
  name?: string;
262
+ /** One-line producer account (notice-form summary), shown after the name. */
263
+ detail?: string;
252
264
  from?: string;
253
265
  to?: string;
254
266
  /** Turn/step of the request logged right BEFORE the event (host-stamped). */
@@ -339,12 +351,6 @@ interface TimelineState {
339
351
  * Absent until a v4-flash / v4-pro request reports usage.
340
352
  */
341
353
  cost?: SessionCostUsage;
342
- /**
343
- * Cumulative image-block count over the COMPLETE session log (user uploads
344
- * plus tool-result images, nested blocks included) — running total, never
345
- * trimmed, so the stats board's image cell stays whole-session like cost.
346
- */
347
- images: number;
348
354
  /** Newest `gone` among archive entries dropped by the retention bounds. */
349
355
  archiveFloor?: number;
350
356
  /**
@@ -365,6 +371,14 @@ interface TimelineState {
365
371
  * to keep the state plain JSON for the projection cache.
366
372
  */
367
373
  pendingShadowedSeqs?: number[];
374
+ /**
375
+ * The seq of the compaction/prune event that armed `pendingShadowedSeqs` —
376
+ * the shadowed path rewrites that event's `tokens` from the gross shadow
377
+ * price to the NET freed amount (removed nodes minus the synchronous
378
+ * replacement), so the row matches the drop the trend chart shows. Same
379
+ * arm/remove lifecycle as `pendingShadowedSeqs`.
380
+ */
381
+ pendingShadowEventSeq?: number;
368
382
  }
369
383
  //#endregion
370
384
  //#region node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.8_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_c0ffab70d18276fadfe75ed916313ea3/node_modules/@deepseek-ai/dsh-session-projection/lib/types/types.d.ts
package/lib/index.js CHANGED
@@ -254,8 +254,27 @@ function toolCallNames(blocks) {
254
254
  for (const b of blocks) if (b.type === "tool-call" && typeof b.name === "string") names.push(b.name);
255
255
  return names;
256
256
  }
257
+ /**
258
+ * Producer label for an injection event, mirroring the dsh transcript's
259
+ * context provenance (client-runtime context-provenance.ts): workspace
260
+ * instructions name the files they were reconciled from, a plugin source its
261
+ * plugin id, and any other producer its own durable kind. Returns '' when
262
+ * the source carries no readable identity at all.
263
+ */
264
+ function injectionSourceName(source) {
265
+ if (source.kind === "agent-instructions" && Array.isArray(source.changes)) {
266
+ const paths = [];
267
+ for (const change of source.changes) {
268
+ const path = change?.path;
269
+ if (typeof path === "string" && path !== "" && !paths.includes(path)) paths.push(path);
270
+ }
271
+ if (paths.length > 0) return paths.join(", ");
272
+ }
273
+ if (typeof source.plugin === "string" && source.plugin !== "") return source.plugin;
274
+ return typeof source.kind === "string" && source.kind !== "" ? source.kind : "";
275
+ }
257
276
  function isInjection(source) {
258
- return source !== null && source !== void 0 && (source.kind === "plugin" || source.kind === "skill-invocation" || typeof source.form === "string");
277
+ return source !== null && source !== void 0 && (typeof source.kind === "string" && source.kind !== "" && source.kind !== "user" || typeof source.form === "string");
259
278
  }
260
279
  //#endregion
261
280
  //#region src/host/headers.ts
@@ -416,8 +435,7 @@ function createTimelineState() {
416
435
  requests: [],
417
436
  events: [],
418
437
  archived: [],
419
- callNames: {},
420
- images: 0
438
+ callNames: {}
421
439
  };
422
440
  }
423
441
  function categoryOf(type, message) {
@@ -465,13 +483,14 @@ function skillNameOf(msg) {
465
483
  }
466
484
  function applySurface(st, ev, type, data, message) {
467
485
  const cat = categoryOf(type, message ?? void 0);
468
- st.images = st.images + imageCountOf(message?.content);
469
486
  const node = {
470
487
  seq: ev.seq,
471
488
  time: ev.time,
472
489
  cat,
473
490
  tokens: estimateMessage(message, type === "assistant/message")
474
491
  };
492
+ const imgs = imageCountOf(message?.content);
493
+ if (imgs > 0) node.imgs = imgs;
475
494
  const source = message?.source;
476
495
  const form = source?.form;
477
496
  if (typeof form === "string") node.form = form;
@@ -507,7 +526,9 @@ function applySurface(st, ev, type, data, message) {
507
526
  if (utext !== "") node.text = utext;
508
527
  }
509
528
  const shadowedSeqs = st.pendingShadowedSeqs;
529
+ const shadowEventSeq = st.pendingShadowEventSeq;
510
530
  delete st.pendingShadowedSeqs;
531
+ delete st.pendingShadowEventSeq;
511
532
  const op = ev.surfaceOp;
512
533
  if (op !== null && typeof op === "object" && op.op === "replace") {
513
534
  if (Array.isArray(shadowedSeqs) && shadowedSeqs.length > 0) {
@@ -522,6 +543,14 @@ function applySurface(st, ev, type, data, message) {
522
543
  st.surface = kept;
523
544
  st.sums[cat] += node.tokens;
524
545
  st.surface.push(node);
546
+ if (shadowEventSeq !== void 0) {
547
+ const removedSum = removed.reduce((sum, n) => sum + n.tokens, 0);
548
+ const i = st.events.findIndex((e) => e.seq === shadowEventSeq);
549
+ if (i >= 0) st.events[i] = {
550
+ ...st.events[i],
551
+ tokens: Math.max(0, removedSum - node.tokens)
552
+ };
553
+ }
525
554
  return node;
526
555
  }
527
556
  let si = -1;
@@ -633,7 +662,7 @@ function applyTimeline(state, event, bounds) {
633
662
  s.systemTokens = estimateSystem(header.system);
634
663
  if (header.config && typeof header.config.model === "string") s.model = header.config.model;
635
664
  if (header.config && typeof header.config.provider === "string") s.provider = header.config.provider;
636
- if (data?.reason === "change" && s.model && s.lastModel && s.model !== s.lastModel) s.events.push({
665
+ if ((data?.reason === "change" || data?.reason === "resume") && s.model && s.lastModel && s.model !== s.lastModel) s.events.push({
637
666
  seq: event.seq,
638
667
  time: event.time,
639
668
  kind: "model",
@@ -672,7 +701,11 @@ function applyTimeline(state, event, bounds) {
672
701
  if (source.kind === "skill-invocation") {
673
702
  rec.sub = "skill";
674
703
  rec.name = typeof source.name === "string" ? source.name : "?";
675
- } else if (typeof source.plugin === "string" && source.plugin !== "") rec.name = source.plugin;
704
+ } else {
705
+ const label = injectionSourceName(source);
706
+ if (label !== "") rec.name = label;
707
+ if (source.form === "notice" && typeof source.summary === "string" && source.summary !== "") rec.detail = source.summary;
708
+ }
676
709
  s.events.push(rec);
677
710
  }
678
711
  break;
@@ -725,10 +758,21 @@ function applyTimeline(state, event, bounds) {
725
758
  applySurface(s, event, event.type, data, asstMsg);
726
759
  break;
727
760
  }
761
+ case "plan/mode":
762
+ if (data && typeof data.active === "boolean") ensure().events.push({
763
+ seq: event.seq,
764
+ time: event.time,
765
+ kind: "mode",
766
+ name: data.active ? "plan.on" : "plan.off"
767
+ });
768
+ break;
728
769
  case "compaction/summary":
729
770
  case "compaction/prune": {
730
771
  const s = ensure();
731
- if (data && Array.isArray(data.shadowedSeqs)) s.pendingShadowedSeqs = data.shadowedSeqs.filter((x) => typeof x === "number");
772
+ if (data && Array.isArray(data.shadowedSeqs)) {
773
+ s.pendingShadowedSeqs = data.shadowedSeqs.filter((x) => typeof x === "number");
774
+ s.pendingShadowEventSeq = event.seq;
775
+ }
732
776
  s.events.push({
733
777
  seq: event.seq,
734
778
  time: event.time,
@@ -769,7 +813,8 @@ function buildTimelineView(state, bounds) {
769
813
  total: surfaceTotal + state.systemTokens + state.toolsTokens
770
814
  },
771
815
  toolList: state.toolList,
772
- images: state.images,
816
+ images: state.surface.reduce((n, node) => n + (node.imgs ?? 0), 0),
817
+ toolCalls: state.surface.reduce((n, node) => node.cat === "tool" ? n + 1 : n, 0),
773
818
  requests: state.requests.map((r) => ({ ...r })),
774
819
  events: state.events.map((e) => ({ ...e })),
775
820
  nodes: [],
@@ -852,6 +897,7 @@ const surfaceNodeSchema = z.object({
852
897
  "tool"
853
898
  ]),
854
899
  tokens: z.number().int().nonnegative(),
900
+ imgs: z.number().int().nonnegative().optional(),
855
901
  gone: z.number().int().nonnegative().optional(),
856
902
  form: z.string().optional(),
857
903
  text: z.string().optional(),
@@ -883,13 +929,15 @@ const contextEventSchema = z.object({
883
929
  "compaction",
884
930
  "prune",
885
931
  "inject",
886
- "model"
932
+ "model",
933
+ "mode"
887
934
  ]),
888
935
  form: z.string().optional(),
889
936
  tokens: z.number().optional(),
890
937
  count: z.number().optional(),
891
938
  sub: z.string().optional(),
892
939
  name: z.string().optional(),
940
+ detail: z.string().optional(),
893
941
  from: z.string().optional(),
894
942
  to: z.string().optional(),
895
943
  fromTurn: z.number().optional(),
@@ -927,6 +975,7 @@ const contextTimelineSchema = z.object({
927
975
  tokens: z.number().int().nonnegative()
928
976
  }).strict()),
929
977
  images: z.number().int().nonnegative().optional(),
978
+ toolCalls: z.number().int().nonnegative().optional(),
930
979
  requests: z.array(requestRecordSchema),
931
980
  events: z.array(contextEventSchema),
932
981
  cost: z.object({
@@ -970,10 +1019,10 @@ const timelineStateSchema = z.object({
970
1019
  flash: costFamilySchema.optional(),
971
1020
  pro: costFamilySchema.optional()
972
1021
  }).strict().optional(),
973
- images: z.number().int().nonnegative().optional(),
974
1022
  archiveFloor: z.number().optional(),
975
1023
  callNames: z.record(z.string(), z.string()),
976
- pendingShadowedSeqs: z.array(z.number()).optional()
1024
+ pendingShadowedSeqs: z.array(z.number()).optional(),
1025
+ pendingShadowEventSeq: z.number().optional()
977
1026
  });
978
1027
  /**
979
1028
  * The context-timeline projection unit, created per plugin instance with its
@@ -1006,7 +1055,7 @@ function createContextTimelineDefinition(config) {
1006
1055
  },
1007
1056
  init: () => createTimelineState(),
1008
1057
  apply: (state, event) => applyTimeline(state, event, bounds),
1009
- stateVersion: 7
1058
+ stateVersion: 8
1010
1059
  };
1011
1060
  }
1012
1061
  //#endregion
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-context",
3
- "version": "0.26.1",
3
+ "version": "0.28.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": {