dsh-context 0.63.0 → 0.64.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +5 -5
  2. package/lib/client.js +420 -303
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -9,7 +9,7 @@
9
9
  **The best [DeepSeek Harness plugin](https://www.deepseek.com/harness/) for Agent's context insights and management.**
10
10
 
11
11
  [`dsh-context`](https://www.npmjs.com/package/dsh-context) provides full context lifecycle management features.
12
- - **Context Dashboard** — the cross-session overview above Settings on the sidebar foot: KPI band with a 7-day token/cost usage chart, activity heatmap, aggregate composition ring, and filterable session cards that jump straight into any session.
12
+ - **Context Insights page** — the cross-session overview as a first-level sidebar panel (beside Plugins and Automation tasks): KPI band with a 7-day token/cost usage chart, activity heatmap, aggregate composition ring, and filterable session cards that jump straight into any session.
13
13
  - **Context tab** — an UI context dashboard for DeepSeek Harness's context stats, composition, trend, events, and messages.
14
14
  - **Context panel** — the same dashboard as a right-sidebar tab (dsh 0.1.5-rc.1+): pick **Context** on the sidebar's guide page and the panel opens beside the chat.
15
15
  - **`/context` command** — the slash command shows the context model for current context composition and recent context evolution.
@@ -44,16 +44,16 @@ Four surfaces, one story — what your agent is carrying, how it got there, and
44
44
 
45
45
  | Where | What you get |
46
46
  | --- | --- |
47
- | **Context Dashboard** | Every session at a glance: usage, cost, cache hit, daily activity, and per-session context profiles — filtered by range, day, group, or search, one click to jump in. |
47
+ | **Context Insights page** | Every session at a glance: usage, cost, cache hit, daily activity, and per-session context profiles — filtered by range, day, group, or search, one click to jump in. |
48
48
  | **Context tab** | The full dashboard: stats, composition, per-request trend, events, file activity, and the agent network — in every session. |
49
49
  | **`/context` command** | A centered modal with the same composition and context browser, without leaving the chat. |
50
50
  | **Preferences card** | Per-user defaults: view placement, trend granularity & mode, File Activity sort, and more. |
51
51
 
52
- ## 🗂️ The Context Dashboard
52
+ ## 🗂️ The Context Insights page
53
53
 
54
- Click **Context Dashboard / 上下文仪表盘** at the bottom-left of the sidebar, right above **Settings**:
54
+ Click **Context Insights / 上下文洞察** in the sidebar's panel list — the same row level as **Plugins** and **Automation tasks** — and the page opens as a full center-column panel:
55
55
 
56
- ![Context Dashboard](https://raw.githubusercontent.com/bowenliang123/dsh-context/main/docs/context-dashboard.png)
56
+ ![The Context Insights page](https://raw.githubusercontent.com/bowenliang123/dsh-context/main/docs/context-dashboard.png)
57
57
 
58
58
  | Section | The question it answers |
59
59
  | --- | --- |
package/lib/client.js CHANGED
@@ -118,7 +118,6 @@ window.__ModuleLoader__.load({
118
118
  "gran.total": "全量",
119
119
  "gran.delta": "增量",
120
120
  "gran.modeHint": "全量:累计构成;增量:相对上一条请求的变化量",
121
- "trend.focus": "仅展示 {cat}",
122
121
  "trend.adaptive": "自适应",
123
122
  "trend.adaptiveHint": "按当前可视范围内的柱子重新缩放高度,滚动时随之变化",
124
123
  "trend.duration": "耗时",
@@ -358,7 +357,6 @@ window.__ModuleLoader__.load({
358
357
  "attach.sent": "发送",
359
358
  "attach.token": "Token",
360
359
  "attach.tokensTip": "按 DeepSeek 官方图片尺寸换算(单图上限 384 tokens)估算的 token 消耗",
361
- "ov.entry": "上下文洞察",
362
360
  "ov.title": "上下文洞察",
363
361
  "ov.unavailable": "会话列表暂不可用",
364
362
  "ov.range.label": "统计范围",
@@ -520,7 +518,6 @@ window.__ModuleLoader__.load({
520
518
  "gran.total": "Total",
521
519
  "gran.delta": "Delta",
522
520
  "gran.modeHint": "Total: cumulative makeup; Delta: change vs the previous request",
523
- "trend.focus": "Showing {cat} only",
524
521
  "trend.adaptive": "Adaptive",
525
522
  "trend.adaptiveHint": "Rescale bar heights to the visible range, following the scroll",
526
523
  "trend.duration": "Duration",
@@ -760,7 +757,6 @@ window.__ModuleLoader__.load({
760
757
  "attach.sent": "Sent",
761
758
  "attach.token": "Token",
762
759
  "attach.tokensTip": "Estimated token cost via DeepSeek's official image-size conversion (384-token cap per image)",
763
- "ov.entry": "Context Insights",
764
760
  "ov.title": "Context Insights",
765
761
  "ov.unavailable": "The session list is unavailable",
766
762
  "ov.range.label": "Range",
@@ -849,11 +845,11 @@ window.__ModuleLoader__.load({
849
845
  * it to the Plugins page's package cards. The client bundle inlines the
850
846
  * file's markup at build time (the `?raw` channel in tsdown.config.ts) and
851
847
  * re-renders it at every requested size. The identity seats (tab chip,
852
- * command, sidebar registration, panel head) keep the sheet's fixed fills —
848
+ * command, sidebar registration) keep the sheet's fixed fills —
853
849
  * deliberately polychrome on both light and dark chrome — while the
854
- * sidebar-foot entry seat (overviewButton.tsx) opts into `mono`, trading
855
- * every fill for `currentColor` so the glyph sits quietly beside the
856
- * harness's own footer rows (Settings and friends).
850
+ * sidebar's panel-list seat (insightPage.ts) opts into `mono`, trading
851
+ * every fill for `currentColor` so the glyph follows the shell-owned row's
852
+ * own state colors, exactly as the shipped panel glyphs do.
857
853
  */
858
854
  /** Everything between the file's `<svg>` tags: the sheet's strokes in paint order, whitespace-folded. */
859
855
  const SHEET_MARKUP = icon_default.slice(icon_default.indexOf(">") + 1, icon_default.lastIndexOf("</svg>")).trim().replace(/>\s+</g, "><");
@@ -872,6 +868,19 @@ window.__ModuleLoader__.load({
872
868
  });
873
869
  }
874
870
  /**
871
+ * The sidebar panel-list glyph (`sidebar.panellist`): the emblem in `mono` at
872
+ * the size the shell asks for, so the shell-owned row's hover/active colors
873
+ * paint it like the shipped panel glyphs. The shell owns the row's label,
874
+ * and the row's selected state its own styling, so — as on the shipped
875
+ * glyphs — the owner props' `active` goes unread.
876
+ */
877
+ function InsightPanelIcon({ size = 18 }) {
878
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ContextIcon, {
879
+ size,
880
+ mono: true
881
+ });
882
+ }
883
+ /**
875
884
  * The tab chip's title seat (`sidebar.right.pane.tab.title`): the emblem before
876
885
  * the label, so the chip reads as the files chip does. The label comes from the
877
886
  * plugin's own bound translate — read at render, so the chip follows the active
@@ -3526,6 +3535,8 @@ window.__ModuleLoader__.load({
3526
3535
  const lastGranRef = (0, react.useRef)(props.granularity);
3527
3536
  const lastSeqRef = (0, react.useRef)(0);
3528
3537
  const prevScrollWidthRef = (0, react.useRef)(0);
3538
+ const cwRef = (0, react.useRef)(0);
3539
+ const slRef = (0, react.useRef)(0);
3529
3540
  /**
3530
3541
  * Keep each turn label centered within its block's VISIBLE slice, then thin colliding labels: a label wider
3531
3542
  * than its block overflows it, so consecutive narrow turns would smear into each other — walking left→right
@@ -3596,6 +3607,8 @@ window.__ModuleLoader__.load({
3596
3607
  } else if (grew && el.scrollLeft + el.clientWidth >= widthBeforeAppend - 24) el.scrollLeft = el.scrollWidth;
3597
3608
  lastSeqRef.current = newestSeq;
3598
3609
  prevScrollWidthRef.current = el.scrollWidth;
3610
+ slRef.current = el.scrollLeft;
3611
+ cwRef.current = el.clientWidth;
3599
3612
  updateTurnLabels(el);
3600
3613
  syncTip(el);
3601
3614
  measureVisible(el);
@@ -3617,6 +3630,7 @@ window.__ModuleLoader__.load({
3617
3630
  if (el === null) return;
3618
3631
  if (typeof ResizeObserver !== "function") return;
3619
3632
  const observer = new ResizeObserver(() => {
3633
+ cwRef.current = el.clientWidth;
3620
3634
  measureRef.current(el);
3621
3635
  });
3622
3636
  observer.observe(el);
@@ -3704,17 +3718,18 @@ window.__ModuleLoader__.load({
3704
3718
  * Glue the hover tip to its bar's VISIBLE slice. The tip deliberately does NOT live inside the scrolling
3705
3719
  * content: an absolutely-positioned child of a scroller contributes to its scrollable overflow, so a wide
3706
3720
  * reply preview on a right-edge bar used to inflate scrollWidth on every hover and flap the horizontal
3707
- * scrollbar open/closed — jumping the whole card. Reads (offsetWidth/clientWidth) batch before the single
3708
- * style write; unchanged transforms write nothing.
3721
+ * scrollbar open/closed — jumping the whole card. The only layout read left is the tip's own width (its
3722
+ * subtree is the thing that just changed); the scroller's width/offset ride the cached refs, so this never
3723
+ * forces a document-scope layout flush on the hover path. Unchanged transforms write nothing.
3709
3724
  */
3710
3725
  const syncTip = (el) => {
3711
3726
  /* v8 ignore next 1 -- the scroll div renders unconditionally while mounted, so its parent exists. */
3712
3727
  const tip = (el.parentElement ?? document.body).querySelector(".lc-chart-tip");
3713
3728
  if (tip === null) return;
3714
3729
  const lw = tip.offsetWidth;
3715
- const cw = el.clientWidth;
3730
+ const cw = cwRef.current;
3716
3731
  const half = Math.min(lw / 2, cw / 2);
3717
- const cx = Math.min(Math.max(tipColRef.current - el.scrollLeft, half), cw - half);
3732
+ const cx = Math.min(Math.max(tipColRef.current - slRef.current, half), cw - half);
3718
3733
  const next = `translate(${Math.round(cx - lw / 2)}px, 0)`;
3719
3734
  if (tip.style.transform !== next) tip.style.transform = next;
3720
3735
  };
@@ -3781,6 +3796,8 @@ window.__ModuleLoader__.load({
3781
3796
  className: "lc-chart-scroll" + (props.activeTurn !== null ? " lc-chart-dim" : ""),
3782
3797
  ref: scrollRef,
3783
3798
  onScroll: (e) => {
3799
+ slRef.current = e.currentTarget.scrollLeft;
3800
+ cwRef.current = e.currentTarget.clientWidth;
3784
3801
  updateTurnLabels(e.currentTarget);
3785
3802
  syncTip(e.currentTarget);
3786
3803
  measureVisible(e.currentTarget);
@@ -4038,10 +4055,17 @@ window.__ModuleLoader__.load({
4038
4055
  const scaled = Math.trunc(reads / billed * 100 * factor + 1e-9);
4039
4056
  return `${Math.floor(scaled / factor)}.${String(scaled % factor).padStart(decimals, "0")}`;
4040
4057
  }
4058
+ /** One shared formatter: building an Intl formatter per call costs ~50x the format itself (issue #116). */
4059
+ const TIME_FMT = new Intl.DateTimeFormat("en-GB", {
4060
+ hour12: false,
4061
+ hour: "2-digit",
4062
+ minute: "2-digit",
4063
+ second: "2-digit"
4064
+ });
4041
4065
  function fmtTime(t) {
4042
4066
  const d = new Date(t);
4043
4067
  if (isNaN(d.getTime())) return "—";
4044
- return d.toLocaleTimeString("en-GB", { hour12: false });
4068
+ return TIME_FMT.format(d);
4045
4069
  }
4046
4070
  /**
4047
4071
  * Share of a whole as a compact leading percentage for the slice rows:
@@ -6031,71 +6055,6 @@ window.__ModuleLoader__.load({
6031
6055
  };
6032
6056
  }
6033
6057
  //#endregion
6034
- //#region src/client/overviewStore.ts
6035
- function createStore() {
6036
- let open = false;
6037
- const listeners = /* @__PURE__ */ new Set();
6038
- return {
6039
- subscribe: (listener) => {
6040
- listeners.add(listener);
6041
- return () => {
6042
- listeners.delete(listener);
6043
- };
6044
- },
6045
- getSnapshot: () => open,
6046
- set: (next) => {
6047
- if (next === open) return;
6048
- open = next;
6049
- for (const listener of listeners) listener();
6050
- }
6051
- };
6052
- }
6053
- const overviewStore = createStore();
6054
- //#endregion
6055
- //#region src/client/components/overviewButton.tsx
6056
- /**
6057
- * The Context Dashboard's sidebar entry: a footer action stacked directly
6058
- * above Settings (the harness's own foot layout: footer actions, then the
6059
- * settings row), mirroring the Settings trigger's geometry in both column
6060
- * widths. The button carries the plugin emblem — in the mono seat, so the
6061
- * glyph matches the harness's own footer rows rather than shouting over
6062
- * them — and, on the wide column, its label. Clicking opens the overview
6063
- * overlay through the shared module store (overviewStore.ts).
6064
- *
6065
- * The per-user `insightsEntry` preference takes the entry down (renders
6066
- * null) without unregistering the seat. The subscription fails open: an
6067
- * absent settings store, an unserved namespace, or a value the plugin
6068
- * cannot understand all leave the entry visible.
6069
- */
6070
- /** Stable subscription faces for the settings-less degrade (no re-subscribes). */
6071
- const subscribeNever = () => () => {};
6072
- const entryShown = () => "show";
6073
- function makeOverviewButton(kit, settings) {
6074
- const { t } = kit;
6075
- const subscribeEntry = settings === void 0 ? subscribeNever : (listener) => settings.store.subscribe(listener);
6076
- const getEntry = settings === void 0 ? entryShown : () => settings.insightsEntry();
6077
- return function OverviewButton(props) {
6078
- if ((0, react.useSyncExternalStore)(subscribeEntry, getEntry) === "hide") return null;
6079
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
6080
- type: "button",
6081
- className: props.wide === true ? "lc-ov-entry" : "lc-ov-entry lc-ov-entry-rail",
6082
- title: t("ov.entry"),
6083
- "aria-label": t("ov.entry"),
6084
- onClick: () => {
6085
- overviewStore.set(true);
6086
- },
6087
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ContextIcon, {
6088
- size: props.wide === true ? 16 : 18,
6089
- className: "lc-ov-entry-icon",
6090
- mono: true
6091
- }), props.wide === true && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6092
- className: "lc-ov-entry-label",
6093
- children: t("ov.entry")
6094
- })]
6095
- });
6096
- };
6097
- }
6098
- //#endregion
6099
6058
  //#region src/shared/providers.ts
6100
6059
  /**
6101
6060
  * The provider-id seam between dsh request envelopes and the models.dev
@@ -7441,14 +7400,15 @@ window.__ModuleLoader__.load({
7441
7400
  //#region src/client/components/balanceCapsule.tsx
7442
7401
  /**
7443
7402
  * BalanceCapsule — the DeepSeek open-platform balance pill in the Context
7444
- * Dashboard's header (the plugin's one account-level figure, beside the
7403
+ * Insights page's heading (the plugin's one account-level figure, beside the
7445
7404
  * session-level ones). Clicking it opens the platform's usage console in a
7446
- * new tab. Mounted only by the dashboard header; it paints the figure the
7405
+ * new tab. Mounted only by the page heading; it paints the figure the
7447
7406
  * previous open remembered while client/balance.ts revalidates it in the
7448
7407
  * background, and renders NOTHING when nothing is remembered and the route
7449
7408
  * answers nothing — the pill exists only when there is a figure to show. The
7450
- * non-zero parts of the breakdown (topped-up / granted) ride the harness
7451
- * Tooltip primitive — immediate on hover, where a native `title` lags — in
7409
+ * non-zero parts of the breakdown (topped-up / granted) ride the page's
7410
+ * portaled hover tip (hoverTip.tsx, off the pill's `data-lc-tip`) —
7411
+ * immediate on hover, where a native `title` lags — in
7452
7412
  * the entry's own currency (the pill itself carries the total); the entry
7453
7413
  * follows the active locale (zh → CNY) with the account's first currency as
7454
7414
  * the fallback.
@@ -7472,9 +7432,13 @@ window.__ModuleLoader__.load({
7472
7432
  if (entry === null) return null;
7473
7433
  const money = (amount) => symbolOf(entry.currency) + amount.toFixed(2);
7474
7434
  const tipLines = [...entry.toppedUp > 0 ? [t("balance.tip.toppedUp") + ": " + money(entry.toppedUp)] : [], ...entry.granted > 0 ? [t("balance.tip.granted") + ": " + money(entry.granted)] : []];
7475
- const pill = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("a", {
7435
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("a", {
7476
7436
  className: "lc-ov-balance",
7477
7437
  "aria-label": tipLines.length > 0 ? tipLines.join("\n") : void 0,
7438
+ ...tipLines.length > 0 ? {
7439
+ "data-lc-tip": tipLines.join("\n"),
7440
+ "data-lc-tip-side": "bottom"
7441
+ } : {},
7478
7442
  href: USAGE_URL,
7479
7443
  target: "_blank",
7480
7444
  rel: "noreferrer",
@@ -7486,11 +7450,6 @@ window.__ModuleLoader__.load({
7486
7450
  children: money(entry.total)
7487
7451
  })]
7488
7452
  });
7489
- return tipLines.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
7490
- label: tipLines.join("\n"),
7491
- side: "bottom",
7492
- children: pill
7493
- }) : pill;
7494
7453
  };
7495
7454
  }
7496
7455
  //#endregion
@@ -7551,24 +7510,6 @@ window.__ModuleLoader__.load({
7551
7510
  //#endregion
7552
7511
  //#region src/client/components/heatmap.tsx
7553
7512
  /**
7554
- * The Context Dashboard's activity heatmap: a GitHub-style contribution grid
7555
- * (weeks as columns, Sunday-first weekdays as rows, a month label over each
7556
- * column where a month begins — the window's opening column always labeled —
7557
- * and a Less→More key for the depth steps) over the merged daily
7558
- * ledger (overview.ts). Cell depth is the selected metric's share of the
7559
- * window's maximum — distinct active sessions or settlement steps; a session
7560
- * can spread its steps thinly across many days while another day stacks a
7561
- * run, so each metric scales on its OWN maximum — in four steps; a day with
7562
- * data is a button whose click
7563
- * pins the session list to that day (click again to release). Cells tip
7564
- * through the harness's own Tooltip primitive (instant on hover; native
7565
- * `title` lags a second behind), the bubble carrying the date, the day's
7566
- * active sessions, and its steps. The grid is computed from the injected
7567
- * `today` key, so
7568
- * the layout is deterministic in tests and follows the browser's local
7569
- * calendar at runtime.
7570
- */
7571
- /**
7572
7513
  * Lay out the grid: `weeks` columns ending at today's week, each seven
7573
7514
  * Sunday-first cells (row 0 = Sunday). Returns null when `today` (or its
7574
7515
  * week math) fails — a corrupt injected key degrades the card to its empty
@@ -7679,25 +7620,21 @@ window.__ModuleLoader__.load({
7679
7620
  "aria-hidden": "true"
7680
7621
  }, cell.key);
7681
7622
  const level = cell.entry === void 0 ? 0 : levelOf(metricValueOf(cell.entry), max);
7682
- if (cell.entry === void 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
7683
- label: cell.key,
7684
- side: "top",
7685
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: "lc-heat-cell lc-heat-0" })
7623
+ if (cell.entry === void 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7624
+ className: "lc-heat-cell lc-heat-0",
7625
+ "data-lc-tip": cell.key
7686
7626
  }, cell.key);
7687
7627
  const picked = props.selected === cell.key;
7688
7628
  const label = `${cell.key}\n${t("ov.heat.sessions", { n: cell.entry.sessions })}\n${t("ov.heat.steps", { n: cell.entry.requests })}`;
7689
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
7690
- label,
7691
- side: "top",
7692
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
7693
- type: "button",
7694
- className: `lc-heat-cell lc-heat-${String(level)}${picked ? " lc-heat-on" : ""}`,
7695
- "aria-label": label,
7696
- "aria-pressed": picked,
7697
- onClick: () => {
7698
- if (props.onSelect !== void 0) props.onSelect(picked ? null : cell.key);
7699
- }
7700
- })
7629
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
7630
+ type: "button",
7631
+ className: `lc-heat-cell lc-heat-${String(level)}${picked ? " lc-heat-on" : ""}`,
7632
+ "data-lc-tip": label,
7633
+ "aria-label": label,
7634
+ "aria-pressed": picked,
7635
+ onClick: () => {
7636
+ if (props.onSelect !== void 0) props.onSelect(picked ? null : cell.key);
7637
+ }
7701
7638
  }, cell.key);
7702
7639
  })]
7703
7640
  }, wi);
@@ -7825,6 +7762,156 @@ window.__ModuleLoader__.load({
7825
7762
  };
7826
7763
  }
7827
7764
  //#endregion
7765
+ //#region src/client/components/hoverTip.tsx
7766
+ /**
7767
+ * The dashboard's hover tips — one fixed bubble, portaled to <body>, driven
7768
+ * by event delegation off the page root.
7769
+ *
7770
+ * Why not the harness Tooltip: the Insights page is the `lc-ov` query
7771
+ * container, and inline-size containment makes the page the containing block
7772
+ * for FIXED descendants — an in-tree fixed bubble (the harness Tooltip's
7773
+ * unportaled spelling) would paint sidebar-width away from its anchor, while
7774
+ * the primitive's `portal` prop exists only on 0.1.7+. The plugin already
7775
+ * portals its own fixed overlays for exactly this trap (the image lightbox,
7776
+ * base.css), so the page's tips follow that precedent and stay correct on
7777
+ * every supported line.
7778
+ *
7779
+ * Anchors carry `data-lc-tip` (the label) and optional `data-lc-tip-side`
7780
+ * ('top' default, 'bottom'); the zone delegates `mouseover`/`mouseout` and
7781
+ * focus/blur capture, so anchors stay plain elements — no per-cell wrapper
7782
+ * components. One bubble at a time: it re-anchors on anchor switch, hides on
7783
+ * anchor leave, on any zone scroll, on a viewport resize (every anchor just
7784
+ * moved), and on unmount; while shown it sets the anchor's
7785
+ * `aria-describedby`.
7786
+ *
7787
+ * @module dsh-context/client/components/hoverTip
7788
+ */
7789
+ /** The bubble's identity for the anchor's `aria-describedby` (one live bubble at a time). */
7790
+ const TIP_ID = "lc-hovertip-bubble";
7791
+ /** Anchor-to-bubble distance and the viewport margin the bubble clamps inside, in px. */
7792
+ const GAP = 6;
7793
+ const VIEWPORT_MARGIN = 8;
7794
+ /** The nearest tip anchor of an event target, if any. */
7795
+ function anchorOf(target) {
7796
+ return target instanceof Element ? target.closest("[data-lc-tip]") : null;
7797
+ }
7798
+ function tipOf(anchor) {
7799
+ const label = anchor.getAttribute("data-lc-tip");
7800
+ if (label === null || label === "") return null;
7801
+ const r = anchor.getBoundingClientRect();
7802
+ return {
7803
+ anchor,
7804
+ label,
7805
+ side: anchor.getAttribute("data-lc-tip-side") === "bottom" ? "bottom" : "top",
7806
+ rect: {
7807
+ left: r.left,
7808
+ top: r.top,
7809
+ width: r.width,
7810
+ height: r.height,
7811
+ bottom: r.bottom
7812
+ }
7813
+ };
7814
+ }
7815
+ /**
7816
+ * The zone hook: stable delegated handlers plus the portaled bubble. The
7817
+ * bubble renders hidden until the layout effect measures it, so it never
7818
+ * flashes at an unmeasured spot.
7819
+ */
7820
+ function useHoverTip() {
7821
+ const [tip, setTip] = (0, react.useState)(null);
7822
+ const [measured, setMeasured] = (0, react.useState)(null);
7823
+ const bubbleRef = (0, react.useRef)(null);
7824
+ const show = (0, react.useCallback)((anchor) => {
7825
+ setTip((current) => {
7826
+ if (current?.anchor === anchor) return current;
7827
+ current?.anchor.removeAttribute("aria-describedby");
7828
+ const next = tipOf(anchor);
7829
+ if (next === null) return null;
7830
+ anchor.setAttribute("aria-describedby", TIP_ID);
7831
+ return next;
7832
+ });
7833
+ }, []);
7834
+ const hide = (0, react.useCallback)(() => {
7835
+ setTip((current) => {
7836
+ current?.anchor.removeAttribute("aria-describedby");
7837
+ return null;
7838
+ });
7839
+ }, []);
7840
+ const onMouseOver = (0, react.useCallback)((ev) => {
7841
+ const anchor = anchorOf(ev.target);
7842
+ if (anchor !== null) show(anchor);
7843
+ }, [show]);
7844
+ const onMouseOut = (0, react.useCallback)((ev) => {
7845
+ if (anchorOf(ev.target) !== null && anchorOf(ev.relatedTarget) === null) hide();
7846
+ }, [hide]);
7847
+ const onFocusCapture = (0, react.useCallback)((ev) => {
7848
+ const anchor = anchorOf(ev.target);
7849
+ if (anchor !== null) show(anchor);
7850
+ }, [show]);
7851
+ const onBlurCapture = (0, react.useCallback)((ev) => {
7852
+ if (anchorOf(ev.target) !== null && anchorOf(ev.relatedTarget) === null) hide();
7853
+ }, [hide]);
7854
+ const onScrollCapture = (0, react.useCallback)(() => {
7855
+ hide();
7856
+ }, [hide]);
7857
+ (0, react.useEffect)(() => {
7858
+ if (tip === null) return void 0;
7859
+ const retract = () => {
7860
+ hide();
7861
+ };
7862
+ window.addEventListener("resize", retract);
7863
+ return () => {
7864
+ window.removeEventListener("resize", retract);
7865
+ };
7866
+ }, [tip, hide]);
7867
+ (0, react.useLayoutEffect)(() => {
7868
+ if (tip === null || measured?.tip === tip) return;
7869
+ const el = bubbleRef.current;
7870
+ /* v8 ignore next -- the portal commits its ref before layout effects run,
7871
+ * so a null ref here is unreachable; kept as a guard so a future portal
7872
+ * change cannot crash the page. */
7873
+ if (el === null) return;
7874
+ const w = el.offsetWidth;
7875
+ const h = el.offsetHeight;
7876
+ const { rect } = tip;
7877
+ const left = Math.max(VIEWPORT_MARGIN, Math.min(rect.left + rect.width / 2 - w / 2, window.innerWidth - w - VIEWPORT_MARGIN));
7878
+ let top = tip.side === "top" ? rect.top - h - GAP : rect.bottom + GAP;
7879
+ if (tip.side === "top" && top < VIEWPORT_MARGIN) top = rect.bottom + GAP;
7880
+ else if (tip.side === "bottom" && top + h > window.innerHeight - VIEWPORT_MARGIN) top = rect.top - h - GAP;
7881
+ setMeasured({
7882
+ tip,
7883
+ left,
7884
+ top: Math.max(VIEWPORT_MARGIN, top)
7885
+ });
7886
+ }, [tip, measured]);
7887
+ const shown = measured !== null && measured.tip === tip ? measured : null;
7888
+ return {
7889
+ zoneProps: {
7890
+ onMouseOver,
7891
+ onMouseOut,
7892
+ onFocusCapture,
7893
+ onBlurCapture,
7894
+ onScrollCapture
7895
+ },
7896
+ bubble: tip === null ? null : (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7897
+ ref: bubbleRef,
7898
+ id: TIP_ID,
7899
+ role: "tooltip",
7900
+ className: "lc-tip lc-hovertip",
7901
+ style: shown === null ? {
7902
+ left: 0,
7903
+ top: 0,
7904
+ visibility: "hidden"
7905
+ } : {
7906
+ left: shown.left,
7907
+ top: shown.top,
7908
+ opacity: 1
7909
+ },
7910
+ children: tip.label
7911
+ }), document.body)
7912
+ };
7913
+ }
7914
+ //#endregion
7828
7915
  //#region src/client/components/sliceList.tsx
7829
7916
  /**
7830
7917
  * The stats cards' slice rows: the donut's legend with numbers, two tiers
@@ -7935,26 +8022,6 @@ window.__ModuleLoader__.load({
7935
8022
  }
7936
8023
  //#endregion
7937
8024
  //#region src/client/components/overviewUsage.tsx
7938
- /**
7939
- * The Context Insights panel's first-row usage chart — the RIGHT half of the
7940
- * KPI row. Seven day columns ending today, each pairing two bars priced off
7941
- * the merged daily ledger (overview.ts aggregateDays): billed TOKENS (the
7942
- * heatmap's own blue) and the day's estimated COST (green). The fee rides
7943
- * the same per-day pricing records the host fold books at each turn's
7944
- * initiation, priced by the same book and estimator as the KPI band's cost
7945
- * cell — never a whole session's spend dumped on the day it was last
7946
- * active. The two series scale on their OWN window maxima (a $2 week must
7947
- * not flatten under a 169M-token week), so each bar reads as a share of its
7948
- * series' peak; the tooltip carries the exact figures. The window is fixed
7949
- * to the last 7 days — the range selector above scopes the KPI figures, not
7950
- * this calendar.
7951
- *
7952
- * The plot is framed like a chart: hairline gridlines at 0/25/50/75/100% of
7953
- * each series' own peak, a solid baseline at 0, and a tick rail on each
7954
- * side — TOKENS on the left, COST on the right, computed from the same
7955
- * maxima the bars scale to. The cost rail reads '—' until some day actually
7956
- * prices.
7957
- */
7958
8025
  /** The chart's window: today and the six days before it, oldest first. */
7959
8026
  function usageWindowOf(today) {
7960
8027
  const columns = [];
@@ -8035,21 +8102,18 @@ window.__ModuleLoader__.load({
8035
8102
  const tokens = c.entry?.tokens ?? 0;
8036
8103
  const cost = c.entry?.cost ?? null;
8037
8104
  const label = `${c.key}\n${t("ov.usage.tokens")} ${fmt(tokens)}\n${t("ov.usage.costTip")} ${cost === null ? "—" : formatCost(cost, props.currency)}`;
8038
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
8039
- label,
8040
- side: "top",
8041
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
8042
- className: "lc-ov-usage-col",
8043
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8044
- className: "lc-ov-usage-bars",
8045
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8046
- className: "lc-ov-usage-bar lc-ov-usage-tokens",
8047
- style: { height: heightOf(tokens, maxTokens) }
8048
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8049
- className: "lc-ov-usage-bar lc-ov-usage-cost",
8050
- style: { height: cost === null ? "0%" : heightOf(cost, maxCost) }
8051
- })]
8052
- })
8105
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
8106
+ className: "lc-ov-usage-col",
8107
+ "data-lc-tip": label,
8108
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8109
+ className: "lc-ov-usage-bars",
8110
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8111
+ className: "lc-ov-usage-bar lc-ov-usage-tokens",
8112
+ style: { height: heightOf(tokens, maxTokens) }
8113
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8114
+ className: "lc-ov-usage-bar lc-ov-usage-cost",
8115
+ style: { height: cost === null ? "0%" : heightOf(cost, maxCost) }
8116
+ })]
8053
8117
  })
8054
8118
  }, c.key);
8055
8119
  })
@@ -8541,27 +8605,37 @@ window.__ModuleLoader__.load({
8541
8605
  //#endregion
8542
8606
  //#region src/client/components/overviewPanel.tsx
8543
8607
  /**
8544
- * The Context Dashboard panel — the cross-session insight surface opened
8545
- * from the sidebar foot (overviewButton.tsx). Rendered from the frame-wide
8546
- * `shell.overlay` slot behind the module store's flag; data rides the
8547
- * root-scope `useSessions` standard kit (every list row's host-cached
8548
- * projection values), so the panel draws every session's insight without
8549
- * opening one log.
8608
+ * The Context Insights page — the plugin's first-level panel, opened from
8609
+ * the sidebar's panel list (insightPage.ts), a sibling of the shipped
8610
+ * Plugins and Automation tasks pages. Registered on the layout's keyed
8611
+ * `main` slot, so the shell's center column mounts it when the panel is
8612
+ * selected and unmounts it on leave — the page's mount IS its open, and its
8613
+ * data rides the root-scope `useSessions`/`useWorkspaces` standard kit
8614
+ * (every list row's host-cached projection values), so the page draws every
8615
+ * session's insight without opening one log.
8616
+ *
8617
+ * The chrome mirrors the shipped first-level pages: one scroll region whose
8618
+ * centered content column (the Plugins page's 960px frame) opens with the
8619
+ * page heading — the title beside the range group (and the DeepSeek balance
8620
+ * capsule when it serves) — and the page element is the `lc-ov` query
8621
+ * container, so every fold keys off the pane's own width. Hover tips portal
8622
+ * to <body> (hoverTip.tsx) because the container would otherwise capture
8623
+ * their fixed positioning.
8550
8624
  *
8551
- * The panel's first row is a 1:1 column pair: the KPI metrics band (the
8625
+ * The body's first row is a 1:1 column pair: the KPI metrics band (the
8552
8626
  * range's six figures — sessions, billed tokens, cost, cache hit, tool
8553
8627
  * calls, active time — three per row) beside the last-7-days usage chart
8554
- * (each day's billed tokens and estimated cost as a bar pair, folded off
8555
- * the merged daily ledger). Below it, the aggregate stats row folds the
8556
- * same range's
8557
- * sessions into the two donut cards the per-session Context tab opens with —
8558
- * Token Stats (the composition-split billed volume) and Timing Stats (the
8559
- * summed totals). The body is then a 3:7 column pair: the insight column (the
8560
- * activity heatmap, then the preferences entry row) beside the session column
8561
- * (search, group chips, and the card grid); the heatmap keeps its own fixed
8562
- * 8-week window and PINs the list to a picked day (the panel's drill-down
8563
- * gesture). A session card click jumps to that session through the harness's
8564
- * own selection verb (openSessionVia) and closes the panel.
8628
+ * (each day's billed tokens and estimated cost as a bar pair, folded off the
8629
+ * merged daily ledger). Below it, the aggregate stats row folds the same
8630
+ * range's sessions into the two donut cards the per-session Context tab
8631
+ * opens with — Token Stats (the composition-split billed volume) and Timing
8632
+ * Stats (the summed totals). The body is then a 3:7 column pair: the
8633
+ * insight column (the activity heatmap, then the preferences entry row)
8634
+ * beside the session column (search, group chips, and the card grid); the
8635
+ * heatmap keeps its own fixed 8-week window and PINs the list to a picked
8636
+ * day (the page's drill-down gesture). A session card click jumps to that
8637
+ * session through the harness's own selection verb (openSessionVia), whose
8638
+ * navigation returns the center column to the conversation.
8565
8639
  */
8566
8640
  const RANGES = [
8567
8641
  "24h",
@@ -8592,7 +8666,6 @@ window.__ModuleLoader__.load({
8592
8666
  return (typeof locale.getLocale === "function" ? locale.getLocale().active : "en") === "zh" ? "cny" : "usd";
8593
8667
  }
8594
8668
  function OverviewBody(props) {
8595
- const open = (0, react.useSyncExternalStore)(overviewStore.subscribe, overviewStore.getSnapshot);
8596
8669
  const { book } = useModelPrices();
8597
8670
  const snapshot = sessionsSnapshotOf(props);
8598
8671
  const wsSnapshot = workspacesSnapshotOf(props);
@@ -8603,18 +8676,13 @@ window.__ModuleLoader__.load({
8603
8676
  const [sort, setSort] = (0, react.useState)("recent");
8604
8677
  const [metric, setMetric] = (0, react.useState)("steps");
8605
8678
  const [page, setPage] = (0, react.useState)(0);
8606
- const close = () => {
8607
- overviewStore.set(false);
8608
- };
8609
- useEscapeClose(open, close);
8679
+ const { zoneProps, bubble } = useHoverTip();
8610
8680
  const rows = (0, react.useMemo)(() => rowsOfSnapshot(snapshot, wsSnapshot), [snapshot, wsSnapshot]);
8611
8681
  const groups = (0, react.useMemo)(() => sessionGroupsOf(wsSnapshot), [wsSnapshot]);
8612
8682
  (0, react.useEffect)(() => {
8613
- if (open) {
8614
- requestActivityBackfill();
8615
- refreshSessions(ctx);
8616
- }
8617
- }, [open]);
8683
+ requestActivityBackfill();
8684
+ refreshSessions(ctx);
8685
+ }, []);
8618
8686
  (0, react.useEffect)(() => {
8619
8687
  setPage(0);
8620
8688
  }, [
@@ -8624,7 +8692,6 @@ window.__ModuleLoader__.load({
8624
8692
  group,
8625
8693
  sort
8626
8694
  ]);
8627
- if (!open) return null;
8628
8695
  const currency = activeCurrency();
8629
8696
  const now = Date.now();
8630
8697
  const allRows = rows ?? [];
@@ -8649,55 +8716,41 @@ window.__ModuleLoader__.load({
8649
8716
  const days = aggregateDays(allRows, book, currency);
8650
8717
  const openOne = (id) => {
8651
8718
  openSessionVia(ctx, id);
8652
- overviewStore.set(false);
8653
8719
  };
8654
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
8655
- className: "lc-ov-backdrop",
8656
- onClick: close,
8657
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8658
- className: "lc-ov-card",
8659
- onClick: (ev) => {
8660
- ev.stopPropagation();
8661
- },
8662
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8663
- className: "lc-ov-head",
8664
- children: [
8665
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ContextIcon, {
8666
- size: 18,
8667
- className: "lc-ov-head-icon"
8668
- }),
8669
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8670
- className: "lc-ov-title",
8671
- children: t("ov.title")
8672
- }),
8673
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BalanceCapsule, {}),
8674
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
8675
- className: "lc-gran lc-ov-range",
8676
- role: "group",
8677
- "aria-label": t("ov.range.label"),
8678
- children: RANGES.map((r) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
8679
- type: "button",
8680
- className: "lc-gran-btn" + (range === r ? " lc-gran-on" : ""),
8681
- onClick: () => {
8682
- setRange(r);
8683
- },
8684
- children: t("ov.range." + r)
8685
- }, r))
8686
- }),
8687
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
8688
- type: "button",
8689
- className: "lc-modal-close hover:text-(--dsw-alias-label-primary) hover:bg-(--dsw-alias-bg-layer-2)",
8690
- "aria-label": t("cmd.close"),
8691
- onClick: close,
8692
- children: "×"
8693
- })
8694
- ]
8695
- }), rows === null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
8696
- className: "lc-empty",
8697
- children: t("ov.unavailable")
8698
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8699
- className: "lc-ov-scroll",
8700
- children: [
8720
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
8721
+ className: "lc-ov-page",
8722
+ "aria-label": t("ov.title"),
8723
+ ...zoneProps,
8724
+ children: [bubble, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
8725
+ className: "lc-ov-pagescroll",
8726
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8727
+ className: "lc-ov-pagecontent",
8728
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8729
+ className: "lc-ov-pagehead",
8730
+ children: [
8731
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h1", {
8732
+ className: "lc-ov-pagetitle",
8733
+ children: t("ov.title")
8734
+ }),
8735
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BalanceCapsule, {}),
8736
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
8737
+ className: "lc-gran lc-ov-range",
8738
+ role: "group",
8739
+ "aria-label": t("ov.range.label"),
8740
+ children: RANGES.map((r) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
8741
+ type: "button",
8742
+ className: "lc-gran-btn" + (range === r ? " lc-gran-on" : ""),
8743
+ onClick: () => {
8744
+ setRange(r);
8745
+ },
8746
+ children: t("ov.range." + r)
8747
+ }, r))
8748
+ })
8749
+ ]
8750
+ }), rows === null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
8751
+ className: "lc-empty",
8752
+ children: t("ov.unavailable")
8753
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
8701
8754
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8702
8755
  className: "lc-ov-first",
8703
8756
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -8865,7 +8918,6 @@ window.__ModuleLoader__.load({
8865
8918
  className: "lc-ov-settings",
8866
8919
  onClick: () => {
8867
8920
  openPluginSettings();
8868
- close();
8869
8921
  },
8870
8922
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
8871
8923
  className: "lc-ov-settings-label",
@@ -8998,9 +9050,9 @@ window.__ModuleLoader__.load({
8998
9050
  ]
8999
9051
  })]
9000
9052
  })
9001
- ]
9002
- })]
9003
- })
9053
+ ] })]
9054
+ })
9055
+ })]
9004
9056
  });
9005
9057
  }
9006
9058
  return function OverviewPanel(props) {
@@ -9287,6 +9339,97 @@ window.__ModuleLoader__.load({
9287
9339
  };
9288
9340
  }
9289
9341
  //#endregion
9342
+ //#region src/client/insightPage.ts
9343
+ /**
9344
+ * The Context Insights page — the plugin's first-level panel, a sibling of
9345
+ * the shipped Plugins and Automation tasks pages.
9346
+ *
9347
+ * Two registrations, one identity:
9348
+ * - the full page itself on the layout's root keyed `main` slot, under the
9349
+ * panel key — the shell's center column renders it whenever the panel is
9350
+ * selected (keyed entryKey switching mounts it on entry and unmounts it
9351
+ * on leave, so the page's mount IS its open);
9352
+ * - the sidebar entry on the root list `sidebar.panellist` under the same
9353
+ * id — the shell owns the row (button, label, active state, and the
9354
+ * click that selects the panel), the plugin contributes only the glyph
9355
+ * and the localized label thunk.
9356
+ *
9357
+ * Both seats ship on every supported line (the `main` conversation panel and
9358
+ * the panellist contract are present since 0.1.5-rc.1 — the compat matrix
9359
+ * pins both spellings per baseline), so the registrations ride plain
9360
+ * `slots.inject` declaration injects, like the conversation tab's.
9361
+ *
9362
+ * The per-user `insightsEntry` preference gates the pair: 'show' mounts both
9363
+ * registrations, 'hide' unwinds them (a hidden entry leaves the page no
9364
+ * opener). The watcher mirrors placement.ts's preference-glued mounting;
9365
+ * each mount owns its disposers so a preference flip takes down exactly what
9366
+ * it drops.
9367
+ *
9368
+ * @module dsh-context/client/insightPage
9369
+ */
9370
+ /**
9371
+ * The id shared by the sidebar entry and the `main` panel it opens (the
9372
+ * layout's MainPanelId domain) — namespaced, like the right-Sidebar kind, so
9373
+ * no shipped or foreign panel collides with it.
9374
+ */
9375
+ const INSIGHT_PANEL_ID = "dsh-context";
9376
+ /**
9377
+ * Mount the page and its sidebar entry while the preference shows them.
9378
+ * @param ctx - client root context carrying `slots` and the locale service.
9379
+ * @param settings - the preferences store; the gate re-reads on every publish.
9380
+ * @param page - the Insights page component (the root-scope standard kit
9381
+ * arrives on its props, as on every root seat).
9382
+ * @param t - the plugin-namespace translate; the label thunk reads it at call
9383
+ * time, so a language switch relabels the sidebar row.
9384
+ * @param ns - the plugin's locale namespace, put on both registrations so the
9385
+ * framework synthesizes the `t` seat for the page too.
9386
+ * @returns the watcher's disposer (unsubscribes and unwinds any live mount).
9387
+ */
9388
+ function watchInsightPage(ctx, settings, page, t, ns) {
9389
+ let mounted = false;
9390
+ const disposers = [];
9391
+ const own = (result) => {
9392
+ if (typeof result === "function") disposers.push(result);
9393
+ };
9394
+ const mount = () => {
9395
+ own(ctx.slots.inject("main", () => ctx.slots.register({
9396
+ name: "main",
9397
+ key: INSIGHT_PANEL_ID,
9398
+ locale: ns
9399
+ }, page)));
9400
+ own(ctx.slots.inject("sidebar.panellist", () => ctx.slots.register({
9401
+ name: "sidebar.panellist",
9402
+ id: INSIGHT_PANEL_ID,
9403
+ order: 20,
9404
+ label: () => t("ov.title"),
9405
+ locale: ns
9406
+ }, (props) => (0, react.createElement)(InsightPanelIcon, { size: typeof props.size === "number" ? props.size : void 0 }))));
9407
+ };
9408
+ const unmount = () => {
9409
+ while (disposers.length > 0) disposers.pop()?.();
9410
+ };
9411
+ const applyEntry = (entry) => {
9412
+ if (entry === "show" && !mounted) {
9413
+ mounted = true;
9414
+ mount();
9415
+ } else if (entry === "hide" && mounted) {
9416
+ mounted = false;
9417
+ unmount();
9418
+ }
9419
+ };
9420
+ applyEntry(settings.insightsEntry());
9421
+ const unsubscribe = settings.store.subscribe(() => {
9422
+ applyEntry(settings.insightsEntry());
9423
+ });
9424
+ return () => {
9425
+ unsubscribe();
9426
+ if (mounted) {
9427
+ mounted = false;
9428
+ unmount();
9429
+ }
9430
+ };
9431
+ }
9432
+ //#endregion
9290
9433
  //#region src/client/settings.ts
9291
9434
  function prefsOf(value) {
9292
9435
  if (value === null || typeof value !== "object") return {};
@@ -11524,7 +11667,7 @@ window.__ModuleLoader__.load({
11524
11667
  return function PluginInfo() {
11525
11668
  const [latest, setLatest] = (0, react.useState)(null);
11526
11669
  (0, react.useEffect)(() => {
11527
- if ("0.63.0".includes("-dev")) return;
11670
+ if ("0.64.0".includes("-dev")) return;
11528
11671
  let on = true;
11529
11672
  fetchLatestVersion().then((v) => {
11530
11673
  if (on && v) setLatest(v);
@@ -11533,8 +11676,8 @@ window.__ModuleLoader__.load({
11533
11676
  on = false;
11534
11677
  };
11535
11678
  }, []);
11536
- const update = latest !== null && isNewerVersion(latest, "0.63.0") ? latest : null;
11537
- const nameText = "dsh-context (v0.63.0)";
11679
+ const update = latest !== null && isNewerVersion(latest, "0.64.0") ? latest : null;
11680
+ const nameText = "dsh-context (v0.64.0)";
11538
11681
  const nameValue = [nameText];
11539
11682
  if (update) nameValue.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
11540
11683
  className: "lc-pi-update",
@@ -12740,49 +12883,39 @@ window.__ModuleLoader__.load({
12740
12883
  className: "lc-card-title-text",
12741
12884
  children: t("trend.title")
12742
12885
  }),
12743
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
12744
- className: "lc-gran lc-trend-dna",
12745
- role: "group",
12746
- title: t("trend.dnaTip"),
12747
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
12748
- type: "button",
12749
- className: "lc-gran-btn" + (dna ? " lc-gran-on" : ""),
12750
- onClick: () => {
12751
- setDna((v) => !v);
12752
- },
12753
- children: t("trend.dna")
12754
- })
12755
- }),
12756
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
12757
- className: "lc-gran lc-trend-adaptive",
12758
- role: "group",
12759
- title: t("trend.adaptiveHint"),
12760
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
12761
- type: "button",
12762
- className: "lc-gran-btn" + (adaptive ? " lc-gran-on" : ""),
12763
- onClick: () => {
12764
- setAdaptive((on) => !on);
12765
- },
12766
- children: t("trend.adaptive")
12767
- })
12768
- }),
12769
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
12770
- className: "lc-gran lc-trend-duration",
12886
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
12887
+ className: "lc-gran lc-trend-mods",
12771
12888
  role: "group",
12772
- title: t("trend.durationTip"),
12773
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
12774
- type: "button",
12775
- className: "lc-gran-btn" + (durationCurve ? " lc-gran-on" : ""),
12776
- onClick: () => {
12777
- setDurationCurve((on) => !on);
12778
- },
12779
- children: t("trend.duration")
12780
- })
12889
+ children: [
12890
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
12891
+ type: "button",
12892
+ className: "lc-gran-btn" + (dna ? " lc-gran-on" : ""),
12893
+ title: t("trend.dnaTip"),
12894
+ onClick: () => {
12895
+ setDna((v) => !v);
12896
+ },
12897
+ children: t("trend.dna")
12898
+ }),
12899
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
12900
+ type: "button",
12901
+ className: "lc-gran-btn" + (adaptive ? " lc-gran-on" : ""),
12902
+ title: t("trend.adaptiveHint"),
12903
+ onClick: () => {
12904
+ setAdaptive((on) => !on);
12905
+ },
12906
+ children: t("trend.adaptive")
12907
+ }),
12908
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
12909
+ type: "button",
12910
+ className: "lc-gran-btn" + (durationCurve ? " lc-gran-on" : ""),
12911
+ title: t("trend.durationTip"),
12912
+ onClick: () => {
12913
+ setDurationCurve((on) => !on);
12914
+ },
12915
+ children: t("trend.duration")
12916
+ })
12917
+ ]
12781
12918
  }),
12782
- focusCat !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
12783
- className: "lc-card-sub",
12784
- children: t("trend.focus", { cat: kit.catLabel(focusCat) })
12785
- }) : null,
12786
12919
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
12787
12920
  className: "lc-trend-ctl",
12788
12921
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -13140,7 +13273,7 @@ window.__ModuleLoader__.load({
13140
13273
  }
13141
13274
  //#endregion
13142
13275
  //#region \0dsh-global-css:/home/runner/work/dsh-context/dsh-context/src/client/styles/base.css.mjs
13143
- const css$14 = ".lc-root{box-sizing:border-box;height:100%;color:var(--dsw-alias-label-primary);padding:16px 20px 32px;font-size:13px;overflow-y:auto}[data-sidebar-right-open] .lc-root,[data-sidebar-right-float-host] .lc-root{padding:12px}.lc-title-icon{flex:none}.lc-title-label{padding-right:30px}.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{box-sizing:border-box;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,.lc-heat-ctl{align-items:center;gap:6px;margin-left:auto;display:flex}.lc-trend-ctl .lc-gran,.lc-heat-ctl .lc-gran,.lc-heat-ctl .lc-card-sub{margin-left:0}.lc-trend-dna,.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-btn:disabled{opacity:.4;cursor:not-allowed}.lc-gran-btn:disabled:hover{color:var(--dsw-alias-label-secondary)}.lc-gran-on,.lc-gran-on:hover{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground)}.lc-kind-n{font-variant-numeric:tabular-nums;opacity:.65;margin-left:4px}.lc-gran-on .lc-kind-n{opacity:.85}.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-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:has(.lc-stats){flex-direction:column;display:flex}.lc-head .lc-stats{flex:1;align-content:stretch}.lc-head .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-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}";
13276
+ const css$14 = ".lc-root{box-sizing:border-box;height:100%;color:var(--dsw-alias-label-primary);padding:16px 20px 32px;font-size:13px;overflow-y:auto}[data-sidebar-right-open] .lc-root,[data-sidebar-right-float-host] .lc-root{padding:12px}.lc-title-icon{flex:none}.lc-title-label{padding-right:30px}.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{box-sizing:border-box;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,.lc-heat-ctl{align-items:center;gap:6px;margin-left:auto;display:flex}.lc-trend-ctl .lc-gran,.lc-heat-ctl .lc-gran,.lc-heat-ctl .lc-card-sub{margin-left:0}.lc-trend-mods{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-btn:disabled{opacity:.4;cursor:not-allowed}.lc-gran-btn:disabled:hover{color:var(--dsw-alias-label-secondary)}.lc-gran-on,.lc-gran-on:hover{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground)}.lc-kind-n{font-variant-numeric:tabular-nums;opacity:.65;margin-left:4px}.lc-gran-on .lc-kind-n{opacity:.85}.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-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:has(.lc-stats){flex-direction:column;display:flex}.lc-head .lc-stats{flex:1;align-content:stretch}.lc-head .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-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}";
13144
13277
  const tagId$14 = "dsh-context/base.css";
13145
13278
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$14) + "]") === null) {
13146
13279
  const tag = document.createElement("style");
@@ -13151,7 +13284,7 @@ window.__ModuleLoader__.load({
13151
13284
  }
13152
13285
  //#endregion
13153
13286
  //#region \0dsh-global-css:/home/runner/work/dsh-context/dsh-context/src/client/styles/stats.css.mjs
13154
- const css$13 = ".lc-stat{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;flex-direction:column;gap:2px;min-width:0;padding:6px;display:flex}a.lc-stat{color:inherit;cursor:pointer;text-decoration:none}a.lc-stat:hover{border-color:var(--dsw-alias-label-secondary)}.lc-stats .lc-stat{padding:6px 3px}.lc-stats .lc-stat-q{margin:0;position:absolute;top:3px;right:4px}.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-l2);cursor:help;transition:color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), border-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);border-radius:50%;margin-left:4px;font-size:9px;font-style:normal;font-weight:700;line-height:11px;display:inline-block}.lc-stat-tip{max-width:280px;font-weight:400;line-height:1.5;top:calc(100% + 6px);left:0}.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-timing-tps{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);font-variant-numeric:tabular-nums;cursor:default;border-radius:999px;flex:none;margin-left:auto;padding:1px 8px;font-size:12px;line-height:18px}.lc-stat-tip-row{margin-top:2px;display:block}.lc-stat-tip-band{justify-content:space-between;gap:2rem;display:flex}.lc-stat-tip-band i{font-style:normal}.lc-stat-tip-by{color:var(--dsw-alias-label-secondary);margin-top:3px;display:block}.lc-card-sub{color:var(--dsw-alias-label-secondary);margin-left:auto;font-size:12px;font-weight:400}.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-stat-head{color:var(--dsw-alias-label-secondary);margin:12px 0 8px;font-size:11px;font-weight:600}.lc-col-donut{flex-direction:column;display:flex}.lc-col-donut .lc-donut-row{flex:1}.lc-donut{flex:none;position:relative}.lc-donut svg{display:block}.lc-donut-track{stroke:color-mix(in srgb, var(--color-neutral-500) 18%, transparent)}.lc-donut-seg{transition:opacity var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out)}.lc-donut-dim .lc-donut-seg{opacity:.35}.lc-donut-dim .lc-donut-seg-on{opacity:1}.lc-donut-center{pointer-events:none;text-align:center;box-sizing:border-box;flex-direction:column;justify-content:center;align-items:center;gap:1px;padding:0 7px;display:flex;position:absolute;inset:0}.lc-donut-center b{white-space:nowrap;text-overflow:ellipsis;max-width:100%;line-height:1.15;overflow:hidden}.lc-donut-center span{color:var(--dsw-alias-label-secondary);white-space:nowrap}.lc-sl{grid-template-columns:repeat(auto-fill,minmax(160px,1fr));gap:4px 20px;min-width:0;display:grid;overflow:hidden}.lc-sl-row{min-width:0;transition:background-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);border-radius:6px;flex-direction:column;gap:1px;margin:0 -6px;padding:1px 6px;font-size:12px;display:flex}.lc-sl-row-on{background:var(--dsw-alias-interactive-bg-hover)}.lc-sl-row-dim{opacity:.55}.lc-sl-main{align-items:center;gap:6px;min-width:0;display:flex}.lc-sl-dot{border-radius:2px;flex:none;width:8px;height:8px}.lc-sl-label{white-space:nowrap;text-overflow:ellipsis;flex:auto;min-width:0;font-weight:600;line-height:1.25;overflow:hidden}.lc-sl-pct{text-align:right;font-variant-numeric:tabular-nums;flex:none;min-width:34px;font-weight:700}.lc-sl-sub{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;white-space:nowrap;text-overflow:ellipsis;margin-left:14px;font-size:11px;line-height:1.3;overflow:hidden}.lc-pi-grid{grid-template-columns:1fr;gap:8px;display:grid}.lc-pi-row-btn{appearance:none;font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;width:100%;padding:0}.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-hint{text-decoration:none}.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-labelicon{vertical-align:-2px;margin-right:4px;display:inline-block}.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-tstrip{margin-top:10px}.lc-tstrip-wrap{position:relative}.lc-tstrip-bar{background:color-mix(in srgb, var(--color-neutral-500) 18%, transparent);border-radius:4px;width:100%;height:12px;position:relative;overflow:hidden}.lc-tstrip-seg{transform-origin:0;height:100%;transition:opacity var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), filter var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);position:absolute;top:0}.lc-tstrip-seg-on{filter:brightness(1.18)}.lc-tstrip-dim .lc-tstrip-seg{opacity:.35}.lc-tstrip-dim .lc-tstrip-seg-on{opacity:1}.lc-tstrip-axis{height:13px;color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;margin-top:5px;font-size:10px;line-height:13px;position:relative}.lc-tstrip-tick{white-space:nowrap;position:absolute;transform:translate(-50%)}.lc-tstrip-tick:before{content:\"\";background:var(--dsw-alias-border-l1);width:1px;height:3px;position:absolute;top:-4px;left:50%}.lc-tstrip-tick-first{transform:none}.lc-tstrip-tick-first:before{left:0}.lc-tstrip-tick-last{transform:translate(-100%)}.lc-tstrip-tick-last:before{left:auto;right:0}";
13287
+ const css$13 = ".lc-stat{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;flex-direction:column;gap:2px;min-width:0;padding:6px;display:flex}a.lc-stat{color:inherit;cursor:pointer;text-decoration:none}a.lc-stat:hover{border-color:var(--dsw-alias-label-secondary)}.lc-stats .lc-stat{padding:6px 3px}.lc-stats .lc-stat-q{margin:0;position:absolute;top:3px;right:4px}.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-l2);cursor:help;transition:color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), border-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);border-radius:50%;margin-left:4px;font-size:9px;font-style:normal;font-weight:700;line-height:11px;display:inline-block}.lc-stat-tip{max-width:280px;font-weight:400;line-height:1.5;top:calc(100% + 6px);left:0}.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-timing-tps{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);font-variant-numeric:tabular-nums;cursor:default;border-radius:999px;flex:none;margin-left:auto;padding:1px 8px;font-size:12px;line-height:18px}.lc-stat-tip-row{margin-top:2px;display:block}.lc-stat-tip-band{justify-content:space-between;gap:2rem;display:flex}.lc-stat-tip-band i{font-style:normal}.lc-stat-tip-by{color:var(--dsw-alias-label-secondary);margin-top:3px;display:block}.lc-card-sub{color:var(--dsw-alias-label-secondary);margin-left:auto;font-size:12px;font-weight:400}.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-stat-head{color:var(--dsw-alias-label-secondary);margin:12px 0 8px;font-size:11px;font-weight:600}.lc-col-donut{flex-direction:column;display:flex}.lc-col-donut .lc-donut-row{flex:1}.lc-donut{flex:none;position:relative}.lc-donut svg{display:block}.lc-donut-track{stroke:color-mix(in srgb, var(--color-neutral-500) 18%, transparent)}.lc-donut-seg{transition:opacity var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out)}.lc-donut-dim .lc-donut-seg{opacity:.35}.lc-donut-dim .lc-donut-seg-on{opacity:1}.lc-donut-center{pointer-events:none;text-align:center;box-sizing:border-box;flex-direction:column;justify-content:center;align-items:center;gap:1px;padding:0 7px;display:flex;position:absolute;inset:0}.lc-donut-center b{white-space:nowrap;text-overflow:ellipsis;max-width:100%;line-height:1.15;overflow:hidden}.lc-donut-center span{color:var(--dsw-alias-label-secondary);white-space:nowrap}.lc-sl{grid-template-columns:repeat(auto-fill,minmax(min(150px,100%),1fr));gap:4px 8px;min-width:0;display:grid;overflow:hidden}.lc-sl-row{min-width:0;transition:background-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);border-radius:6px;flex-direction:column;gap:1px;margin:0 -6px;padding:1px 6px;font-size:12px;display:flex}.lc-sl-row-on{background:var(--dsw-alias-interactive-bg-hover)}.lc-sl-row-dim{opacity:.55}.lc-sl-main{align-items:center;gap:6px;min-width:0;display:flex}.lc-sl-dot{border-radius:2px;flex:none;width:8px;height:8px}.lc-sl-label{white-space:nowrap;text-overflow:ellipsis;flex:auto;min-width:0;font-weight:600;line-height:1.25;overflow:hidden}.lc-sl-pct{text-align:right;font-variant-numeric:tabular-nums;flex:none;min-width:30px;font-weight:700}.lc-sl-sub{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;white-space:nowrap;text-overflow:ellipsis;margin-left:14px;font-size:11px;line-height:1.3;overflow:hidden}.lc-pi-grid{grid-template-columns:1fr;gap:8px;display:grid}.lc-pi-row-btn{appearance:none;font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;width:100%;padding:0}.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-hint{text-decoration:none}.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-labelicon{vertical-align:-2px;margin-right:4px;display:inline-block}.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-tstrip{margin-top:10px}.lc-tstrip-wrap{position:relative}.lc-tstrip-bar{background:color-mix(in srgb, var(--color-neutral-500) 18%, transparent);border-radius:4px;width:100%;height:12px;position:relative;overflow:hidden}.lc-tstrip-seg{transform-origin:0;height:100%;transition:opacity var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), filter var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);position:absolute;top:0}.lc-tstrip-seg-on{filter:brightness(1.18)}.lc-tstrip-dim .lc-tstrip-seg{opacity:.35}.lc-tstrip-dim .lc-tstrip-seg-on{opacity:1}.lc-tstrip-axis{height:13px;color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;margin-top:5px;font-size:10px;line-height:13px;position:relative}.lc-tstrip-tick{white-space:nowrap;position:absolute;transform:translate(-50%)}.lc-tstrip-tick:before{content:\"\";background:var(--dsw-alias-border-l1);width:1px;height:3px;position:absolute;top:-4px;left:50%}.lc-tstrip-tick-first{transform:none}.lc-tstrip-tick-first:before{left:0}.lc-tstrip-tick-last{transform:translate(-100%)}.lc-tstrip-tick-last:before{left:auto;right:0}";
13155
13288
  const tagId$13 = "dsh-context/stats.css";
13156
13289
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$13) + "]") === null) {
13157
13290
  const tag = document.createElement("style");
@@ -13195,7 +13328,7 @@ window.__ModuleLoader__.load({
13195
13328
  }
13196
13329
  //#endregion
13197
13330
  //#region \0dsh-global-css:/home/runner/work/dsh-context/dsh-context/src/client/styles/trendChart.css.mjs
13198
- const css$9 = ".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-r{flex:none;width:34px}.lc-axis-r span{left:0;right:auto}.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:18px 2px 0;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:color-mix(in srgb, var(--color-neutral-500) 50%, transparent);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-chart-tip span+span{color:var(--dsw-alias-label-secondary)}.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:color-mix(in srgb, var(--color-neutral-500) 14%, transparent)}.lc-bar-stack{flex-direction:column-reverse;width:100%;display:flex}.lc-bar-stack>div{width:100%}.lc-bar-dna{border-radius:2px;width:100%}.lc-bar-stack,.lc-bar-up,.lc-bar-down,.lc-bar-dna{transform-origin:50% 100%}.lc-bar-down{transform-origin:50% 0}.lc-bar-stack>div:first-child{border-radius:0 0 2px 2px}.lc-bar-stack>div:last-child{border-radius:2px 2px 0 0}.lc-bar-stack>div:only-child{border-radius:2px}.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-bar-up>div:last-child{border-radius:2px 2px 0 0}.lc-bar-down>div:last-child{border-radius:0 0 2px 2px}.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=skill] .lc-cat-seg[data-cat=skill],.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-dna-hl{z-index:1;pointer-events:none;align-items:stretch;gap:2px;display:flex;position:absolute;inset:18px 2px 0}.lc-dna-cell{flex:none;width:14px;position:relative}.lc-dna-slice{box-sizing:border-box;border:1px solid var(--dsw-alias-brand-primary);background:color-mix(in srgb, var(--dsw-alias-brand-primary) 26%, transparent);border-radius:1px;width:100%;position:absolute;left:0}.lc-duration{z-index:1;pointer-events:none;position:absolute;top:18px;left:2px;overflow:visible}.lc-duration polyline,.lc-duration circle{fill:none;stroke:var(--dsw-alias-brand-primary);stroke-width:1.5px;stroke-linejoin:round;stroke-linecap:round}.lc-duration circle{fill:var(--dsw-alias-brand-primary)}.lc-chart-dim .lc-duration{opacity:.35}.lc-bar-marker{z-index:2;color:var(--dsw-alias-state-warn-primary);font-size:11px;position:absolute;top:-16px;left:50%;transform:translate(-50%)}.lc-step-flag{z-index:2;background:color-mix(in srgb, var(--color-neutral-500) 45%, transparent);pointer-events:none;width:1px;position:absolute;top:-17px;bottom:0;right:-1px}.lc-step-flag-label{box-sizing:border-box;border:1px solid color-mix(in srgb, var(--color-neutral-500) 45%, transparent);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-secondary);white-space:nowrap;border-radius:3px;padding:1px 3px;font-size:9px;font-weight:600;line-height:1;position:absolute;top:0;right:0}.lc-turns{box-sizing:border-box;gap:2px;width:max-content;min-width:100%;margin-top:4px;padding:0 2px;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}";
13331
+ const css$9 = ".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-r{flex:none;width:34px}.lc-axis-r span{left:0;right:auto}.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:18px 2px 0;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:color-mix(in srgb, var(--color-neutral-500) 50%, transparent);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-chart-tip span+span{color:var(--dsw-alias-label-secondary)}.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:color-mix(in srgb, var(--color-neutral-500) 14%, transparent)}.lc-bar-stack{flex-direction:column-reverse;width:100%;display:flex}.lc-bar-stack>div{width:100%}.lc-bar-dna{border-radius:2px;width:100%}.lc-bar-stack,.lc-bar-up,.lc-bar-down,.lc-bar-dna{transform-origin:50% 100%}.lc-bar-down{transform-origin:50% 0}.lc-bar-stack>div:first-child{border-radius:0 0 2px 2px}.lc-bar-stack>div:last-child{border-radius:2px 2px 0 0}.lc-bar-stack>div:only-child{border-radius:2px}.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-bar-up>div:last-child{border-radius:2px 2px 0 0}.lc-bar-down>div:last-child{border-radius:0 0 2px 2px}.lc-cat-seg{transition: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=skill] .lc-cat-seg[data-cat=skill],.lc-chart[data-catdim=assistant] .lc-cat-seg[data-cat=assistant],.lc-chart[data-catdim=tool] .lc-cat-seg[data-cat=tool]{opacity:1}.lc-dna-hl{z-index:1;pointer-events:none;align-items:stretch;gap:2px;display:flex;position:absolute;inset:18px 2px 0}.lc-dna-cell{flex:none;width:14px;position:relative}.lc-dna-slice{box-sizing:border-box;border:1px solid var(--dsw-alias-brand-primary);background:color-mix(in srgb, var(--dsw-alias-brand-primary) 26%, transparent);border-radius:1px;width:100%;position:absolute;left:0}.lc-duration{z-index:1;pointer-events:none;position:absolute;top:18px;left:2px;overflow:visible}.lc-duration polyline,.lc-duration circle{fill:none;stroke:var(--dsw-alias-brand-primary);stroke-width:1.5px;stroke-linejoin:round;stroke-linecap:round}.lc-duration circle{fill:var(--dsw-alias-brand-primary)}.lc-chart-dim .lc-duration{opacity:.35}.lc-bar-marker{z-index:2;color:var(--dsw-alias-state-warn-primary);font-size:11px;position:absolute;top:-16px;left:50%;transform:translate(-50%)}.lc-step-flag{z-index:2;background:color-mix(in srgb, var(--color-neutral-500) 45%, transparent);pointer-events:none;width:1px;position:absolute;top:-17px;bottom:0;right:-1px}.lc-step-flag-label{box-sizing:border-box;border:1px solid color-mix(in srgb, var(--color-neutral-500) 45%, transparent);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-secondary);white-space:nowrap;border-radius:3px;padding:1px 3px;font-size:9px;font-weight:600;line-height:1;position:absolute;top:0;right:0}.lc-turns{box-sizing:border-box;gap:2px;width:max-content;min-width:100%;margin-top:4px;padding:0 2px;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}";
13199
13332
  const tagId$9 = "dsh-context/trendChart.css";
13200
13333
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$9) + "]") === null) {
13201
13334
  const tag = document.createElement("style");
@@ -13294,7 +13427,7 @@ window.__ModuleLoader__.load({
13294
13427
  }
13295
13428
  //#endregion
13296
13429
  //#region \0dsh-global-css:/home/runner/work/dsh-context/dsh-context/src/client/styles/overview.css.mjs
13297
- const css = ".lc-ov-entry{box-sizing:border-box;width:calc(100% + 4px);height:42px;color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border:0;border-radius:12px;align-items:center;gap:8px;margin:0 -2px;padding:0 10px 0 8px;font-family:inherit;font-size:14px;line-height:22px;display:flex;overflow:hidden}.lc-ov-entry:hover{background:var(--dsw-alias-interactive-bg-hover)}.lc-ov-entry-rail{border-radius:50%;flex:none;justify-content:center;gap:0;width:36px;height:36px;margin:0;padding:0}.lc-ov-entry-icon{flex:none}.lc-ov-entry-label{text-align:left;white-space:nowrap;text-overflow:ellipsis;flex:auto;min-width:0;overflow:hidden}.lc-ov-backdrop{z-index:200;background:var(--dsw-alias-bg-mask-1,#00000073);justify-content:center;align-items:center;display:flex;position:fixed;inset:0;container:lc-ov/inline-size}.lc-ov-card{box-sizing:border-box;background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l2);width:min(1120px,100vw - 32px);height:calc(100% - 80px);box-shadow:var(--dsw-shadow-lv3,0 12px 32px #0006);color:var(--dsw-alias-label-primary);border-radius:12px;flex-direction:column;padding:16px 18px 18px;font-size:13px;display:flex;overflow:hidden}.lc-ov-head{flex-wrap:wrap;flex:none;align-items:center;gap:10px;margin-bottom:14px;display:flex}.lc-ov-head-icon{flex:none}.lc-ov-title{white-space:nowrap;font-size:15px;font-weight:600}.lc-ov-balance{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);max-width:100%;color:inherit;border-radius:999px;flex:none;align-items:center;gap:6px;padding:2px 10px;font-size:12px;line-height:18px;text-decoration:none;display:inline-flex}.lc-ov-balance:hover .lc-ov-balance-value{text-decoration:underline}.lc-ov-balance-label{color:var(--dsw-alias-label-secondary);white-space:nowrap}.lc-ov-balance-value{font-variant-numeric:tabular-nums;white-space:nowrap;font-weight:600}.lc-ov-head .lc-modal-close{flex:none;margin-left:0}.lc-ov-scroll{scrollbar-gutter:stable;flex:auto;min-height:0;padding-right:8px;overflow-y:auto}.lc-ov-first{grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;margin-bottom:10px;display:grid}.lc-ov-kpis{grid-template-columns:repeat(3,minmax(0,1fr));gap:8px;display:grid}.lc-ov-kpi{align-items:center;padding:8px}.lc-ov-kpi .lc-stat-value{font-size:20px}@container lc-ov (width<=932px){.lc-ov-first{grid-template-columns:minmax(0,1fr)}}@container lc-ov (width<=640px){.lc-ov-kpis{grid-template-columns:repeat(2,minmax(0,1fr))}}.lc-ov-usage{box-sizing:border-box;flex-direction:column;flex:auto;min-width:0;margin-bottom:0;display:flex}.lc-ov-usage .lc-card-title{margin-bottom:4px}.lc-ov-usage-plot{flex:auto;align-items:stretch;gap:6px;min-height:0;display:flex}.lc-ov-usage-rail{width:42px;color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;flex:none;font-size:9px;line-height:1.2;position:relative}.lc-ov-usage-rail-l .lc-ov-usage-tick{right:0}.lc-ov-usage-rail-r .lc-ov-usage-tick{left:0}.lc-ov-usage-tick{white-space:nowrap;position:absolute;transform:translateY(-50%)}.lc-ov-usage-grid{flex:auto;min-width:0;min-height:56px;display:flex;position:relative}.lc-ov-usage-line{background:color-mix(in srgb, var(--dsw-alias-border-l2) 70%, transparent);height:1px;position:absolute;left:0;right:0}.lc-ov-usage-line-0{background:var(--dsw-alias-border-l2)}.lc-ov-usage-cols{flex:auto;align-items:stretch;gap:6px;min-width:0;display:flex;position:relative}.lc-ov-usage-col{flex-direction:column;flex:1 1 0;min-width:0;display:flex}.lc-ov-usage-bars{flex:auto;justify-content:center;align-items:flex-end;gap:3px;width:100%;display:flex}.lc-ov-usage-bar{border-radius:3px 3px 0 0;flex:none;width:10px}.lc-ov-usage-tokens{background:color-mix(in srgb, var(--color-blue-500) 72%, transparent)}.lc-ov-usage-cost{background:color-mix(in srgb, var(--color-green-500) 72%, transparent)}.lc-ov-usage-days{flex:none;gap:6px;padding-top:3px;display:flex}.lc-ov-usage-day{text-align:center;min-width:0;color:var(--dsw-alias-label-secondary);white-space:nowrap;font-variant-numeric:tabular-nums;flex:1 1 0;font-size:9px;line-height:1.2}.lc-ov-usage-key{flex:none;justify-content:flex-end;align-items:center;gap:5px;padding-top:5px;display:flex}.lc-ov-usage-swatch{border-radius:2px;flex:none;width:10px;height:8px}.lc-ov-usage-key-label{color:var(--dsw-alias-label-secondary);font-size:9px}.lc-ov-stats{grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;margin-bottom:10px;display:grid}.lc-ov-stats>.lc-card{box-sizing:border-box;min-width:0;margin-bottom:0}@container lc-ov (width<=700px){.lc-ov-stats{grid-template-columns:minmax(0,1fr)}}.lc-ov-body{grid-template-columns:minmax(0,3fr) minmax(0,7fr);align-items:start;gap:10px;display:grid}.lc-ov-left{flex-direction:column;gap:10px;min-width:0;display:flex}.lc-ov-right{min-width:0}@container lc-ov (width<=932px){.lc-ov-body{display:block}.lc-ov-left{margin-bottom:12px}}.lc-ov-left>.lc-card{box-sizing:border-box;min-width:0;margin-bottom:0}.lc-ov-heat-card{flex-direction:column;display:flex}.lc-ov-settings{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);width:100%;font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;transition:border-color 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), color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);border-radius:10px;flex:none;align-items:center;gap:8px;padding:9px 12px;font-size:12px;display:flex}.lc-ov-settings:hover{border-color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary)}.lc-ov-settings-label{white-space:nowrap;flex:none;align-items:center;gap:6px;display:inline-flex}.lc-ov-settings-hint{text-align:right;white-space:nowrap;text-overflow:ellipsis;flex:auto;min-width:0;overflow:hidden}.lc-heat-wrap{flex-direction:column;flex:1;display:flex}.lc-heat{flex:1;justify-content:center;align-items:center;gap:8px;display:flex}.lc-heat-wds,.lc-heat-col{padding-top:18px}.lc-heat-wds{flex-direction:column;gap:3px;display:flex}.lc-heat-wd{height:20px;color:var(--dsw-alias-label-secondary);text-align:center;white-space:nowrap;flex:none;justify-content:center;align-items:center;font-size:9px;display:flex}.lc-heat-cols{gap:3px;display:flex}.lc-heat-col{flex-direction:column;gap:3px;display:flex;position:relative}.lc-heat-mon{color:var(--dsw-alias-label-secondary);white-space:nowrap;font-size:9px;line-height:18px;position:absolute;top:0;left:0}.lc-heat-cell{box-sizing:border-box;background:var(--dsw-alias-bg-layer-2);cursor:default;border:0;border-radius:20%;width:20px;height:20px;padding:0}button.lc-heat-cell{cursor:pointer}button.lc-heat-cell:hover{box-shadow:0 0 0 1.5px color-mix(in srgb, var(--color-blue-500) 70%, transparent)}.lc-heat-future{background:0 0}.lc-heat-0{background:color-mix(in srgb, var(--dsw-alias-label-secondary) 16%, transparent)}.lc-heat-1{background:color-mix(in srgb, var(--color-blue-500) 28%, transparent)}.lc-heat-2{background:color-mix(in srgb, var(--color-blue-500) 50%, transparent)}.lc-heat-3{background:color-mix(in srgb, var(--color-blue-500) 72%, transparent)}.lc-heat-4{background:color-mix(in srgb, var(--color-blue-500) 92%, transparent)}.lc-heat-on{box-shadow:0 0 0 1.5px var(--color-blue-500)}.lc-heat-legend{justify-content:flex-end;align-items:center;gap:3px;padding-top:6px;display:flex}.lc-heat-key{color:var(--dsw-alias-label-secondary);font-size:9px}.lc-ov-list-head{flex-wrap:wrap;align-items:center;gap:10px;margin-bottom:10px;display:flex}.lc-ov-list-title{white-space:nowrap;font-weight:600}.lc-ov-list-count{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;background:var(--dsw-alias-bg-layer-2);border-radius:8px;padding:1px 7px;font-size:11px}.lc-ov-day-chip{border:1px solid color-mix(in srgb, var(--color-blue-500) 45%, transparent);color:var(--color-blue-500);background:color-mix(in srgb, var(--color-blue-500) 10%, transparent);cursor:pointer;white-space:nowrap;border-radius:999px;padding:1px 10px;font-family:inherit;font-size:11px;line-height:1.4}.lc-ov-search{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);min-width:110px;font:inherit;color:var(--dsw-alias-label-primary);transition:border-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);border-radius:6px;outline:none;flex:150px;padding:4px 10px;font-size:12px}.lc-ov-search:focus{border-color:var(--dsw-alias-label-secondary)}.lc-ov-search::placeholder{color:var(--dsw-alias-label-secondary)}.lc-ov-groups{flex-wrap:wrap;gap:6px;margin:-2px 0 10px;display:flex}.lc-ov-chip{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);font:inherit;cursor:pointer;white-space:nowrap;text-overflow:ellipsis;max-width:220px;transition:color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), border-color 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);background:0 0;border-radius:999px;align-items:baseline;gap:5px;padding:2px 10px;font-size:11px;line-height:1.5;display:inline-flex;overflow:hidden}.lc-ov-chip:hover{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-secondary)}.lc-ov-chip-on,.lc-ov-chip-on:hover{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground);border-color:#0000}.lc-ov-chip-n{font-variant-numeric:tabular-nums;opacity:.65;font-size:10px}.lc-ov-chip-on .lc-ov-chip-n{opacity:.85}.lc-ov-grid{grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:10px;display:grid}.lc-ov-session{text-align:left;background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l2);cursor:pointer;font:inherit;color:inherit;transition:border-color 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);border-radius:10px;flex-direction:column;gap:6px;padding:10px 12px;display:flex}.lc-ov-session:hover{border-color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-2)}.lc-ov-session-current{border-color:color-mix(in srgb, var(--color-blue-500) 65%, transparent)}.lc-ov-session-head{align-items:flex-start;gap:6px;min-width:0;display:flex}.lc-ov-running{background:var(--color-green-500);border-radius:50%;flex:none;width:7px;height:7px}.lc-ov-session-title{-webkit-line-clamp:2;overflow-wrap:anywhere;-webkit-box-orient:vertical;flex:auto;min-width:0;font-weight:600;display:-webkit-box;overflow:hidden}.lc-ov-current{color:var(--color-blue-500);border:1px solid color-mix(in srgb, var(--color-blue-500) 45%, transparent);border-radius:4px;flex:none;padding:0 4px;font-size:10px;line-height:1.5}.lc-ov-session-times{flex-direction:column;flex:none;align-items:flex-end;gap:1px;display:flex}.lc-ov-session-time{color:var(--dsw-alias-label-secondary);white-space:nowrap;font-size:11px}.lc-ov-session-created{color:var(--dsw-alias-label-secondary);white-space:nowrap;font-variant-numeric:tabular-nums;font-size:10px;line-height:1.4}.lc-ov-session-crumb{min-width:0;color:var(--dsw-alias-label-secondary);white-space:nowrap;align-items:center;gap:5px;font-size:11px;display:flex;overflow:hidden}.lc-ov-crumb-group{text-overflow:ellipsis;flex:none;max-width:55%;overflow:hidden}.lc-ov-crumb-sep{opacity:.55;flex:none}.lc-ov-crumb-project{text-overflow:ellipsis;min-width:0;font-family:var(--ds-font-family-code,ui-monospace, SFMono-Regular, Menlo, monospace);color:var(--dsw-alias-label-primary);background:color-mix(in srgb, var(--dsw-alias-label-secondary) 16%, transparent);border-radius:999px;flex:0 auto;padding:0 8px;font-size:10px;line-height:1.6;overflow:hidden}.lc-ov-session-body{align-items:center;gap:14px;min-width:0;display:flex}.lc-ov-mini-stats{flex-direction:column;flex:auto;gap:3px;min-width:0;display:flex}.lc-ov-mini-stat{justify-content:space-between;align-items:baseline;gap:10px;font-size:11px;display:flex}.lc-ov-mini-label{color:var(--dsw-alias-label-secondary);white-space:nowrap;flex:none}.lc-ov-mini-value{font-variant-numeric:tabular-nums;white-space:nowrap;font-weight:600}.lc-ov-session-empty{color:var(--dsw-alias-label-secondary);padding:6px 0;font-size:11px;line-height:1.5}.lc-ov-session-preview{border-top:1px solid color-mix(in srgb, var(--dsw-alias-border-l2) 60%, transparent);align-items:baseline;gap:6px;min-width:0;margin-top:auto;padding-top:6px;display:flex}.lc-ov-session-preview-label{color:var(--dsw-alias-label-secondary);flex:none;font-size:10px}.lc-ov-session-preview-text{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--dsw-alias-label-primary);flex:0 auto;font-size:11px;line-height:1.5;overflow:hidden}.lc-ov-pager{justify-content:center;align-items:center;gap:10px;margin-top:12px;display:flex}.lc-ov-pager-btn{border:1px solid var(--dsw-alias-border-l2);width:26px;height:22px;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);background:0 0;border-radius:6px;flex:none;justify-content:center;align-items:center;line-height:1;display:flex}.lc-ov-pager-btn:hover:enabled{border-color:var(--dsw-alias-label-secondary)}.lc-ov-pager-btn:disabled{opacity:.4;cursor:default}.lc-ov-pager-n{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;white-space:nowrap;font-size:11px}";
13430
+ const css = ".lc-ov-page{box-sizing:border-box;background:var(--dsw-alias-bg-base);width:100%;min-width:0;height:100%;min-height:0;color:var(--dsw-alias-label-primary);flex-direction:column;font-size:13px;display:flex;overflow:hidden;container:lc-ov/inline-size}.lc-ov-pagescroll{scrollbar-gutter:stable;flex:auto;min-height:0;overflow-y:auto}.lc-ov-pagecontent{max-width:960px;margin:0 auto;padding:0 clamp(24px,4vw,48px) 48px}.lc-ov-pagehead{flex-wrap:wrap;align-items:center;gap:16px;margin-bottom:24px;padding-top:28px;display:flex}[data-platform=darwin] .lc-ov-pagehead{padding-top:calc(28px + var(--dsh-frame-top-clearance,0px))}.lc-ov-pagetitle{flex:auto;min-width:0;margin:0;font-size:20px;font-weight:500;line-height:28px}.lc-ov-balance{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);max-width:100%;color:inherit;border-radius:999px;flex:none;align-items:center;gap:6px;padding:2px 10px;font-size:12px;line-height:18px;text-decoration:none;display:inline-flex}.lc-ov-balance:hover .lc-ov-balance-value{text-decoration:underline}.lc-ov-balance-label{color:var(--dsw-alias-label-secondary);white-space:nowrap}.lc-ov-balance-value{font-variant-numeric:tabular-nums;white-space:nowrap;font-weight:600}.lc-hovertip{z-index:300;white-space:pre-line;max-width:min(320px,50vw);position:fixed}.lc-ov-first{grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;margin-bottom:10px;display:grid}.lc-ov-kpis{grid-template-columns:repeat(3,minmax(0,1fr));gap:8px;display:grid}.lc-ov-kpi{align-items:center;padding:8px}.lc-ov-kpi .lc-stat-value{font-size:20px}@container lc-ov (width<=932px){.lc-ov-first{grid-template-columns:minmax(0,1fr)}}@container lc-ov (width<=640px){.lc-ov-kpis{grid-template-columns:repeat(2,minmax(0,1fr))}}.lc-ov-usage{box-sizing:border-box;flex-direction:column;flex:auto;min-width:0;margin-bottom:0;display:flex}.lc-ov-usage .lc-card-title{margin-bottom:4px}.lc-ov-usage-plot{flex:auto;align-items:stretch;gap:6px;min-height:0;display:flex}.lc-ov-usage-rail{width:42px;color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;flex:none;font-size:9px;line-height:1.2;position:relative}.lc-ov-usage-rail-l .lc-ov-usage-tick{right:0}.lc-ov-usage-rail-r .lc-ov-usage-tick{left:0}.lc-ov-usage-tick{white-space:nowrap;position:absolute;transform:translateY(-50%)}.lc-ov-usage-grid{flex:auto;min-width:0;min-height:56px;display:flex;position:relative}.lc-ov-usage-line{background:color-mix(in srgb, var(--dsw-alias-border-l2) 70%, transparent);height:1px;position:absolute;left:0;right:0}.lc-ov-usage-line-0{background:var(--dsw-alias-border-l2)}.lc-ov-usage-cols{flex:auto;align-items:stretch;gap:6px;min-width:0;display:flex;position:relative}.lc-ov-usage-col{flex-direction:column;flex:1 1 0;min-width:0;display:flex}.lc-ov-usage-bars{flex:auto;justify-content:center;align-items:flex-end;gap:3px;width:100%;display:flex}.lc-ov-usage-bar{border-radius:3px 3px 0 0;flex:none;width:10px}.lc-ov-usage-tokens{background:color-mix(in srgb, var(--color-blue-500) 72%, transparent)}.lc-ov-usage-cost{background:color-mix(in srgb, var(--color-green-500) 72%, transparent)}.lc-ov-usage-days{flex:none;gap:6px;padding-top:3px;display:flex}.lc-ov-usage-day{text-align:center;min-width:0;color:var(--dsw-alias-label-secondary);white-space:nowrap;font-variant-numeric:tabular-nums;flex:1 1 0;font-size:9px;line-height:1.2}.lc-ov-usage-key{flex:none;justify-content:flex-end;align-items:center;gap:5px;padding-top:5px;display:flex}.lc-ov-usage-swatch{border-radius:2px;flex:none;width:10px;height:8px}.lc-ov-usage-key-label{color:var(--dsw-alias-label-secondary);font-size:9px}.lc-ov-stats{grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;margin-bottom:10px;display:grid}.lc-ov-stats>.lc-card{box-sizing:border-box;min-width:0;margin-bottom:0}@container lc-ov (width<=700px){.lc-ov-stats{grid-template-columns:minmax(0,1fr)}}.lc-ov-body{grid-template-columns:minmax(0,3fr) minmax(0,7fr);align-items:start;gap:10px;display:grid}.lc-ov-left{flex-direction:column;gap:10px;min-width:0;display:flex}.lc-ov-right{min-width:0}@container lc-ov (width<=932px){.lc-ov-body{display:block}.lc-ov-left{margin-bottom:12px}}.lc-ov-left>.lc-card{box-sizing:border-box;min-width:0;margin-bottom:0}.lc-ov-heat-card{flex-direction:column;display:flex}.lc-ov-settings{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);width:100%;font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;transition:border-color 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), color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);border-radius:10px;flex:none;align-items:center;gap:8px;padding:9px 12px;font-size:12px;display:flex}.lc-ov-settings:hover{border-color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary)}.lc-ov-settings-label{white-space:nowrap;flex:none;align-items:center;gap:6px;display:inline-flex}.lc-ov-settings-hint{text-align:right;white-space:nowrap;text-overflow:ellipsis;flex:auto;min-width:0;overflow:hidden}.lc-heat-wrap{flex-direction:column;flex:1;display:flex}.lc-heat{flex:1;justify-content:center;align-items:center;gap:8px;display:flex}.lc-heat-wds,.lc-heat-col{padding-top:18px}.lc-heat-wds{flex-direction:column;gap:3px;display:flex}.lc-heat-wd{height:20px;color:var(--dsw-alias-label-secondary);text-align:center;white-space:nowrap;flex:none;justify-content:center;align-items:center;font-size:9px;display:flex}.lc-heat-cols{gap:3px;display:flex}.lc-heat-col{flex-direction:column;gap:3px;display:flex;position:relative}.lc-heat-mon{color:var(--dsw-alias-label-secondary);white-space:nowrap;font-size:9px;line-height:18px;position:absolute;top:0;left:0}.lc-heat-cell{box-sizing:border-box;background:var(--dsw-alias-bg-layer-2);cursor:default;border:0;border-radius:20%;width:20px;height:20px;padding:0}button.lc-heat-cell{cursor:pointer}button.lc-heat-cell:hover{box-shadow:0 0 0 1.5px color-mix(in srgb, var(--color-blue-500) 70%, transparent)}.lc-heat-future{background:0 0}.lc-heat-0{background:color-mix(in srgb, var(--dsw-alias-label-secondary) 16%, transparent)}.lc-heat-1{background:color-mix(in srgb, var(--color-blue-500) 28%, transparent)}.lc-heat-2{background:color-mix(in srgb, var(--color-blue-500) 50%, transparent)}.lc-heat-3{background:color-mix(in srgb, var(--color-blue-500) 72%, transparent)}.lc-heat-4{background:color-mix(in srgb, var(--color-blue-500) 92%, transparent)}.lc-heat-on{box-shadow:0 0 0 1.5px var(--color-blue-500)}.lc-heat-legend{justify-content:flex-end;align-items:center;gap:3px;padding-top:6px;display:flex}.lc-heat-key{color:var(--dsw-alias-label-secondary);font-size:9px}.lc-ov-list-head{flex-wrap:wrap;align-items:center;gap:10px;margin-bottom:10px;display:flex}.lc-ov-list-title{white-space:nowrap;font-weight:600}.lc-ov-list-count{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;background:var(--dsw-alias-bg-layer-2);border-radius:8px;padding:1px 7px;font-size:11px}.lc-ov-day-chip{border:1px solid color-mix(in srgb, var(--color-blue-500) 45%, transparent);color:var(--color-blue-500);background:color-mix(in srgb, var(--color-blue-500) 10%, transparent);cursor:pointer;white-space:nowrap;border-radius:999px;padding:1px 10px;font-family:inherit;font-size:11px;line-height:1.4}.lc-ov-search{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);min-width:110px;font:inherit;color:var(--dsw-alias-label-primary);transition:border-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);border-radius:6px;outline:none;flex:150px;padding:4px 10px;font-size:12px}.lc-ov-search:focus{border-color:var(--dsw-alias-label-secondary)}.lc-ov-search::placeholder{color:var(--dsw-alias-label-secondary)}.lc-ov-groups{flex-wrap:wrap;gap:6px;margin:-2px 0 10px;display:flex}.lc-ov-chip{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);font:inherit;cursor:pointer;white-space:nowrap;text-overflow:ellipsis;max-width:220px;transition:color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), border-color 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);background:0 0;border-radius:999px;align-items:baseline;gap:5px;padding:2px 10px;font-size:11px;line-height:1.5;display:inline-flex;overflow:hidden}.lc-ov-chip:hover{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-secondary)}.lc-ov-chip-on,.lc-ov-chip-on:hover{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground);border-color:#0000}.lc-ov-chip-n{font-variant-numeric:tabular-nums;opacity:.65;font-size:10px}.lc-ov-chip-on .lc-ov-chip-n{opacity:.85}.lc-ov-grid{grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:10px;display:grid}.lc-ov-session{text-align:left;background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l2);cursor:pointer;font:inherit;color:inherit;transition:border-color 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);border-radius:10px;flex-direction:column;gap:6px;padding:10px 12px;display:flex}.lc-ov-session:hover{border-color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-2)}.lc-ov-session-current{border-color:color-mix(in srgb, var(--color-blue-500) 65%, transparent)}.lc-ov-session-head{align-items:flex-start;gap:6px;min-width:0;display:flex}.lc-ov-running{background:var(--color-green-500);border-radius:50%;flex:none;width:7px;height:7px}.lc-ov-session-title{-webkit-line-clamp:2;overflow-wrap:anywhere;-webkit-box-orient:vertical;flex:auto;min-width:0;font-weight:600;display:-webkit-box;overflow:hidden}.lc-ov-current{color:var(--color-blue-500);border:1px solid color-mix(in srgb, var(--color-blue-500) 45%, transparent);border-radius:4px;flex:none;padding:0 4px;font-size:10px;line-height:1.5}.lc-ov-session-times{flex-direction:column;flex:none;align-items:flex-end;gap:1px;display:flex}.lc-ov-session-time{color:var(--dsw-alias-label-secondary);white-space:nowrap;font-size:11px}.lc-ov-session-created{color:var(--dsw-alias-label-secondary);white-space:nowrap;font-variant-numeric:tabular-nums;font-size:10px;line-height:1.4}.lc-ov-session-crumb{min-width:0;color:var(--dsw-alias-label-secondary);white-space:nowrap;align-items:center;gap:5px;font-size:11px;display:flex;overflow:hidden}.lc-ov-crumb-group{text-overflow:ellipsis;flex:none;max-width:55%;overflow:hidden}.lc-ov-crumb-sep{opacity:.55;flex:none}.lc-ov-crumb-project{text-overflow:ellipsis;min-width:0;font-family:var(--ds-font-family-code,ui-monospace, SFMono-Regular, Menlo, monospace);color:var(--dsw-alias-label-primary);background:color-mix(in srgb, var(--dsw-alias-label-secondary) 16%, transparent);border-radius:999px;flex:0 auto;padding:0 8px;font-size:10px;line-height:1.6;overflow:hidden}.lc-ov-session-body{align-items:center;gap:14px;min-width:0;display:flex}.lc-ov-mini-stats{flex-direction:column;flex:auto;gap:3px;min-width:0;display:flex}.lc-ov-mini-stat{justify-content:space-between;align-items:baseline;gap:10px;font-size:11px;display:flex}.lc-ov-mini-label{color:var(--dsw-alias-label-secondary);white-space:nowrap;flex:none}.lc-ov-mini-value{font-variant-numeric:tabular-nums;white-space:nowrap;font-weight:600}.lc-ov-session-empty{color:var(--dsw-alias-label-secondary);padding:6px 0;font-size:11px;line-height:1.5}.lc-ov-session-preview{border-top:1px solid color-mix(in srgb, var(--dsw-alias-border-l2) 60%, transparent);align-items:baseline;gap:6px;min-width:0;margin-top:auto;padding-top:6px;display:flex}.lc-ov-session-preview-label{color:var(--dsw-alias-label-secondary);flex:none;font-size:10px}.lc-ov-session-preview-text{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--dsw-alias-label-primary);flex:0 auto;font-size:11px;line-height:1.5;overflow:hidden}.lc-ov-pager{justify-content:center;align-items:center;gap:10px;margin-top:12px;display:flex}.lc-ov-pager-btn{border:1px solid var(--dsw-alias-border-l2);width:26px;height:22px;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);background:0 0;border-radius:6px;flex:none;justify-content:center;align-items:center;line-height:1;display:flex}.lc-ov-pager-btn:hover:enabled{border-color:var(--dsw-alias-label-secondary)}.lc-ov-pager-btn:disabled{opacity:.4;cursor:default}.lc-ov-pager-n{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;white-space:nowrap;font-size:11px}";
13298
13431
  const tagId = "dsh-context/overview.css";
13299
13432
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
13300
13433
  const tag = document.createElement("style");
@@ -13373,24 +13506,8 @@ window.__ModuleLoader__.load({
13373
13506
  inject: (sessionId = "") => ({ hooks: { contextModal: modalStoreOf(sessionId) } })
13374
13507
  }, (props) => (0, react.createElement)(ContextModal, props));
13375
13508
  });
13376
- const OverviewButton = makeOverviewButton(kit, settings);
13377
- ctx.slots.inject("sidebar.footer.action", () => {
13378
- return ctx.slots.register({
13379
- name: "sidebar.footer.action",
13380
- id: "context-overview",
13381
- order: 10,
13382
- locale: NS
13383
- }, (props) => (0, react.createElement)(OverviewButton, props));
13384
- });
13385
13509
  const OverviewPanel = makeOverviewPanel(ctx, kit);
13386
- ctx.slots.inject("shell.overlay", () => {
13387
- return ctx.slots.register({
13388
- name: "shell.overlay",
13389
- id: "context-overview",
13390
- order: 10,
13391
- locale: NS
13392
- }, (props) => (0, react.createElement)(OverviewPanel, props));
13393
- });
13510
+ ctx.effect(() => watchInsightPage(ctx, settings, (props) => (0, react.createElement)(OverviewPanel, props), t, NS), "dsh-context: insight page");
13394
13511
  /** The injected face both preference cards ride: the settings store as the
13395
13512
  * framework's hooks-compartment `useContextSettings` seat, plus the set verb. */
13396
13513
  const cardFace = () => ({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-context",
3
- "version": "0.63.0",
3
+ "version": "0.64.0",
4
4
  "description": "A DeepSeek Harness plugin for context insight and management, with context dashboard and context command, for understanding how the context is made of, and how it evolves.",
5
5
  "icon": "icon.svg",
6
6
  "author": "bowenliang123",