dsh-context 0.45.0 → 0.46.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +3 -3
  2. package/lib/client.js +270 -174
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -8,19 +8,19 @@
8
8
 
9
9
  **The best [DeepSeek Harness plugin](https://www.deepseek.com/harness/) for Agent's context insights and management.**
10
10
 
11
- `dsh-context` provides full context lifecycle management features.
11
+ [`dsh-context`](https://www.npmjs.com/package/dsh-context) provides full context lifecycle management features.
12
12
  - **Context tab** — an UI context dashboard for DeepSeek Harness's context stats, composition, trend, events, and messages.
13
13
  - **`/context` command** — the slash command shows the context model for current context composition and recent context evolution.
14
14
 
15
15
  ## Install / Update
16
16
 
17
- To Install from any DeepSeek Harness installation:
17
+ Install [`dsh-context`](https://www.npmjs.com/package/dsh-context) plugin from [DeepSeek Harness](https://www.npmjs.com/package/@deepseek-ai/dsh):
18
18
 
19
19
  ```sh
20
20
  dsh plugin --profile web add dsh-context
21
21
  ```
22
22
 
23
- Or to update the `dsh-context` plugin:
23
+ Or update the `dsh-context` plugin:
24
24
 
25
25
  ```sh
26
26
  dsh plugin --profile web update dsh-context@latest
package/lib/client.js CHANGED
@@ -72,8 +72,9 @@ window.__ModuleLoader__.load({
72
72
  "gran.total": "全量",
73
73
  "gran.delta": "增量",
74
74
  "gran.modeHint": "全量:累计构成;增量:相对上一条请求的变化量",
75
- "trend.hint": "✂ 表示压缩/剪枝,步骤/轮次 切换粒度",
76
75
  "trend.focus": "仅展示 {cat}",
76
+ "trend.adaptive": "自适应",
77
+ "trend.adaptiveHint": "按当前可视范围内的柱子重新缩放高度,滚动时随之变化",
77
78
  "trend.empty": "发起一轮对话后,这里会展示每次模型请求的上下文构成",
78
79
  "detail.step": "第 {t} 轮 · 第 {s} 步",
79
80
  "detail.turn": "第 {t} 轮 · 共 {n} 步",
@@ -89,7 +90,6 @@ window.__ModuleLoader__.load({
89
90
  "brief.noInputs": "(无新增)",
90
91
  "brief.locate": "在上下文浏览器中查看",
91
92
  "jump.title": "在上下文标签页中查看此轮",
92
- "jump.statsLine": "在上下文标签页中查看上下文构成",
93
93
  "brief.turnTip": "这一轮开场时用户发送的消息;回合内的每一步都会回显同一条",
94
94
  "brief.inputTip": "上一步回复之后、本次请求发出前新进入上下文的内容——通常是上一步所调工具的结果;每轮的第一步无新增",
95
95
  "brief.replyTip": "这一步模型返回的内容(文本回复或工具调用);此步发起的调用,其结果会出现在下一柱的「输入」行",
@@ -234,6 +234,8 @@ window.__ModuleLoader__.load({
234
234
  "browser.missingLive": "… 另有 {n} 条更早的消息也在上下文中(超出展示窗口)",
235
235
  "browser.approx": "该步骤涉及的部分已移除消息超出保留范围,以下为近似构成",
236
236
  "browser.deltaHint": "对比上轮末步的变动",
237
+ "browser.dna": "DNA 模式",
238
+ "browser.dnaTip": "按模型读取上下文的次序逐条展示每一项:系统提示词、工具定义,然后是按时间排列的消息;悬停查看条目,点击定位到下方列表",
237
239
  "browser.noHeader": "此数据来自旧版插件:仅提供 token 估算,无实际内容",
238
240
  "browser.noEpoch": "该步骤的头部内容(系统提示词 / 工具定义)不在保留范围内",
239
241
  "browser.headerMetaOnly": "此环境不支持按需读取头部内容,仅显示 token 估算",
@@ -356,8 +358,9 @@ window.__ModuleLoader__.load({
356
358
  "gran.total": "Total",
357
359
  "gran.delta": "Delta",
358
360
  "gran.modeHint": "Total: cumulative makeup; Delta: change vs the previous request",
359
- "trend.hint": "✂ marks compaction/prune, Step/Turn switches granularity",
360
361
  "trend.focus": "Showing {cat} only",
362
+ "trend.adaptive": "Adaptive",
363
+ "trend.adaptiveHint": "Rescale bar heights to the visible range, following the scroll",
361
364
  "trend.empty": "Send a message and each model request’s context makeup shows up here",
362
365
  "detail.step": "Turn {t} · Step {s}",
363
366
  "detail.turn": "Turn {t} · {n} steps",
@@ -373,7 +376,6 @@ window.__ModuleLoader__.load({
373
376
  "brief.noInputs": "(nothing new)",
374
377
  "brief.locate": "Reveal in Context Browser",
375
378
  "jump.title": "View this turn in the Context tab",
376
- "jump.statsLine": "View the context composition in the Context tab",
377
379
  "brief.turnTip": "The user message that opened this turn — every step of the turn recalls it",
378
380
  "brief.inputTip": "What entered after the previous reply and before this request went out — usually the previous tool-call results; a turn opener has nothing new",
379
381
  "brief.replyTip": "What the model returned on this step (a text reply or tool calls) — results of calls made here appear in the In row of the next bar",
@@ -518,6 +520,8 @@ window.__ModuleLoader__.load({
518
520
  "browser.missingLive": "… {n} earlier messages are also part of the context (outside the served window)",
519
521
  "browser.approx": "Some removed messages of this step exceed retention — the makeup below is approximate",
520
522
  "browser.deltaHint": "vs previous turn",
523
+ "browser.dna": "DNA Mode",
524
+ "browser.dnaTip": "One band per item in the order the model reads the context — system prompt, tool schemas, then messages chronologically; hover for details, click to open its row below",
521
525
  "browser.noHeader": "Served by an older plugin build: token estimates only, no content",
522
526
  "browser.noEpoch": "The header content (System Prompt / Tool Schemas) of this step is outside retention",
523
527
  "browser.headerMetaOnly": "This environment cannot fetch header content on demand; token estimates only",
@@ -715,6 +719,8 @@ window.__ModuleLoader__.load({
715
719
  color: "#14b8a6"
716
720
  }
717
721
  ];
722
+ /** Category key → bar color, for per-item bands (the browser's DNA mode) that bypass the CATS-order part builders. */
723
+ const CAT_COLOR = Object.fromEntries(CATS.map((c) => [c.key, c.color]));
718
724
  const MESSAGE_CATS = [
719
725
  "user",
720
726
  "inject",
@@ -1891,6 +1897,32 @@ window.__ModuleLoader__.load({
1891
1897
  };
1892
1898
  }
1893
1899
  //#endregion
1900
+ //#region src/client/dna.ts
1901
+ function dnaOf(view) {
1902
+ const items = [];
1903
+ if (view.header !== null) {
1904
+ if (view.header.systemTokens !== void 0) items.push({
1905
+ key: "sys",
1906
+ cat: "system",
1907
+ tokens: view.header.systemTokens,
1908
+ time: view.header.time
1909
+ });
1910
+ for (const tool of view.header.tools) items.push({
1911
+ key: "tool:" + tool.name,
1912
+ cat: "tools",
1913
+ tokens: tool.tokens
1914
+ });
1915
+ }
1916
+ for (const n of view.nodes) items.push({
1917
+ key: "n" + String(n.seq),
1918
+ cat: n.cat,
1919
+ tokens: n.tokens,
1920
+ node: n,
1921
+ ...n.time !== void 0 ? { time: n.time } : {}
1922
+ });
1923
+ return items;
1924
+ }
1925
+ //#endregion
1894
1926
  //#region src/shared/fileOps.ts
1895
1927
  /** Parse a call's raw JSON arguments; non-string/malformed/non-record inputs yield null. */
1896
1928
  function parseCallArgs(raw) {
@@ -3193,6 +3225,11 @@ window.__ModuleLoader__.load({
3193
3225
  for (let i = requests.length - 1; i >= 0; i--) if ((requests[i].turn ?? 0) === turn) return requests[i];
3194
3226
  return null;
3195
3227
  }
3228
+ /**
3229
+ * DNA bands keep at least this share of the occupied region, so a tiny item (a 25-token user message in a 40k
3230
+ * context) stays a hoverable/clickable filament instead of a sub-pixel sliver. Tooltips still report true shares.
3231
+ */
3232
+ const DNA_MIN_BAND = .35;
3196
3233
  function makeContextBrowser(kit, StackedBar) {
3197
3234
  const { t, fmt, fmtTime, catLabel } = kit;
3198
3235
  const DetailNote = makeDetailNote(kit);
@@ -3207,6 +3244,8 @@ window.__ModuleLoader__.load({
3207
3244
  const [openElem, setOpenElem] = (0, react.useState)(null);
3208
3245
  const [rowQuery, setRowQuery] = (0, react.useState)("");
3209
3246
  const [toolSort, setToolSort] = (0, react.useState)("size");
3247
+ const [dna, setDna] = (0, react.useState)(false);
3248
+ const [dnaKey, setDnaKey] = (0, react.useState)(null);
3210
3249
  const onOpenCat = props.onOpenCat;
3211
3250
  const setCat = (c) => {
3212
3251
  setOpenCat(c);
@@ -3269,6 +3308,7 @@ window.__ModuleLoader__.load({
3269
3308
  const breakdown = req !== null ? req : data.current;
3270
3309
  const parts = partsOf(breakdown);
3271
3310
  const total = breakdown.total;
3311
+ const pinKey = openCat !== null && (breakdown[openCat] || 0) > 0 ? openCat : null;
3272
3312
  const pick = (v) => {
3273
3313
  setSel(v === "live" ? "live" : Number(v));
3274
3314
  setCat(null);
@@ -3278,6 +3318,34 @@ window.__ModuleLoader__.load({
3278
3318
  const prevView = refReq !== null ? assemble(data, headers, refReq.seq) : null;
3279
3319
  const prevByCat = prevView !== null ? byCatOf(prevView) : null;
3280
3320
  const byCat = byCatOf(view);
3321
+ const dnaLabel = (it) => {
3322
+ let base;
3323
+ if (!("node" in it)) base = it.cat === "system" ? catLabel("system") : it.key.slice(5);
3324
+ else {
3325
+ const n = it.node;
3326
+ base = n.skill !== void 0 ? t("node.skillTag", { name: n.skill }) : n.cat === "tool" ? n.tool ?? "?" : n.cat === "inject" ? t("form." + (n.form || "context")) : catLabel(n.cat);
3327
+ }
3328
+ return it.time !== void 0 ? base + " · " + fmtTime(it.time) : base;
3329
+ };
3330
+ const dnaItems = dna ? dnaOf(view) : null;
3331
+ const dnaByKey = new Map(dnaItems?.map((it) => [it.key, it]) ?? []);
3332
+ const dnaParts = dnaItems?.map((it) => ({
3333
+ key: it.key,
3334
+ color: CAT_COLOR[it.cat],
3335
+ value: it.tokens,
3336
+ label: dnaLabel(it),
3337
+ group: it.cat
3338
+ })) ?? null;
3339
+ const liveDnaKey = dnaKey !== null && dnaByKey.has(dnaKey) ? dnaKey : null;
3340
+ const pickDna = (key) => {
3341
+ const it = dnaByKey.get(key);
3342
+ /* v8 ignore next 1 -- the bar only reports keys of the parts it was handed; defensive. */
3343
+ if (it === void 0) return;
3344
+ setCat(it.cat);
3345
+ setRowQuery("");
3346
+ setOpenElem(key);
3347
+ focusScrollRef.current = true;
3348
+ };
3281
3349
  const toolCount = (c) => countOf(view, byCat, c);
3282
3350
  const singleKeyOf = (c) => {
3283
3351
  if (c === "system") return view.header?.systemTokens !== void 0 ? "sys" : null;
@@ -3511,6 +3579,19 @@ window.__ModuleLoader__.load({
3511
3579
  className: "lc-card-title-text",
3512
3580
  children: t("browser.title")
3513
3581
  }),
3582
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3583
+ className: "lc-gran lc-br-dna-ctl",
3584
+ role: "group",
3585
+ title: t("browser.dnaTip"),
3586
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3587
+ type: "button",
3588
+ className: "lc-gran-btn" + (dna ? " lc-gran-on" : ""),
3589
+ onClick: () => {
3590
+ setDna((on) => !on);
3591
+ },
3592
+ children: t("browser.dna")
3593
+ })
3594
+ }),
3514
3595
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3515
3596
  className: "lc-br-hint",
3516
3597
  children: t("browser.deltaHint")
@@ -3554,13 +3635,15 @@ window.__ModuleLoader__.load({
3554
3635
  ]
3555
3636
  }),
3556
3637
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3557
- className: "lc-br-bar",
3638
+ className: "lc-br-bar" + (dna ? " lc-br-bar-dna" : ""),
3558
3639
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StackedBar, {
3559
- parts,
3640
+ parts: dnaParts ?? parts,
3560
3641
  height: 10,
3561
- hoverKey: linked ? linkKey : void 0,
3562
- onHoverKey: linked ? props.onHoverKey : void 0,
3563
- tip: false
3642
+ hoverKey: dna ? liveDnaKey ?? linkKey ?? pinKey : linkKey ?? pinKey,
3643
+ onHoverKey: dna ? setDnaKey : linked ? props.onHoverKey : void 0,
3644
+ tip: dna,
3645
+ onPickKey: dna ? pickDna : void 0,
3646
+ minBand: dna ? DNA_MIN_BAND : void 0
3564
3647
  })
3565
3648
  }),
3566
3649
  view.missingLive > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -3674,6 +3757,24 @@ window.__ModuleLoader__.load({
3674
3757
  const usedPct = scale > 0 ? total / scale * 100 : 0;
3675
3758
  const hovering = props.hoverKey !== null && props.hoverKey !== void 0;
3676
3759
  const showBox = free > 0 && hovering;
3760
+ const pickKey = props.onPickKey;
3761
+ const minBand = props.minBand !== void 0 && props.minBand > 0 ? props.minBand : 0;
3762
+ const visible = total > 0 ? props.parts.filter((p) => p.value > 0) : [];
3763
+ const widths = (() => {
3764
+ if (minBand === 0 || visible.length < 2) return visible.map((p) => p.value / scale * 100);
3765
+ const shares = visible.map((p) => p.value / total * 100);
3766
+ const floor = Math.min(minBand, 100 / visible.length);
3767
+ let pinned = 0;
3768
+ let pinnedRaw = 0;
3769
+ for (const s of shares) if (s < floor) {
3770
+ pinned += 1;
3771
+ pinnedRaw += s;
3772
+ }
3773
+ if (pinned === 0) return visible.map((p) => p.value / scale * 100);
3774
+ const restRoom = 100 - pinned * floor;
3775
+ const restRaw = 100 - pinnedRaw;
3776
+ return shares.map((s) => (s < floor ? floor : s * restRoom / restRaw) * total / scale);
3777
+ })();
3677
3778
  const reserve = props.reserve !== void 0 && props.max !== void 0 && props.max > 0 ? {
3678
3779
  ...props.reserve,
3679
3780
  max: props.max
@@ -3696,17 +3797,17 @@ window.__ModuleLoader__.load({
3696
3797
  let acc = 0;
3697
3798
  let rawTotal = 0;
3698
3799
  for (const p of props.parts) rawTotal += p.raw ?? p.value;
3699
- for (const p of props.parts) {
3700
- const pct = scale > 0 ? p.value / scale * 100 : 0;
3701
- if (p.key === props.hoverKey && p.value > 0) {
3800
+ for (let i = 0; i < visible.length; i++) {
3801
+ const p = visible[i];
3802
+ if (p.key === props.hoverKey) {
3702
3803
  const count = p.raw ?? p.value;
3703
3804
  tip = {
3704
- text: `${catLabel(p.key)} ≈${fmt(count)} (${rawTotal > 0 ? Math.round(count / rawTotal * 100) : 0}%) ` + t("overview.ofUsed"),
3705
- leftPct: Math.max(12, Math.min(acc + pct / 2, 88))
3805
+ text: `${p.label ?? catLabel(p.key)} ≈${fmt(count)} (${rawTotal > 0 ? Math.round(count / rawTotal * 100) : 0}%) ` + t("overview.ofUsed"),
3806
+ leftPct: Math.max(12, Math.min(acc + widths[i] / 2, 88))
3706
3807
  };
3707
3808
  break;
3708
3809
  }
3709
- acc += pct;
3810
+ acc += widths[i];
3710
3811
  }
3711
3812
  }
3712
3813
  }
@@ -3720,20 +3821,22 @@ window.__ModuleLoader__.load({
3720
3821
  setReserveOn(false);
3721
3822
  },
3722
3823
  children: [
3723
- total > 0 ? props.parts.map((p) => {
3724
- if (!p.value) return null;
3725
- const on = props.hoverKey !== void 0 && props.hoverKey === p.key;
3824
+ visible.map((p, i) => {
3825
+ const on = props.hoverKey !== void 0 && (props.hoverKey === p.key || p.group !== void 0 && props.hoverKey === p.group);
3726
3826
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3727
- className: "lc-stacked-seg" + (on ? " lc-stacked-seg-on" : ""),
3827
+ className: "lc-stacked-seg" + (on ? " lc-stacked-seg-on" : "") + (pickKey !== void 0 ? " lc-stacked-seg-pick" : ""),
3728
3828
  style: {
3729
- width: `${p.value / scale * 100}%`,
3829
+ width: `${widths[i]}%`,
3730
3830
  background: p.color
3731
3831
  },
3732
3832
  onMouseEnter: () => {
3733
3833
  if (props.onHoverKey !== void 0) props.onHoverKey(p.key);
3734
- }
3834
+ },
3835
+ onClick: pickKey !== void 0 ? () => {
3836
+ pickKey(p.key);
3837
+ } : void 0
3735
3838
  }, p.key);
3736
- }) : null,
3839
+ }),
3737
3840
  free > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3738
3841
  className: "lc-stacked-free" + (props.hoverKey === "free" ? " lc-stacked-free-on" : ""),
3739
3842
  style: { width: `${free / scale * 100}%` },
@@ -5056,6 +5159,35 @@ window.__ModuleLoader__.load({
5056
5159
  for (const r of requests) if (r.seq > seq && (gone === void 0 || gone > r.seq)) return r.seq;
5057
5160
  return gone === void 0 ? "live" : null;
5058
5161
  }
5162
+ //#endregion
5163
+ //#region src/client/overscroll.ts
5164
+ /**
5165
+ * Stop a horizontal scroller's overscroll from reaching the browser's history navigation — the trackpad
5166
+ * swipe-back (left edge) and swipe-forward (right edge) gestures. The spec answer is `overscroll-behavior-x:
5167
+ * contain`, the harness's own idiom for its horizontal scrollers and what the sheets beside this module's
5168
+ * callers already set; it covers Chromium and Firefox, but WebKit still navigates on horizontal overscroll with
5169
+ * the property set (bug 240183), where a canceled wheel is the only lever. Without either, one swipe past the
5170
+ * edge of the trend chart or the agent graph leaves the whole app for another page in the tab's history.
5171
+ */
5172
+ /**
5173
+ * Cancel the horizontal-dominant wheel gestures a scroller cannot consume — the ones the browser would
5174
+ * otherwise read as a history swipe. Vertical-dominant gestures are left alone: they belong to the page's own
5175
+ * scrolling, and the scrollers this guards only overflow horizontally.
5176
+ * @param el - the horizontal scroll container (the listener must be non-passive, so it cannot ride React's passive wheel seat).
5177
+ * @returns the disposer removing the listener.
5178
+ */
5179
+ function containHorizontalOverscroll(el) {
5180
+ const onWheel = (e) => {
5181
+ if (Math.abs(e.deltaX) <= Math.abs(e.deltaY)) return;
5182
+ const atStart = e.deltaX < 0 && el.scrollLeft <= 0;
5183
+ const atEnd = e.deltaX > 0 && el.scrollLeft + el.clientWidth >= el.scrollWidth - 1;
5184
+ if (atStart || atEnd) e.preventDefault();
5185
+ };
5186
+ el.addEventListener("wheel", onWheel, { passive: false });
5187
+ return () => {
5188
+ el.removeEventListener("wheel", onWheel);
5189
+ };
5190
+ }
5059
5191
  const SLOT_MAX = 184;
5060
5192
  const SLOT_MIN = 112;
5061
5193
  const CAPTION_GUTTER = 8;
@@ -5503,6 +5635,13 @@ window.__ModuleLoader__.load({
5503
5635
  };
5504
5636
  /* v8 ignore stop */
5505
5637
  }, []);
5638
+ (0, react.useEffect)(() => {
5639
+ const el = stageRef.current;
5640
+ /* v8 ignore next 1 -- the stage renders whenever the card does, and React
5641
+ attaches refs before effects run; el is never null here. */
5642
+ if (el === null) return;
5643
+ return containHorizontalOverscroll(el);
5644
+ }, []);
5506
5645
  (0, react.useEffect)(() => {
5507
5646
  if (face === null || typeof sessionId !== "string" || sessionId === "") return;
5508
5647
  if (typeof face.refreshSubagents !== "function") return;
@@ -6343,7 +6482,7 @@ window.__ModuleLoader__.load({
6343
6482
  return function PluginInfo() {
6344
6483
  const [latest, setLatest] = (0, react.useState)(null);
6345
6484
  (0, react.useEffect)(() => {
6346
- if ("0.45.0".includes("-dev")) return;
6485
+ if ("0.46.1".includes("-dev")) return;
6347
6486
  let on = true;
6348
6487
  fetchLatestVersion().then((v) => {
6349
6488
  if (on && v) setLatest(v);
@@ -6352,8 +6491,8 @@ window.__ModuleLoader__.load({
6352
6491
  on = false;
6353
6492
  };
6354
6493
  }, []);
6355
- const update = latest !== null && isNewerVersion(latest, "0.45.0") ? latest : null;
6356
- const nameText = "dsh-context (v0.45.0)";
6494
+ const update = latest !== null && isNewerVersion(latest, "0.46.1") ? latest : null;
6495
+ const nameText = "dsh-context (v0.46.1)";
6357
6496
  const nameValue = [nameText];
6358
6497
  if (update) nameValue.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6359
6498
  className: "lc-pi-update",
@@ -7362,17 +7501,17 @@ window.__ModuleLoader__.load({
7362
7501
  const LABEL_FONT = 10;
7363
7502
  const LABEL_FONT_MIN = 6;
7364
7503
  const estTurnLabel = (turn) => 6.5 * String(turn).length;
7365
- const anchorOf = (req) => typeof req.prompt === "number" && req.prompt > 0 && req.total > 0 ? req.prompt / req.total : 1;
7366
- const barTotalOf = (req) => typeof req.prompt === "number" && req.prompt > 0 ? req.prompt : req.total;
7367
7504
  /**
7368
- * Focus a bar on one category (the browser's open category): the kept bucket carries its provider-anchored
7369
- * value, the other buckets zero, and the provider prompt drops — the downstream stack/anchor/tooltip math
7370
- * reads the derived record unchanged (`total` IS the plotted figure; the anchor becomes a no-op).
7505
+ * Focus a bar on one category (the browser's open category): the kept bucket carries its fold figure, the other
7506
+ * buckets zero, and `total` IS the plotted figure — the downstream stack/tooltip math reads the derived record
7507
+ * unchanged. The raw fold figures are plotted as-is: a per-request rescale against the provider prompt would drift
7508
+ * with the heuristic's ratio error and fake growth into constant categories (a never-changing system prompt must
7509
+ * plot flat).
7371
7510
  */
7372
7511
  const focusOf = (req, cat) => {
7373
7512
  const key = cat;
7374
- const { prompt: _prompt, output: _output, ...out } = req;
7375
- const v = Math.round((req[key] || 0) * anchorOf(req));
7513
+ const out = { ...req };
7514
+ const v = req[key] || 0;
7376
7515
  out.total = v;
7377
7516
  for (const c of CATS) out[c.key] = c.key === key ? v : 0;
7378
7517
  return out;
@@ -7448,7 +7587,7 @@ window.__ModuleLoader__.load({
7448
7587
  })] }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7449
7588
  className: "lc-bar-stack",
7450
7589
  children: CATS.map((c) => {
7451
- const v = (req[c.key] || 0) * anchorOf(req);
7590
+ const v = req[c.key] || 0;
7452
7591
  if (!v) return null;
7453
7592
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7454
7593
  "data-cat": c.key,
@@ -7474,6 +7613,42 @@ window.__ModuleLoader__.load({
7474
7613
  focus
7475
7614
  ]);
7476
7615
  const markers = props.markers;
7616
+ const adaptive = props.adaptive === true;
7617
+ const [visMax, setVisMax] = (0, react.useState)(null);
7618
+ const measureVisible = (el) => {
7619
+ if (!adaptive) return;
7620
+ const n = requests.length;
7621
+ if (n === 0 || el.clientWidth <= 0) return;
7622
+ const pitch = 16;
7623
+ const sl = el.scrollLeft;
7624
+ const vr = sl + el.clientWidth;
7625
+ let total = 0;
7626
+ let up = 0;
7627
+ let down = 0;
7628
+ const from = Math.max(0, Math.floor(sl / pitch));
7629
+ const to = Math.min(n - 1, Math.max(from, Math.floor((vr - 1) / pitch)));
7630
+ for (let i = from; i <= to; i++) {
7631
+ const col = i * pitch;
7632
+ if (col >= vr || col + BAR_W <= sl) continue;
7633
+ const req = requests[i];
7634
+ if (delta) {
7635
+ let bu = 0;
7636
+ let bd = 0;
7637
+ for (const c of CATS) {
7638
+ const d = req[c.key] || 0;
7639
+ if (d > 0) bu += d;
7640
+ else bd -= d;
7641
+ }
7642
+ if (bu > up) up = bu;
7643
+ if (bd > down) down = bd;
7644
+ } else if (req.total > total) total = req.total;
7645
+ }
7646
+ setVisMax((prev) => prev !== null && prev.total === total && prev.up === up && prev.down === down ? prev : {
7647
+ total,
7648
+ up,
7649
+ down
7650
+ });
7651
+ };
7477
7652
  let maxTotal = 1;
7478
7653
  let maxUp = 0;
7479
7654
  let maxDown = 0;
@@ -7488,9 +7663,14 @@ window.__ModuleLoader__.load({
7488
7663
  if (up > maxUp) maxUp = up;
7489
7664
  if (down > maxDown) maxDown = down;
7490
7665
  }
7491
- else for (const req of requests) {
7492
- const bt = barTotalOf(req);
7493
- if (bt > maxTotal) maxTotal = bt;
7666
+ else for (const req of requests) if (req.total > maxTotal) maxTotal = req.total;
7667
+ if (adaptive && visMax !== null) {
7668
+ if (delta) {
7669
+ if (visMax.up + visMax.down > 0) {
7670
+ maxUp = visMax.up;
7671
+ maxDown = visMax.down;
7672
+ }
7673
+ } else maxTotal = Math.max(1, visMax.total);
7494
7674
  }
7495
7675
  const span = Math.max(1, maxUp + maxDown);
7496
7676
  const deltaScale = CHART_H / span;
@@ -7611,11 +7791,38 @@ window.__ModuleLoader__.load({
7611
7791
  prevScrollWidthRef.current = el.scrollWidth;
7612
7792
  updateTurnLabels(el);
7613
7793
  syncTip(el);
7794
+ measureVisible(el);
7614
7795
  }, [
7615
7796
  props.granularity,
7616
7797
  props.focusTurn,
7617
- requests
7798
+ requests,
7799
+ adaptive
7618
7800
  ]);
7801
+ const measureRef = (0, react.useRef)(measureVisible);
7802
+ (0, react.useLayoutEffect)(() => {
7803
+ measureRef.current = measureVisible;
7804
+ });
7805
+ (0, react.useLayoutEffect)(() => {
7806
+ const el = scrollRef.current;
7807
+ /* v8 ignore next 1 -- the scroll div renders unconditionally and React
7808
+ attaches refs before layout effects run; el is never null here. */
7809
+ if (el === null) return;
7810
+ if (typeof ResizeObserver !== "function") return;
7811
+ const observer = new ResizeObserver(() => {
7812
+ measureRef.current(el);
7813
+ });
7814
+ observer.observe(el);
7815
+ return () => {
7816
+ observer.disconnect();
7817
+ };
7818
+ }, []);
7819
+ (0, react.useLayoutEffect)(() => {
7820
+ const el = scrollRef.current;
7821
+ /* v8 ignore next 1 -- the scroll div renders unconditionally and React
7822
+ attaches refs before layout effects run; el is never null here. */
7823
+ if (el === null) return;
7824
+ return containHorizontalOverscroll(el);
7825
+ }, []);
7619
7826
  const tipRowsOf = (req) => {
7620
7827
  const n = req.stepCount ?? 1;
7621
7828
  const head = props.granularity === "turn" ? n > 1 ? t("tip.turn", {
@@ -7633,8 +7840,8 @@ window.__ModuleLoader__.load({
7633
7840
  }
7634
7841
  return [head, focus !== null ? t("tip.cat", {
7635
7842
  cat: catLabel(focus),
7636
- n: fmt(barTotalOf(req))
7637
- }) : t("tip.total", { n: fmt(barTotalOf(req)) })];
7843
+ n: fmt(req.total)
7844
+ }) : t("tip.total", { n: fmt(req.total) })];
7638
7845
  };
7639
7846
  const hoveredIdx = props.hoveredSeq !== null ? requests.findIndex((r) => r.seq === props.hoveredSeq) : -1;
7640
7847
  const hoveredReq = hoveredIdx >= 0 ? requests[hoveredIdx] : null;
@@ -7720,6 +7927,7 @@ window.__ModuleLoader__.load({
7720
7927
  onScroll: (e) => {
7721
7928
  updateTurnLabels(e.currentTarget);
7722
7929
  syncTip(e.currentTarget);
7930
+ measureVisible(e.currentTarget);
7723
7931
  },
7724
7932
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7725
7933
  className: "lc-chart",
@@ -7870,6 +8078,7 @@ window.__ModuleLoader__.load({
7870
8078
  const [hoverTurn, setHoverTurn] = (0, react.useState)(null);
7871
8079
  const [granularity, setGranularity] = (0, react.useState)(() => settings.defaultGranularity());
7872
8080
  const [trendMode, setTrendMode] = (0, react.useState)(() => settings.defaultTrendMode());
8081
+ const [adaptive, setAdaptive] = (0, react.useState)(false);
7873
8082
  const [focusTurn, setFocusTurn] = (0, react.useState)(null);
7874
8083
  const [jumpSeq, setJumpSeq] = (0, react.useState)(null);
7875
8084
  const [hoverCat, setHoverCat] = (0, react.useState)(null);
@@ -8093,9 +8302,22 @@ window.__ModuleLoader__.load({
8093
8302
  children: t("trend.title")
8094
8303
  }),
8095
8304
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8096
- className: "lc-card-sub",
8097
- children: focusCat !== null ? t("trend.focus", { cat: kit.catLabel(focusCat) }) : t("trend.hint")
8305
+ className: "lc-gran lc-trend-adaptive",
8306
+ role: "group",
8307
+ title: t("trend.adaptiveHint"),
8308
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
8309
+ type: "button",
8310
+ className: "lc-gran-btn" + (adaptive ? " lc-gran-on" : ""),
8311
+ onClick: () => {
8312
+ setAdaptive((on) => !on);
8313
+ },
8314
+ children: t("trend.adaptive")
8315
+ })
8098
8316
  }),
8317
+ focusCat !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8318
+ className: "lc-card-sub",
8319
+ children: t("trend.focus", { cat: kit.catLabel(focusCat) })
8320
+ }) : null,
8099
8321
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8100
8322
  className: "lc-trend-ctl",
8101
8323
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -8149,6 +8371,7 @@ window.__ModuleLoader__.load({
8149
8371
  focusTurn,
8150
8372
  hoverCat: trendHoverCat,
8151
8373
  focusCat,
8374
+ adaptive,
8152
8375
  onSelect: setSelectedSeq,
8153
8376
  onHover: setHoveredSeq,
8154
8377
  onHoverTurn: setHoverTurn,
@@ -8337,124 +8560,6 @@ window.__ModuleLoader__.load({
8337
8560
  };
8338
8561
  }
8339
8562
  //#endregion
8340
- //#region src/client/components/statsJump.tsx
8341
- /**
8342
- * The chat page's stats line — the harness's own StatsLine entry on the
8343
- * `conversation.composer.dock` seat — becomes a jump affordance: hovering
8344
- * underlines it, a click (or Enter/Space) opens the Context tab. The plugin
8345
- * wires this from a sibling dock entry that renders no UI of its own: an
8346
- * invisible anchor mounts inside the slot's `[data-slot]` wrapper and spots
8347
- * the stats row beside it, and a MutationObserver re-spots it on dock churn
8348
- * (the row mounts only once the first stats exist, tooltip bubbles come and
8349
- * go beside it, and switching conversations remounts the pair together).
8350
- *
8351
- * EVERY step degrades silently: a host without the dock seat never mounts
8352
- * the entry; a dock without exactly one spotless candidate row (another
8353
- * plugin's entry, a crash face, an unexpected layout) decorates nothing; a
8354
- * row that throws mid-wiring stays unwired; a drag-selection click is
8355
- * ignored. The affordance is simply absent — nothing here can take the chat
8356
- * page down.
8357
- */
8358
- /** The plugin's invisible dock anchor, and the class it brands the stats row with. */
8359
- const ANCHOR_CLASS = "lc-stats-jump";
8360
- const ROW_CLASS = "lc-stats-jump-row";
8361
- /**
8362
- * The stats row beside `anchor`: the single element child that is neither
8363
- * the anchor nor a tooltip bubble. Children are untrusted input — one that
8364
- * throws on attribute access is skipped whole, and two live candidates at
8365
- * once (another plugin's dock entry, a crash face) answer null so nothing
8366
- * is ever decorated on a guess.
8367
- */
8368
- function statsRowOf(anchor) {
8369
- const parent = anchor.parentElement;
8370
- if (parent === null) return null;
8371
- let row = null;
8372
- for (const child of parent.children) {
8373
- try {
8374
- if (child === anchor || child.getAttribute("role") === "tooltip") continue;
8375
- } catch {
8376
- continue;
8377
- }
8378
- if (row !== null) return null;
8379
- row = child;
8380
- }
8381
- return row;
8382
- }
8383
- /**
8384
- * Wire the dock beside `anchor`: decorate today's stats row and re-spot it
8385
- * on dock churn. Returns the teardown that disconnects the observer and
8386
- * strips every mark the wiring left on the row.
8387
- */
8388
- function wireDock(anchor, label, activate) {
8389
- if (anchor === null) return () => {};
8390
- let wired = null;
8391
- const unwire = () => {
8392
- wired?.off();
8393
- wired = null;
8394
- };
8395
- const scan = () => {
8396
- try {
8397
- const row = statsRowOf(anchor);
8398
- if (wired?.row === row) return;
8399
- unwire();
8400
- if (row === null || !(row instanceof HTMLElement)) return;
8401
- row.classList.add(ROW_CLASS);
8402
- row.setAttribute("role", "button");
8403
- row.setAttribute("tabindex", "0");
8404
- row.setAttribute("aria-label", label);
8405
- const onKey = (e) => {
8406
- if (e.key !== "Enter" && e.key !== " ") return;
8407
- e.preventDefault();
8408
- activate();
8409
- };
8410
- const onClick = () => {
8411
- const selection = anchor.ownerDocument.getSelection();
8412
- if (selection !== null && !selection.isCollapsed) return;
8413
- activate();
8414
- };
8415
- row.addEventListener("click", onClick);
8416
- row.addEventListener("keydown", onKey);
8417
- wired = {
8418
- row,
8419
- off() {
8420
- row.removeEventListener("click", onClick);
8421
- row.removeEventListener("keydown", onKey);
8422
- row.classList.remove(ROW_CLASS);
8423
- row.removeAttribute("role");
8424
- row.removeAttribute("tabindex");
8425
- row.removeAttribute("aria-label");
8426
- }
8427
- };
8428
- } catch {}
8429
- };
8430
- scan();
8431
- const parent = anchor.parentElement;
8432
- if (parent === null) return unwire;
8433
- const observer = new MutationObserver(scan);
8434
- observer.observe(parent, { childList: true });
8435
- return () => {
8436
- observer.disconnect();
8437
- unwire();
8438
- };
8439
- }
8440
- /** The dock entry component: the invisible anchor plus the wiring around it. */
8441
- function makeStatsJump(kit) {
8442
- const { t } = kit;
8443
- return function StatsJump() {
8444
- const anchorRef = (0, react.useRef)(null);
8445
- const label = t("jump.statsLine");
8446
- (0, react.useEffect)(() => wireDock(anchorRef.current, label, () => {
8447
- activateContextTab(t("tab"));
8448
- }), [label]);
8449
- return (0, react.createElement)("span", {
8450
- ref: anchorRef,
8451
- className: ANCHOR_CLASS,
8452
- hidden: true,
8453
- "aria-hidden": "true"
8454
- });
8455
- };
8456
- }
8457
- //#endregion
8458
8563
  //#region src/client/viewkit.ts
8459
8564
  function makeViewKit(t) {
8460
8565
  const { eventLabel, eventAt } = makeEventText(t);
@@ -8471,7 +8576,7 @@ window.__ModuleLoader__.load({
8471
8576
  }
8472
8577
  //#endregion
8473
8578
  //#region \0dsh-global-css:/home/runner/work/dsh-context/dsh-context/src/client/styles/base.css.mjs
8474
- const css$13 = ".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-l2);border-radius:10px;margin-bottom:14px;padding:14px 16px}.lc-root .lc-card{margin-bottom:7px;padding:7px 8px;container:lc-card/inline-size}.lc-root .lc-cols{gap:7px;margin-bottom:7px}.lc-card-title{flex-wrap:wrap;align-items:baseline;gap:8px;margin-bottom:10px;font-weight:600;display:flex}.lc-card-title-text{white-space:nowrap;flex:none}.lc-gran,.lc-kinds{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);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;transition:color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);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-tip{z-index:6;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);width:max-content;color:var(--dsw-alias-label-primary);box-shadow:var(--dsw-shadow-lv3,0 2px 8px #0000002e);pointer-events:none;opacity:0;transition:opacity var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);border-radius:6px;padding:6px 10px;font-size:12px;position:absolute}.lc-events,.lc-fa-list{flex-direction:column;gap:2px;height:320px;display:flex;overflow-y:auto}.lc-cols{flex-wrap:wrap;gap:14px;margin-bottom:14px;display:flex}.lc-col{flex:1;min-width:min(280px,100%)}.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{container:lc-head-row/inline-size}.lc-head>.lc-card{flex:1 1 0;min-width:0}@container lc-head-row (width<=1045px){.lc-head>.lc-card{flex-basis:40%}}@container lc-head-row (width<=480px){.lc-head>.lc-card{flex-basis:100%}}.lc-head>.lc-card:first-child{flex-direction:column;display:flex}.lc-head>.lc-card:first-child .lc-stats{flex:1;align-content:stretch}.lc-head>.lc-card:first-child .lc-stat{justify-content:center}.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{font-family:var(--ds-font-family-code,ui-monospace, SFMono-Regular, Menlo, monospace);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-size:12px}.lc-error-retry{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;transition:border-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);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}[data-conversation-scroll]:has(.lc-root)>[data-composer-seat]:not(:has([data-approval-key],[data-question-key],[data-plan-review-key])),[data-conversation-scroll]:has(.lc-root,.lc-modal-backdrop)~[data-width-handle]{display:none}";
8579
+ const css$13 = ".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-l2);border-radius:10px;margin-bottom:14px;padding:14px 16px}.lc-root .lc-card{margin-bottom:7px;padding:7px 8px;container:lc-card/inline-size}.lc-root .lc-cols{gap:7px;margin-bottom:7px}.lc-card-title{flex-wrap:wrap;align-items:baseline;gap:8px;margin-bottom:10px;font-weight:600;display:flex}.lc-card-title-text{white-space:nowrap;flex:none}.lc-gran,.lc-kinds{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);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-trend-adaptive{flex:none;margin-left:0}.lc-gran-btn{color:var(--dsw-alias-label-secondary);cursor:pointer;transition:color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);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-tip{z-index:6;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);width:max-content;color:var(--dsw-alias-label-primary);box-shadow:var(--dsw-shadow-lv3,0 2px 8px #0000002e);pointer-events:none;opacity:0;transition:opacity var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);border-radius:6px;padding:6px 10px;font-size:12px;position:absolute}.lc-events,.lc-fa-list{flex-direction:column;gap:2px;height:320px;display:flex;overflow-y:auto}.lc-cols{flex-wrap:wrap;gap:14px;margin-bottom:14px;display:flex}.lc-col{flex:1;min-width:min(280px,100%)}.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{container:lc-head-row/inline-size}.lc-head>.lc-card{flex:1 1 0;min-width:0}@container lc-head-row (width<=1045px){.lc-head>.lc-card{flex-basis:40%}}@container lc-head-row (width<=480px){.lc-head>.lc-card{flex-basis:100%}}.lc-head>.lc-card:first-child{flex-direction:column;display:flex}.lc-head>.lc-card:first-child .lc-stats{flex:1;align-content:stretch}.lc-head>.lc-card:first-child .lc-stat{justify-content:center}.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{font-family:var(--ds-font-family-code,ui-monospace, SFMono-Regular, Menlo, monospace);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-size:12px}.lc-error-retry{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;transition:border-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);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}[data-conversation-scroll]:has(.lc-root)>[data-composer-seat]:not(:has([data-approval-key],[data-question-key],[data-plan-review-key])),[data-conversation-scroll]:has(.lc-root,.lc-modal-backdrop)~[data-width-handle]{display:none}";
8475
8580
  const tagId$13 = "dsh-context/base.css";
8476
8581
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$13) + "]") === null) {
8477
8582
  const tag = document.createElement("style");
@@ -8493,7 +8598,7 @@ window.__ModuleLoader__.load({
8493
8598
  }
8494
8599
  //#endregion
8495
8600
  //#region \0dsh-global-css:/home/runner/work/dsh-context/dsh-context/src/client/styles/jump.css.mjs
8496
- const css$11 = ".lc-jump{width:calc(28px + var(--dsh-content-font-delta,0px));height:calc(28px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-tertiary);cursor:pointer;transition:background-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);background:0 0;border:0;border-radius:28px;justify-content:center;align-items:center;padding:6px;display:inline-flex}.lc-jump svg{width:calc(16px + var(--dsh-content-font-delta,0px));height:calc(16px + var(--dsh-content-font-delta,0px))}.lc-jump:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary)}.lc-stats-jump{display:none}.lc-stats-jump-row{cursor:pointer}.lc-stats-jump-row:hover,.lc-stats-jump-row:focus-visible{text-decoration:underline}";
8601
+ const css$11 = ".lc-jump{width:calc(28px + var(--dsh-content-font-delta,0px));height:calc(28px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-tertiary);cursor:pointer;transition:background-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);background:0 0;border:0;border-radius:28px;justify-content:center;align-items:center;padding:6px;display:inline-flex}.lc-jump svg{width:calc(16px + var(--dsh-content-font-delta,0px));height:calc(16px + var(--dsh-content-font-delta,0px))}.lc-jump:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary)}";
8497
8602
  const tagId$11 = "dsh-context/jump.css";
8498
8603
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$11) + "]") === null) {
8499
8604
  const tag = document.createElement("style");
@@ -8515,7 +8620,7 @@ window.__ModuleLoader__.load({
8515
8620
  }
8516
8621
  //#endregion
8517
8622
  //#region \0dsh-global-css:/home/runner/work/dsh-context/dsh-context/src/client/styles/stackedBar.css.mjs
8518
- const css$9 = ".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);transition:opacity var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);border-radius:5px;position:absolute;top:0;bottom:0;left:0}.lc-occupied-box-on{opacity:1}.lc-bar-tip{z-index:5;white-space:nowrap;padding:3px 8px;bottom:calc(100% + 6px);transform:translate(-50%)}.lc-bar-tip-on{opacity:1}.lc-stacked>div{height:100%}.lc-stacked-seg{transition:filter var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), opacity var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out)}.lc-stacked-free{box-sizing:border-box;transition:box-shadow var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), opacity var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out)}.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;transition:background-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);border-radius:6px;align-items:center;gap:5px;padding:1px 6px;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{border-radius:2px;width:8px;height:8px;display:inline-block}.lc-chip i{transition:box-shadow var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out)}.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)}";
8623
+ const css$9 = ".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);transition:opacity var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);border-radius:5px;position:absolute;top:0;bottom:0;left:0}.lc-occupied-box-on{opacity:1}.lc-bar-tip{z-index:5;white-space:nowrap;padding:3px 8px;bottom:calc(100% + 6px);transform:translate(-50%)}.lc-bar-tip-on{opacity:1}.lc-stacked>div{height:100%}.lc-stacked-seg-pick{cursor:pointer}.lc-stacked-seg{transition:filter var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), opacity var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out)}.lc-stacked-free{box-sizing:border-box;transition:box-shadow var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), opacity var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out)}.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;transition:background-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);border-radius:6px;align-items:center;gap:5px;padding:1px 6px;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{border-radius:2px;width:8px;height:8px;display:inline-block}.lc-chip i{transition:box-shadow var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out)}.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)}";
8519
8624
  const tagId$9 = "dsh-context/stackedBar.css";
8520
8625
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$9) + "]") === null) {
8521
8626
  const tag = document.createElement("style");
@@ -8526,7 +8631,7 @@ window.__ModuleLoader__.load({
8526
8631
  }
8527
8632
  //#endregion
8528
8633
  //#region \0dsh-global-css:/home/runner/work/dsh-context/dsh-context/src/client/styles/trendChart.css.mjs
8529
- const css$8 = ".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-q3{top:41px}.lc-axis-mid{top:69px}.lc-axis-q1{top:97px}.lc-axis-bot{top:125px}.lc-chart-wrap{flex:1;min-width:0;position:relative}.lc-chart-scroll{scrollbar-gutter:stable;padding-bottom:var(--dsh-scrollbar-width,8px);overflow:auto hidden}.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-l2);pointer-events:none;position:absolute;left:0;right:0}.lc-grid-top{top:18px}.lc-grid-q3{top:46px}.lc-grid-mid{top:74px}.lc-grid-q1{top:102px}.lc-grid-zero{border-top-style:solid;border-top-color:#80808080;top:130px}.lc-bar{cursor:pointer;outline-offset:1px;width:14px;height:100%;transition:opacity var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), background-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), outline-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);border-radius:2px;outline:1px dashed #0000;flex:none;align-items:flex-end;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;box-sizing:border-box;overflow-wrap:break-word;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);max-width:100%;color:var(--dsw-alias-label-primary);pointer-events:none;border-radius:6px;flex-direction:column;gap:2px;padding:3px 8px;font-size:12px;display:flex;position:absolute;bottom:calc(100% + 4px);left:0;box-shadow:0 2px 8px #0000002e}.lc-bar:hover{background:var(--dsw-alias-bg-layer-2)}.lc-bar-hovered{outline-color:var(--dsw-alias-brand-primary)}.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-up,.lc-bar-down{width:100%;display:flex;position:absolute;left:0}.lc-bar-up{flex-direction:column-reverse}.lc-bar-down{flex-direction:column}.lc-bar-up>div,.lc-bar-down>div{width:100%}.lc-cat-seg{transition:filter var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), opacity var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out)}.lc-chart[data-catdim] .lc-cat-seg{opacity:.35}.lc-chart[data-catdim=system] .lc-cat-seg[data-cat=system],.lc-chart[data-catdim=tools] .lc-cat-seg[data-cat=tools],.lc-chart[data-catdim=user] .lc-cat-seg[data-cat=user],.lc-chart[data-catdim=inject] .lc-cat-seg[data-cat=inject],.lc-chart[data-catdim=assistant] .lc-cat-seg[data-cat=assistant],.lc-chart[data-catdim=tool] .lc-cat-seg[data-cat=tool]{opacity:1;filter:brightness(1.18)}.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;overflow:hidden}.lc-turn{box-sizing:border-box;text-align:center;color:var(--dsw-alias-label-secondary);white-space:nowrap;cursor:pointer;height:14px;transition:filter var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), opacity var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);border-radius:3px;flex:none;font-size:10px;font-weight:600;line-height:14px}.lc-turn-on{filter:brightness(1.35);color:var(--dsw-alias-label-primary)}.lc-turn-label{display:inline-block}";
8634
+ const css$8 = ".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-q3{top:41px}.lc-axis-mid{top:69px}.lc-axis-q1{top:97px}.lc-axis-bot{top:125px}.lc-chart-wrap{flex:1;min-width:0;position:relative}.lc-chart-scroll{overscroll-behavior-x:contain;scrollbar-gutter:stable;padding-bottom:var(--dsh-scrollbar-width,8px);overflow:auto hidden}.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-l2);pointer-events:none;position:absolute;left:0;right:0}.lc-grid-top{top:18px}.lc-grid-q3{top:46px}.lc-grid-mid{top:74px}.lc-grid-q1{top:102px}.lc-grid-zero{border-top-style:solid;border-top-color:#80808080;top:130px}.lc-bar{cursor:pointer;outline-offset:1px;width:14px;height:100%;transition:opacity var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), background-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), outline-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);border-radius:2px;outline:1px dashed #0000;flex:none;align-items:flex-end;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;box-sizing:border-box;overflow-wrap:break-word;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);max-width:100%;color:var(--dsw-alias-label-primary);pointer-events:none;border-radius:6px;flex-direction:column;gap:2px;padding:3px 8px;font-size:12px;display:flex;position:absolute;bottom:calc(100% + 4px);left:0;box-shadow:0 2px 8px #0000002e}.lc-bar:hover{background:var(--dsw-alias-bg-layer-2)}.lc-bar-hovered{outline-color:var(--dsw-alias-brand-primary)}.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-up,.lc-bar-down{width:100%;display:flex;position:absolute;left:0}.lc-bar-up{flex-direction:column-reverse}.lc-bar-down{flex-direction:column}.lc-bar-up>div,.lc-bar-down>div{width:100%}.lc-cat-seg{transition:filter var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), opacity var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out)}.lc-chart[data-catdim] .lc-cat-seg{opacity:.35}.lc-chart[data-catdim=system] .lc-cat-seg[data-cat=system],.lc-chart[data-catdim=tools] .lc-cat-seg[data-cat=tools],.lc-chart[data-catdim=user] .lc-cat-seg[data-cat=user],.lc-chart[data-catdim=inject] .lc-cat-seg[data-cat=inject],.lc-chart[data-catdim=assistant] .lc-cat-seg[data-cat=assistant],.lc-chart[data-catdim=tool] .lc-cat-seg[data-cat=tool]{opacity:1;filter:brightness(1.18)}.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;overflow:hidden}.lc-turn{box-sizing:border-box;text-align:center;color:var(--dsw-alias-label-secondary);white-space:nowrap;cursor:pointer;height:14px;transition:filter var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), opacity var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);border-radius:3px;flex:none;font-size:10px;font-weight:600;line-height:14px}.lc-turn-on{filter:brightness(1.35);color:var(--dsw-alias-label-primary)}.lc-turn-label{display:inline-block}";
8530
8635
  const tagId$8 = "dsh-context/trendChart.css";
8531
8636
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$8) + "]") === null) {
8532
8637
  const tag = document.createElement("style");
@@ -8581,7 +8686,7 @@ window.__ModuleLoader__.load({
8581
8686
  }
8582
8687
  //#endregion
8583
8688
  //#region \0dsh-global-css:/home/runner/work/dsh-context/dsh-context/src/client/styles/browser.css.mjs
8584
- const css$3 = ".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-l2);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-retry{color:var(--dsw-alias-brand-primary);font:inherit;cursor:pointer;text-underline-offset:2px;transition:filter var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);background:0 0;border:0;padding:0;font-size:12px;text-decoration:underline}.lc-br-retry:hover{filter:brightness(1.15)}.lc-br-cats{flex-direction:column;gap:4px;margin-top:10px;display:flex}.lc-br-cat{border:1px solid var(--dsw-alias-border-l2);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;transition:background-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);background:0 0;border:0;align-items:center;gap:8px;padding:7px 10px;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{width:8px;height:8px;transition:box-shadow var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);border-radius:2px;flex:none;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;height:14px;color:var(--dsw-alias-label-tertiary);flex:none;justify-content:center;align-items:center;display:flex}.lc-br-chev:before{content:\"\";width:5px;height:5px;transition:transform var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);border-bottom:1px solid;border-right:1px solid;transform:rotate(-45deg)}.lc-br-chev-on:before{transform:rotate(45deg)}.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;transition:background-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);background:0 0;border:0;border-radius:6px;align-items:center;gap:8px;padding:5px 6px;font-size:12px;display:flex}.lc-br-elem-row:hover{background:var(--dsw-alias-interactive-bg-hover)}.lc-br-err-dot{background:var(--dsw-alias-state-error-primary);width:6px;height:6px;box-shadow:0 0 0 2px color-mix(in srgb, var(--dsw-alias-state-error-primary) 10%, transparent);border-radius:50%;flex:none}.lc-br-tag{min-width:0;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;max-width:220px;padding:0 6px;font-size:11px;overflow:hidden}.lc-br-tool-plugin{color:var(--dsw-alias-brand-primary);background:color-mix(in srgb, var(--dsw-alias-brand-primary) 14%, transparent);border-color:#0000;border-radius:6px;font-size:12px}.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)}";
8689
+ const css$3 = ".lc-br-dna-ctl{flex:none;margin-left:0}.lc-br-bar-dna .lc-stacked-seg{box-shadow:inset -1px 0 0 var(--dsw-alias-bg-layer-1)}.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-l2);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-retry{color:var(--dsw-alias-brand-primary);font:inherit;cursor:pointer;text-underline-offset:2px;transition:filter var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);background:0 0;border:0;padding:0;font-size:12px;text-decoration:underline}.lc-br-retry:hover{filter:brightness(1.15)}.lc-br-cats{flex-direction:column;gap:4px;margin-top:10px;display:flex}.lc-br-cat{border:1px solid var(--dsw-alias-border-l2);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;transition:background-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);background:0 0;border:0;align-items:center;gap:8px;padding:7px 10px;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{width:8px;height:8px;transition:box-shadow var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);border-radius:2px;flex:none;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;height:14px;color:var(--dsw-alias-label-tertiary);flex:none;justify-content:center;align-items:center;display:flex}.lc-br-chev:before{content:\"\";width:5px;height:5px;transition:transform var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);border-bottom:1px solid;border-right:1px solid;transform:rotate(-45deg)}.lc-br-chev-on:before{transform:rotate(45deg)}.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;transition:background-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);background:0 0;border:0;border-radius:6px;align-items:center;gap:8px;padding:5px 6px;font-size:12px;display:flex}.lc-br-elem-row:hover{background:var(--dsw-alias-interactive-bg-hover)}.lc-br-err-dot{background:var(--dsw-alias-state-error-primary);width:6px;height:6px;box-shadow:0 0 0 2px color-mix(in srgb, var(--dsw-alias-state-error-primary) 10%, transparent);border-radius:50%;flex:none}.lc-br-tag{min-width:0;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;max-width:220px;padding:0 6px;font-size:11px;overflow:hidden}.lc-br-tool-plugin{color:var(--dsw-alias-brand-primary);background:color-mix(in srgb, var(--dsw-alias-brand-primary) 14%, transparent);border-color:#0000;border-radius:6px;font-size:12px}.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)}";
8585
8690
  const tagId$3 = "dsh-context/browser.css";
8586
8691
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$3) + "]") === null) {
8587
8692
  const tag = document.createElement("style");
@@ -8614,7 +8719,7 @@ window.__ModuleLoader__.load({
8614
8719
  }
8615
8720
  //#endregion
8616
8721
  //#region \0dsh-global-css:/home/runner/work/dsh-context/dsh-context/src/client/styles/agentGraph.css.mjs
8617
- const css = ".lc-agents-chips{flex-wrap:wrap;gap:6px;margin-bottom:10px;display:flex}.lc-agents-chip{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;border-radius:999px;padding:2px 8px;font-size:11px}.lc-agents-chip-on{color:var(--dsw-alias-state-success-primary);border-color:color-mix(in srgb, var(--dsw-alias-state-success-primary) 40%, transparent)}.lc-agents-stage{margin:0 -4px;padding:0 4px;overflow-x:auto}.lc-agents-svg{max-width:none;margin:0 auto;display:block}.lc-agents-link{stroke-width:1.5px;stroke-opacity:.45}.lc-agents-link-live{stroke-opacity:.85}.lc-agents-flow{stroke-width:2px;stroke-linecap:round;stroke-dasharray:2 7;animation:.9s linear infinite lc-agent-flow}@keyframes lc-agent-flow{to{stroke-dashoffset:-9px}}.lc-agent-node{outline:none}.lc-agent-clickable{cursor:pointer}.lc-agent-halo{fill:#0000;transition:fill var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out)}.lc-agent-hover .lc-agent-halo,.lc-agent-node:focus-visible .lc-agent-halo{fill:var(--dsw-alias-interactive-bg-hover,var(--dsw-alias-bg-layer-2))}.lc-agent-self .lc-agent-halo{fill:var(--dsw-alias-bg-layer-2)}.lc-agent-running .lc-agent-halo{fill:color-mix(in srgb, var(--dsw-alias-state-success-primary) 12%, transparent);animation:1.8s ease-in-out infinite lc-agent-glow}.lc-agent-done .lc-agent-halo{fill:color-mix(in srgb, var(--dsw-alias-state-success-primary) 7%, transparent)}@keyframes lc-agent-glow{0%,to{opacity:1}50%{opacity:.4}}.lc-agent-track{fill:var(--dsw-alias-bg-layer-1);stroke:var(--dsw-alias-border-l1);stroke-width:1.5px}.lc-agent-seg{fill:none;stroke-width:9px;transition:stroke-dasharray .3s,stroke-dashoffset .3s}.lc-agent-free{stroke:color-mix(in srgb, var(--dsw-alias-label-secondary) 18%, transparent)}.lc-agent-pct{fill:var(--dsw-alias-label-primary);font-variant-numeric:tabular-nums;pointer-events:none;font-size:11px;font-weight:600}.lc-agent-caption{text-align:center;pointer-events:none;width:100%;line-height:1.25}.lc-agent-label{color:var(--dsw-alias-label-primary);overflow-wrap:break-word;-webkit-line-clamp:3;-webkit-box-orient:vertical;font-size:11px;display:-webkit-box;overflow:hidden}.lc-agent-tokens{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;font-size:10px}.lc-agents-solo{padding:4px 0 10px}.lc-agents-inspector{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);border-radius:8px;flex-wrap:wrap;align-items:baseline;gap:4px 8px;min-width:0;margin-top:10px;padding:7px 10px;font-size:12px;display:flex}.lc-agents-inspector-name{color:var(--dsw-alias-label-primary);overflow-wrap:anywhere}.lc-agents-badge{background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-secondary);border-radius:999px;flex:none;padding:1px 6px;font-size:10px}.lc-agent-self-badge{vertical-align:1px;margin-left:5px}.lc-agents-badge-on{color:var(--dsw-alias-state-success-primary);border-color:color-mix(in srgb, var(--dsw-alias-state-success-primary) 40%, transparent)}.lc-agents-inspector-stats{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.lc-agents-inspector-open{color:var(--dsw-alias-brand-primary,#3b82f6);flex:none;margin-left:auto}.lc-agents-legend{color:var(--dsw-alias-label-secondary);flex-wrap:wrap;gap:4px 14px;margin-top:8px;font-size:11px;display:flex}.lc-agents-legend-item{align-items:center;gap:5px;display:inline-flex}.lc-agents-legend-item i{border-radius:2px;width:8px;height:8px}.lc-agents-legend-free{background:color-mix(in srgb, var(--dsw-alias-label-secondary) 18%, transparent)}.lc-agents-legend-edge{border-top:2px dashed var(--dsw-alias-label-secondary);border-radius:0!important;width:14px!important;height:0!important}";
8722
+ const css = ".lc-agents-chips{flex-wrap:wrap;gap:6px;margin-bottom:10px;display:flex}.lc-agents-chip{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;border-radius:999px;padding:2px 8px;font-size:11px}.lc-agents-chip-on{color:var(--dsw-alias-state-success-primary);border-color:color-mix(in srgb, var(--dsw-alias-state-success-primary) 40%, transparent)}.lc-agents-stage{overscroll-behavior-x:contain;margin:0 -4px;padding:0 4px;overflow-x:auto}.lc-agents-svg{max-width:none;margin:0 auto;display:block}.lc-agents-link{stroke-width:1.5px;stroke-opacity:.45}.lc-agents-link-live{stroke-opacity:.85}.lc-agents-flow{stroke-width:2px;stroke-linecap:round;stroke-dasharray:2 7;animation:.9s linear infinite lc-agent-flow}@keyframes lc-agent-flow{to{stroke-dashoffset:-9px}}.lc-agent-node{outline:none}.lc-agent-clickable{cursor:pointer}.lc-agent-halo{fill:#0000;transition:fill var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out)}.lc-agent-hover .lc-agent-halo,.lc-agent-node:focus-visible .lc-agent-halo{fill:var(--dsw-alias-interactive-bg-hover,var(--dsw-alias-bg-layer-2))}.lc-agent-self .lc-agent-halo{fill:var(--dsw-alias-bg-layer-2)}.lc-agent-running .lc-agent-halo{fill:color-mix(in srgb, var(--dsw-alias-state-success-primary) 12%, transparent);animation:1.8s ease-in-out infinite lc-agent-glow}.lc-agent-done .lc-agent-halo{fill:color-mix(in srgb, var(--dsw-alias-state-success-primary) 7%, transparent)}@keyframes lc-agent-glow{0%,to{opacity:1}50%{opacity:.4}}.lc-agent-track{fill:var(--dsw-alias-bg-layer-1);stroke:var(--dsw-alias-border-l1);stroke-width:1.5px}.lc-agent-seg{fill:none;stroke-width:9px;transition:stroke-dasharray .3s,stroke-dashoffset .3s}.lc-agent-free{stroke:color-mix(in srgb, var(--dsw-alias-label-secondary) 18%, transparent)}.lc-agent-pct{fill:var(--dsw-alias-label-primary);font-variant-numeric:tabular-nums;pointer-events:none;font-size:11px;font-weight:600}.lc-agent-caption{text-align:center;pointer-events:none;width:100%;line-height:1.25}.lc-agent-label{color:var(--dsw-alias-label-primary);overflow-wrap:break-word;-webkit-line-clamp:3;-webkit-box-orient:vertical;font-size:11px;display:-webkit-box;overflow:hidden}.lc-agent-tokens{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;font-size:10px}.lc-agents-solo{padding:4px 0 10px}.lc-agents-inspector{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);border-radius:8px;flex-wrap:wrap;align-items:baseline;gap:4px 8px;min-width:0;margin-top:10px;padding:7px 10px;font-size:12px;display:flex}.lc-agents-inspector-name{color:var(--dsw-alias-label-primary);overflow-wrap:anywhere}.lc-agents-badge{background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-secondary);border-radius:999px;flex:none;padding:1px 6px;font-size:10px}.lc-agent-self-badge{vertical-align:1px;margin-left:5px}.lc-agents-badge-on{color:var(--dsw-alias-state-success-primary);border-color:color-mix(in srgb, var(--dsw-alias-state-success-primary) 40%, transparent)}.lc-agents-inspector-stats{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.lc-agents-inspector-open{color:var(--dsw-alias-brand-primary,#3b82f6);flex:none;margin-left:auto}.lc-agents-legend{color:var(--dsw-alias-label-secondary);flex-wrap:wrap;gap:4px 14px;margin-top:8px;font-size:11px;display:flex}.lc-agents-legend-item{align-items:center;gap:5px;display:inline-flex}.lc-agents-legend-item i{border-radius:2px;width:8px;height:8px}.lc-agents-legend-free{background:color-mix(in srgb, var(--dsw-alias-label-secondary) 18%, transparent)}.lc-agents-legend-edge{border-top:2px dashed var(--dsw-alias-label-secondary);border-radius:0!important;width:14px!important;height:0!important}";
8618
8723
  const tagId = "dsh-context/agentGraph.css";
8619
8724
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
8620
8725
  const tag = document.createElement("style");
@@ -8679,15 +8784,6 @@ window.__ModuleLoader__.load({
8679
8784
  locale: NS
8680
8785
  }, (props) => (0, react.createElement)(ContextJump, props));
8681
8786
  });
8682
- const StatsJump = makeStatsJump(kit);
8683
- ctx.slots.inject("conversation.composer.dock", () => {
8684
- return ctx.slots.register({
8685
- name: "conversation.composer.dock",
8686
- id: "stats-jump",
8687
- order: 10,
8688
- locale: NS
8689
- }, (props) => (0, react.createElement)(StatsJump, props));
8690
- });
8691
8787
  registerContextCommand(ctx, kit);
8692
8788
  const ContextModal = makeContextModal(ctx, kit);
8693
8789
  ctx.slots.inject("conversation.input.overlay", () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-context",
3
- "version": "0.45.0",
3
+ "version": "0.46.1",
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": {