dsh-context 0.55.0 → 0.56.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/client.js CHANGED
@@ -91,7 +91,7 @@ window.__ModuleLoader__.load({
91
91
  "plugin.name": "插件",
92
92
  "plugin.github": "GitHub",
93
93
  "plugin.settings": "设置",
94
- "plugin.settingsOpen": "打开偏好设置",
94
+ "plugin.settingsOpen": "打开插件设置",
95
95
  "trend.title": "上下文趋势",
96
96
  "gran.step": "步骤",
97
97
  "gran.turn": "轮次",
@@ -363,9 +363,15 @@ window.__ModuleLoader__.load({
363
363
  "ov.heat.sub": "按日期筛选",
364
364
  "ov.heat.empty": "暂无活跃数据 — 会话产生模型请求后,这里会显示每日用量",
365
365
  "ov.heat.sessions": "{n} 个活跃会话",
366
- "ov.heat.wd.1": "一",
367
- "ov.heat.wd.3": "三",
368
- "ov.heat.wd.5": "五",
366
+ "ov.heat.less": "少",
367
+ "ov.heat.more": "多",
368
+ "ov.heat.metric": "指标",
369
+ "ov.heat.metric.sessions": "会话",
370
+ "ov.heat.metric.steps": "步数",
371
+ "ov.heat.steps": "{n} 步",
372
+ "ov.heat.wd.1": "星期一",
373
+ "ov.heat.wd.3": "星期三",
374
+ "ov.heat.wd.5": "星期五",
369
375
  "ov.heat.mon.01": "1月",
370
376
  "ov.heat.mon.02": "2月",
371
377
  "ov.heat.mon.03": "3月",
@@ -379,7 +385,7 @@ window.__ModuleLoader__.load({
379
385
  "ov.heat.mon.11": "11月",
380
386
  "ov.heat.mon.12": "12月",
381
387
  "ov.list.title": "会话",
382
- "ov.list.search": "搜索标题或目录…",
388
+ "ov.list.search": "搜索标题 / 目录 / 最后消息…",
383
389
  "ov.list.sortLabel": "排序",
384
390
  "ov.list.sort.recent": "最近更新",
385
391
  "ov.list.sort.tokens": "Token 总用量",
@@ -464,7 +470,7 @@ window.__ModuleLoader__.load({
464
470
  "plugin.name": "Plugin",
465
471
  "plugin.github": "GitHub",
466
472
  "plugin.settings": "Settings",
467
- "plugin.settingsOpen": "Open preferences",
473
+ "plugin.settingsOpen": "Open plugin settings",
468
474
  "trend.title": "Context Trend",
469
475
  "gran.step": "Step",
470
476
  "gran.turn": "Turn",
@@ -736,9 +742,15 @@ window.__ModuleLoader__.load({
736
742
  "ov.heat.sub": "Filter by date",
737
743
  "ov.heat.empty": "No activity yet — daily usage appears once sessions make model requests",
738
744
  "ov.heat.sessions": "{n} active sessions",
739
- "ov.heat.wd.1": "M",
740
- "ov.heat.wd.3": "W",
741
- "ov.heat.wd.5": "F",
745
+ "ov.heat.less": "Less",
746
+ "ov.heat.more": "More",
747
+ "ov.heat.metric": "Metric",
748
+ "ov.heat.metric.sessions": "Sessions",
749
+ "ov.heat.metric.steps": "Steps",
750
+ "ov.heat.steps": "{n} steps",
751
+ "ov.heat.wd.1": "Mon",
752
+ "ov.heat.wd.3": "Wed",
753
+ "ov.heat.wd.5": "Fri",
742
754
  "ov.heat.mon.01": "Jan",
743
755
  "ov.heat.mon.02": "Feb",
744
756
  "ov.heat.mon.03": "Mar",
@@ -752,7 +764,7 @@ window.__ModuleLoader__.load({
752
764
  "ov.heat.mon.11": "Nov",
753
765
  "ov.heat.mon.12": "Dec",
754
766
  "ov.list.title": "Sessions",
755
- "ov.list.search": "Search title or path…",
767
+ "ov.list.search": "Search title / path / last message…",
756
768
  "ov.list.sortLabel": "Sort",
757
769
  "ov.list.sort.recent": "Last updated",
758
770
  "ov.list.sort.tokens": "Total Tokens",
@@ -2033,12 +2045,11 @@ window.__ModuleLoader__.load({
2033
2045
  }
2034
2046
  /**
2035
2047
  * Map one raw durable event into the epoch content the browser renders. A
2036
- * `request/header` yields the full system prompt text (V0/V2 envelope) plus
2037
- * each tool's producer description and raw schema; a V3 `system/message`
2038
- * yields the prompt text alone (its tools live in the request header). Both
2039
- * mirror the host fold's per-entry guards — a null or primitive tool entry
2040
- * degrades to an unnamed row instead of throwing the read. Null when the
2041
- * envelope carries neither.
2048
+ * `request/header` yields each tool's producer description and raw schema; a
2049
+ * `system/message` yields the prompt text alone (its tools live in the
2050
+ * request header). Both mirror the host fold's per-entry guards — a null or
2051
+ * primitive tool entry degrades to an unnamed row instead of throwing the
2052
+ * read. Null when the event carries neither.
2042
2053
  */
2043
2054
  function headerContentOf(event) {
2044
2055
  const { type, data } = event;
@@ -2061,18 +2072,15 @@ window.__ModuleLoader__.load({
2061
2072
  schema: t
2062
2073
  });
2063
2074
  }
2064
- return {
2065
- ...typeof rawHeader.system === "string" && rawHeader.system !== "" ? { system: rawHeader.system } : {},
2066
- tools
2067
- };
2075
+ return { tools };
2068
2076
  }
2069
2077
  /**
2070
2078
  * The on-demand CONTENT fetch for the browser's System and Tools sections —
2071
2079
  * the lazy counterpart of the node fetcher above. One seq-anchored history
2072
2080
  * read off the requested seq returns the page holding that event (non-message
2073
2081
  * events ride the page verbatim); a `request/header` maps to the epoch's
2074
- * tools (and its V0/V2 system text), a `system/message` to a V3 prompt's
2075
- * text. Landed content caches per seq (history is immutable), and OLDER
2082
+ * tools, a `system/message` to the prompt's text. Landed content caches per
2083
+ * seq (history is immutable), and OLDER
2076
2084
  * epochs sharing the page cache for free — stepping back through epochs walks
2077
2085
  * the same pages. Undefined when no history face exists — the browser keeps a
2078
2086
  * metadata-only degradation instead.
@@ -2374,8 +2382,9 @@ window.__ModuleLoader__.load({
2374
2382
  * node at or before it carrying tokens, which is exactly the host fold's
2375
2383
  * "last nonempty surviving system" rule and therefore agrees with the
2376
2384
  * per-step `system` figure the fold recorded. Rows folded before `systems`
2377
- * existed carry none; the header epoch's envelope figure stands in for them
2378
- * (the pre-V3 wire shape).
2385
+ * existed carry none; the header epoch's own figure stands in for them (the
2386
+ * legacy wire shape older plugin builds served — current epochs fold
2387
+ * metadata-only, so the fallback only ever fires on those cached rows).
2379
2388
  */
2380
2389
  function systemAt(data, header, seq) {
2381
2390
  const systems = data.systems;
@@ -6094,8 +6103,8 @@ window.__ModuleLoader__.load({
6094
6103
  /**
6095
6104
  * The panel's row pipeline: range (by last-activity), then the heatmap's
6096
6105
  * picked day (sessions contributing to that day's merged ledger), then the
6097
- * search box (title or directory substring). Each stage keeps the rows it
6098
- * cannot prove out of the result — never an exception.
6106
+ * search box (title, directory, or last-message substring). Each stage keeps
6107
+ * the rows it cannot prove out of the result — never an exception.
6099
6108
  */
6100
6109
  function filterRows(rows, opts, now) {
6101
6110
  const start = rangeStartOf(opts.range, now);
@@ -6109,7 +6118,9 @@ window.__ModuleLoader__.load({
6109
6118
  if (query !== "") {
6110
6119
  const inTitle = row.title.toLowerCase().includes(query);
6111
6120
  const inCwd = row.cwd !== void 0 && row.cwd.toLowerCase().includes(query);
6112
- if (!inTitle && !inCwd) return false;
6121
+ const lastUser = row.timeline?.lastUser;
6122
+ const inLastUser = typeof lastUser === "string" && lastUser.toLowerCase().includes(query);
6123
+ if (!inTitle && !inCwd && !inLastUser) return false;
6113
6124
  }
6114
6125
  return true;
6115
6126
  });
@@ -6290,6 +6301,114 @@ window.__ModuleLoader__.load({
6290
6301
  return t("ov.time.d", { n: Math.floor(hours / 24) });
6291
6302
  }
6292
6303
  //#endregion
6304
+ //#region src/client/settingsJump.ts
6305
+ /**
6306
+ * Best-effort jump to this plugin's preferences. Two generations of chrome:
6307
+ * - dsh 0.1.7+ (Config-form generation): the preferences live on the
6308
+ * bundle's page of the Plugins main panel — the jump clicks the panel's
6309
+ * sidebar entry (its shipped aria-label), then follows the page with a
6310
+ * bounded poll for the bundle card's open control, found by the shipped,
6311
+ * locale-independent `data-plugin-package` list identity: the card lists
6312
+ * once the page's package load settles, and inside it the one button
6313
+ * that is not the enable switch is the title that opens the page. A
6314
+ * poll that never finds the card (still loading, plugin absent, or the
6315
+ * page already open on the detail view — the list unmounts there)
6316
+ * degrades to the card list, and every step stays silent.
6317
+ * - older lines: Settings → Plugins → Plugin configuration — the settings
6318
+ * panel keeps its open state inside the shell component (no plugin-facing
6319
+ * open face exists), so the jump drives the real chrome: click the
6320
+ * sidebar's settings trigger, then the Plugins section nav row, both
6321
+ * found by their shipped attributes and labels.
6322
+ * The last leg — the card itself — is ours: the module also carries a
6323
+ * short-lived in-bundle expand request that the settings-section card
6324
+ * consumes on mount, so that jump lands on the configuration already open.
6325
+ * EVERY step is individually guarded: a shell that doesn't match (different
6326
+ * layout, missing sidebar) degrades the whole jump to a silent no-op — this
6327
+ * path must never throw into the caller's render.
6328
+ */
6329
+ let requestedAt = 0;
6330
+ /** Raise a short-lived request for the plugin's settings card to mount expanded. */
6331
+ function requestCardExpand(now = Date.now()) {
6332
+ requestedAt = now;
6333
+ }
6334
+ /** Consume the request once; true only while it is still fresh (younger than maxAgeMs). */
6335
+ function consumeCardExpand(now = Date.now(), maxAgeMs = 5e3) {
6336
+ const fresh = requestedAt > 0 && now - requestedAt < maxAgeMs;
6337
+ requestedAt = 0;
6338
+ return fresh;
6339
+ }
6340
+ /**
6341
+ * The shipped Plugins label in both locales — the main-panel entry's
6342
+ * aria-label and the settings section's nav row text are the same word.
6343
+ */
6344
+ const PLUGIN_LABELS = /* @__PURE__ */ new Set(["Plugins", "插件"]);
6345
+ /** The bundle card's shipped list identity (locale-independent). */
6346
+ const PACKAGE_KEY = "dsh-context";
6347
+ /** How long the card poll follows the panel: 40 ticks at the 100ms tick, enough for the page's package load. */
6348
+ const POLL_TICKS = 40;
6349
+ /** Buttons the jump may operate on, in document order. */
6350
+ function buttonsOf(doc) {
6351
+ return [...doc.querySelectorAll("button")];
6352
+ }
6353
+ /** The Plugins main-panel entry, matched by its shipped aria-label. */
6354
+ function findPanelEntry(doc) {
6355
+ return buttonsOf(doc).find((b) => PLUGIN_LABELS.has(b.getAttribute("aria-label") ?? ""));
6356
+ }
6357
+ /**
6358
+ * The bundle card's open control: the one button inside the card that is not
6359
+ * the enable switch (the primitives switch carries `role="switch"`); the
6360
+ * title button's own aria-label is localized.
6361
+ */
6362
+ function findCardOpenControl(doc) {
6363
+ const card = doc.querySelector(`[data-plugin-package="${PACKAGE_KEY}"]`);
6364
+ if (card === null) return void 0;
6365
+ const open = [...card.querySelectorAll("button")].filter((b) => b.getAttribute("role") !== "switch");
6366
+ return open.length === 1 ? open[0] : void 0;
6367
+ }
6368
+ /** The sidebar's settings triggers: dialog semantics plus an expanded flag. */
6369
+ function findTriggers(doc) {
6370
+ return buttonsOf(doc).filter((b) => b.getAttribute("aria-haspopup") === "dialog" && b.hasAttribute("aria-expanded"));
6371
+ }
6372
+ /** The Plugins section's nav row, matched by its shipped label text. */
6373
+ function findSectionRow(doc) {
6374
+ return buttonsOf(doc).find((b) => PLUGIN_LABELS.has(b.textContent.trim()));
6375
+ }
6376
+ function openPluginSettings(doc = document, schedule = (run, ms) => {
6377
+ window.setTimeout(run, ms);
6378
+ }) {
6379
+ try {
6380
+ const panel = findPanelEntry(doc);
6381
+ if (panel !== void 0) {
6382
+ panel.click();
6383
+ const poll = (left) => {
6384
+ try {
6385
+ const open = findCardOpenControl(doc);
6386
+ if (open !== void 0) {
6387
+ open.click();
6388
+ return;
6389
+ }
6390
+ } catch {}
6391
+ if (left > 0) schedule(() => {
6392
+ poll(left - 1);
6393
+ }, 100);
6394
+ };
6395
+ schedule(() => {
6396
+ poll(POLL_TICKS);
6397
+ }, 200);
6398
+ return;
6399
+ }
6400
+ const triggers = findTriggers(doc);
6401
+ if (triggers.find((b) => b.getAttribute("aria-expanded") === "true") === void 0 && triggers.length === 0) return;
6402
+ triggers.find((b) => b.getAttribute("aria-expanded") !== "true")?.click();
6403
+ requestCardExpand();
6404
+ schedule(() => {
6405
+ try {
6406
+ findSectionRow(doc)?.click();
6407
+ } catch {}
6408
+ }, 80);
6409
+ } catch {}
6410
+ }
6411
+ //#endregion
6293
6412
  //#region src/client/balance.ts
6294
6413
  const BALANCE_ROUTE = "/api/dsh-context/balance";
6295
6414
  /** Where the last live figure is remembered across opens, per browser. */
@@ -6520,51 +6639,57 @@ window.__ModuleLoader__.load({
6520
6639
  date.setDate(date.getDate() + delta);
6521
6640
  return dayKeyOf(date.getTime());
6522
6641
  }
6523
- /** The Monday (local) of the week containing `key` — the heatmap's column anchor. */
6524
- function mondayOfWeek(key) {
6642
+ /** The Sunday (local) of the week containing `key` — the heatmap's column anchor. */
6643
+ function sundayOfWeek(key) {
6525
6644
  if (!DAY_KEY_RE.test(key)) return null;
6526
6645
  const y = Number(key.slice(0, 4));
6527
6646
  const m = Number(key.slice(5, 7));
6528
6647
  const d = Number(key.slice(8, 10));
6529
6648
  const date = new Date(y, m - 1, d);
6530
6649
  if (date.getFullYear() !== y || date.getMonth() !== m - 1 || date.getDate() !== d) return null;
6531
- return shiftDayKey(key, -((date.getDay() + 6) % 7));
6650
+ return shiftDayKey(key, -date.getDay());
6532
6651
  }
6533
6652
  //#endregion
6534
6653
  //#region src/client/components/heatmap.tsx
6535
6654
  /**
6536
6655
  * The Context Dashboard's activity heatmap: a GitHub-style contribution grid
6537
- * (weeks as columns, Monday-first weekdays as rows, a month label over the
6538
- * column where each month begins) over the merged daily
6539
- * ledger (overview.ts). Cell depth is the day's billed-token share of the
6540
- * window's maximum, in four steps; a day with data is a button whose click
6656
+ * (weeks as columns, Sunday-first weekdays as rows, a month label over each
6657
+ * column where a month begins — the window's opening column always labeled —
6658
+ * and a Less→More key for the depth steps) over the merged daily
6659
+ * ledger (overview.ts). Cell depth is the selected metric's share of the
6660
+ * window's maximum — distinct active sessions or settlement steps; a session
6661
+ * can spread its steps thinly across many days while another day stacks a
6662
+ * run, so each metric scales on its OWN maximum — in four steps; a day with
6663
+ * data is a button whose click
6541
6664
  * pins the session list to that day (click again to release). Cells tip
6542
6665
  * through the harness's own Tooltip primitive (instant on hover; native
6543
- * `title` lags a second behind), the bubble carrying the date and the day's
6544
- * active sessions. The grid is computed from the injected `today` key, so
6666
+ * `title` lags a second behind), the bubble carrying the date, the day's
6667
+ * active sessions, and its steps. The grid is computed from the injected
6668
+ * `today` key, so
6545
6669
  * the layout is deterministic in tests and follows the browser's local
6546
6670
  * calendar at runtime.
6547
6671
  */
6548
6672
  /**
6549
6673
  * Lay out the grid: `weeks` columns ending at today's week, each seven
6550
- * Monday-first cells. Returns null when `today` (or its week math) fails —
6551
- * a corrupt injected key degrades the card to its empty note.
6674
+ * Sunday-first cells (row 0 = Sunday). Returns null when `today` (or its
6675
+ * week math) fails — a corrupt injected key degrades the card to its empty
6676
+ * note.
6552
6677
  */
6553
6678
  function gridOf(today, weeks) {
6554
- const lastMonday = mondayOfWeek(today);
6555
- if (lastMonday === null || weeks < 1) return null;
6556
- const firstMonday = shiftDayKey(lastMonday, -7 * (weeks - 1));
6557
- if (firstMonday === null) return null;
6679
+ const lastSunday = sundayOfWeek(today);
6680
+ if (lastSunday === null || weeks < 1) return null;
6681
+ const firstSunday = shiftDayKey(lastSunday, -7 * (weeks - 1));
6682
+ if (firstSunday === null) return null;
6558
6683
  const columns = [];
6559
6684
  for (let w = 0; w < weeks; w++) {
6560
- const monday = shiftDayKey(firstMonday, 7 * w);
6561
- /* v8 ignore next -- monday is bounded by firstMonday and lastMonday (both
6685
+ const sunday = shiftDayKey(firstSunday, 7 * w);
6686
+ /* v8 ignore next -- sunday is bounded by firstSunday and lastSunday (both
6562
6687
  * proven valid), so it can never leave the representable range; kept as a
6563
6688
  * guard so a future shiftDayKey change cannot leak a null into the grid. */
6564
- if (monday === null) return null;
6689
+ if (sunday === null) return null;
6565
6690
  const column = [];
6566
6691
  for (let d = 0; d < 7; d++) {
6567
- const key = shiftDayKey(monday, d);
6692
+ const key = shiftDayKey(sunday, d);
6568
6693
  if (key === null) return null;
6569
6694
  column.push({
6570
6695
  key,
@@ -6589,88 +6714,116 @@ window.__ModuleLoader__.load({
6589
6714
  const { t } = kit;
6590
6715
  return function Heatmap(props) {
6591
6716
  const weeks = props.weeks ?? 8;
6717
+ const metric = props.metric ?? "steps";
6592
6718
  const columns = gridOf(props.today, weeks);
6593
6719
  if (columns === null) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6594
6720
  className: "lc-empty",
6595
6721
  children: t("ov.heat.empty")
6596
6722
  });
6597
6723
  const byKey = props.days;
6598
- let max = 0;
6724
+ let maxSessions = 0;
6725
+ let maxSteps = 0;
6599
6726
  let any = false;
6600
6727
  for (const column of columns) for (const cell of column) {
6601
6728
  const entry = byKey[cell.key];
6602
6729
  if (entry === void 0 || entry.tokens <= 0 && entry.requests <= 0) continue;
6603
6730
  cell.entry = entry;
6604
6731
  any = true;
6605
- if (entry.tokens > max) max = entry.tokens;
6732
+ if (entry.sessions > maxSessions) maxSessions = entry.sessions;
6733
+ if (entry.requests > maxSteps) maxSteps = entry.requests;
6606
6734
  }
6607
6735
  if (!any) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6608
6736
  className: "lc-empty",
6609
6737
  children: t("ov.heat.empty")
6610
6738
  });
6611
- const weekdayLabels = [
6612
- t("ov.heat.wd.1"),
6613
- t("ov.heat.wd.3"),
6614
- t("ov.heat.wd.5")
6615
- ];
6739
+ const max = metric === "sessions" ? maxSessions : maxSteps;
6740
+ const metricValueOf = (entry) => metric === "sessions" ? entry.sessions : entry.requests;
6741
+ const weekdayLabels = {
6742
+ 1: t("ov.heat.wd.1"),
6743
+ 3: t("ov.heat.wd.3"),
6744
+ 5: t("ov.heat.wd.5")
6745
+ };
6616
6746
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6617
- className: "lc-heat",
6618
- role: "group",
6619
- "aria-label": t("ov.heat.title"),
6620
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6621
- className: "lc-heat-wds",
6747
+ className: "lc-heat-wrap",
6748
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6749
+ className: "lc-heat",
6750
+ role: "group",
6751
+ "aria-label": t("ov.heat.title"),
6752
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6753
+ className: "lc-heat-wds",
6754
+ "aria-hidden": "true",
6755
+ children: [
6756
+ 0,
6757
+ 1,
6758
+ 2,
6759
+ 3,
6760
+ 4,
6761
+ 5,
6762
+ 6
6763
+ ].map((row) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6764
+ className: "lc-heat-wd",
6765
+ children: weekdayLabels[row] ?? ""
6766
+ }, row))
6767
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6768
+ className: "lc-heat-cols",
6769
+ children: columns.map((column, wi) => {
6770
+ const opens = wi === 0 || column[0].key.slice(0, 7) !== column[6].key.slice(0, 7) || column[0].key.slice(8, 10) === "01";
6771
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6772
+ className: "lc-heat-col",
6773
+ children: [opens && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6774
+ className: "lc-heat-mon",
6775
+ "aria-hidden": "true",
6776
+ children: t("ov.heat.mon." + column[6].key.slice(5, 7))
6777
+ }), column.map((cell) => {
6778
+ if (cell.future) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6779
+ className: "lc-heat-cell lc-heat-future",
6780
+ "aria-hidden": "true"
6781
+ }, cell.key);
6782
+ const level = cell.entry === void 0 ? 0 : levelOf(metricValueOf(cell.entry), max);
6783
+ if (cell.entry === void 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
6784
+ label: cell.key,
6785
+ side: "top",
6786
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: "lc-heat-cell lc-heat-0" })
6787
+ }, cell.key);
6788
+ const picked = props.selected === cell.key;
6789
+ const label = `${cell.key}\n${t("ov.heat.sessions", { n: cell.entry.sessions })}\n${t("ov.heat.steps", { n: cell.entry.requests })}`;
6790
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
6791
+ label,
6792
+ side: "top",
6793
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6794
+ type: "button",
6795
+ className: `lc-heat-cell lc-heat-${String(level)}${picked ? " lc-heat-on" : ""}`,
6796
+ "aria-label": label,
6797
+ "aria-pressed": picked,
6798
+ onClick: () => {
6799
+ if (props.onSelect !== void 0) props.onSelect(picked ? null : cell.key);
6800
+ }
6801
+ })
6802
+ }, cell.key);
6803
+ })]
6804
+ }, wi);
6805
+ })
6806
+ })]
6807
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6808
+ className: "lc-heat-legend",
6622
6809
  "aria-hidden": "true",
6623
6810
  children: [
6624
- 0,
6625
- 1,
6626
- 2,
6627
- 3,
6628
- 4,
6629
- 5,
6630
- 6
6631
- ].map((row) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6632
- className: "lc-heat-wd",
6633
- children: row === 1 ? weekdayLabels[0] : row === 3 ? weekdayLabels[1] : row === 5 ? weekdayLabels[2] : ""
6634
- }, row))
6635
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6636
- className: "lc-heat-cols",
6637
- children: columns.map((column, wi) => {
6638
- const opens = column[0].key.slice(0, 7) !== column[6].key.slice(0, 7) || column[0].key.slice(8, 10) === "01";
6639
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6640
- className: "lc-heat-col",
6641
- children: [opens && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6642
- className: "lc-heat-mon",
6643
- "aria-hidden": "true",
6644
- children: t("ov.heat.mon." + column[6].key.slice(5, 7))
6645
- }), column.map((cell) => {
6646
- if (cell.future) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6647
- className: "lc-heat-cell lc-heat-future",
6648
- "aria-hidden": "true"
6649
- }, cell.key);
6650
- const level = cell.entry === void 0 ? 0 : levelOf(cell.entry.tokens, max);
6651
- if (cell.entry === void 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
6652
- label: cell.key,
6653
- side: "top",
6654
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: "lc-heat-cell lc-heat-0" })
6655
- }, cell.key);
6656
- const picked = props.selected === cell.key;
6657
- const label = `${cell.key}\n${t("ov.heat.sessions", { n: cell.entry.sessions })}`;
6658
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
6659
- label,
6660
- side: "top",
6661
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6662
- type: "button",
6663
- className: `lc-heat-cell lc-heat-${String(level)}${picked ? " lc-heat-on" : ""}`,
6664
- "aria-label": label,
6665
- "aria-pressed": picked,
6666
- onClick: () => {
6667
- if (props.onSelect !== void 0) props.onSelect(picked ? null : cell.key);
6668
- }
6669
- })
6670
- }, cell.key);
6671
- })]
6672
- }, wi);
6673
- })
6811
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6812
+ className: "lc-heat-key",
6813
+ children: t("ov.heat.less")
6814
+ }),
6815
+ [
6816
+ 0,
6817
+ 1,
6818
+ 2,
6819
+ 3,
6820
+ 4
6821
+ ].map((level) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: `lc-heat-cell lc-heat-${String(level)}` }, level)),
6822
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6823
+ className: "lc-heat-key",
6824
+ children: t("ov.heat.more")
6825
+ })
6826
+ ]
6674
6827
  })]
6675
6828
  });
6676
6829
  };
@@ -6917,11 +7070,11 @@ window.__ModuleLoader__.load({
6917
7070
  * opening one log.
6918
7071
  *
6919
7072
  * The body is a 3:7 column pair: the insight column (the KPI 2×3 block over
6920
- * the activity heatmap) beside the session column (search, group chips, and
6921
- * the card grid); the heatmap keeps its own fixed 8-week window and PINs the
6922
- * list to a picked day (the panel's drill-down gesture). A session card
6923
- * click jumps to that session through the harness's own `sessions.open` and
6924
- * closes the panel.
7073
+ * the activity heatmap, then the preferences entry row) beside the session
7074
+ * column (search, group chips, and the card grid); the heatmap keeps its own
7075
+ * fixed 8-week window and PINs the list to a picked day (the panel's
7076
+ * drill-down gesture). A session card click jumps to that session through
7077
+ * the harness's own `sessions.open` and closes the panel.
6925
7078
  */
6926
7079
  const RANGES = [
6927
7080
  "24h",
@@ -6934,6 +7087,8 @@ window.__ModuleLoader__.load({
6934
7087
  "tokens",
6935
7088
  "context"
6936
7089
  ];
7090
+ /** The heatmap's depth metrics, in toggle order (steps is the default). */
7091
+ const METRICS = ["sessions", "steps"];
6937
7092
  function makeOverviewPanel(ctx, kit) {
6938
7093
  const { t, fmtDuration } = kit;
6939
7094
  const Heatmap = makeHeatmap(kit);
@@ -6955,6 +7110,7 @@ window.__ModuleLoader__.load({
6955
7110
  const [query, setQuery] = (0, react.useState)("");
6956
7111
  const [group, setGroup] = (0, react.useState)(null);
6957
7112
  const [sort, setSort] = (0, react.useState)("recent");
7113
+ const [metric, setMetric] = (0, react.useState)("steps");
6958
7114
  const [page, setPage] = (0, react.useState)(0);
6959
7115
  const close = () => {
6960
7116
  overviewStore.set(false);
@@ -7052,134 +7208,168 @@ window.__ModuleLoader__.load({
7052
7208
  className: "lc-ov-body",
7053
7209
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7054
7210
  className: "lc-ov-left",
7055
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7056
- className: "lc-ov-kpis",
7057
- children: [
7058
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7059
- className: "lc-stat lc-ov-kpi",
7060
- children: [
7061
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7062
- className: "lc-stat-label",
7063
- children: t("ov.kpi.sessions")
7064
- }),
7065
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7066
- className: "lc-stat-value",
7067
- children: kpi.sessions
7068
- }),
7069
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7070
- className: "lc-stat-sub",
7071
- children: t("ov.kpi.ofTotal", { n: kpi.listed })
7072
- })
7073
- ]
7074
- }),
7075
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7076
- className: "lc-stat lc-ov-kpi",
7077
- children: [
7078
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7079
- className: "lc-stat-label",
7080
- children: t("ov.kpi.tokens")
7081
- }),
7082
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7083
- className: "lc-stat-value",
7084
- children: fmt(kpi.tokens)
7085
- }),
7086
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
7087
- className: "lc-stat-sub",
7088
- children: [
7089
- t("stats.turns"),
7090
- " ",
7091
- fmt(kpi.turns)
7092
- ]
7093
- })
7094
- ]
7095
- }),
7096
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7097
- className: "lc-stat lc-ov-kpi",
7098
- children: [
7099
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7100
- className: "lc-stat-label",
7101
- children: t("stats.cost")
7102
- }),
7103
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7104
- className: "lc-stat-value",
7105
- children: kpi.cost === null ? "—" : formatCost(kpi.cost, currency)
7106
- }),
7107
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7108
- className: "lc-stat-sub",
7109
- children: t("ov.kpi.sessionsSub", { n: kpi.costSessions })
7110
- })
7111
- ]
7112
- }),
7113
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7114
- className: "lc-stat lc-ov-kpi",
7115
- children: [
7116
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7117
- className: "lc-stat-label",
7118
- children: t("stats.cacheHit")
7119
- }),
7120
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7121
- className: "lc-stat-value",
7122
- children: kpi.cacheHit === null ? "—" : kpi.cacheHit + "%"
7123
- }),
7124
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7125
- className: "lc-stat-sub",
7126
- children: t("ov.kpi.sessionsSub", { n: kpi.usageSessions })
7127
- })
7128
- ]
7129
- }),
7130
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7131
- className: "lc-stat lc-ov-kpi",
7132
- children: [
7133
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7134
- className: "lc-stat-label",
7135
- children: t("stats.toolCalls")
7136
- }),
7137
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7138
- className: "lc-stat-value",
7139
- children: fmt(kpi.toolCalls)
7140
- }),
7141
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7142
- className: "lc-stat-sub",
7143
- children: t("ov.kpi.toolSub", { dur: fmtDuration(kpi.toolsMs) })
7144
- })
7145
- ]
7146
- }),
7147
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7148
- className: "lc-stat lc-ov-kpi",
7149
- children: [
7150
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7151
- className: "lc-stat-label",
7152
- children: t("timing.total")
7153
- }),
7154
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7155
- className: "lc-stat-value",
7156
- children: fmtDuration(kpi.wallMs)
7157
- }),
7158
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7159
- className: "lc-stat-sub",
7160
- children: t("ov.kpi.wallSub", { n: fmt(kpi.calls) })
7161
- })
7162
- ]
7163
- })
7164
- ]
7165
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7166
- className: "lc-card lc-ov-heat-card",
7167
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7168
- className: "lc-card-title",
7169
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7170
- className: "lc-card-title-text",
7171
- children: t("ov.heat.title")
7211
+ children: [
7212
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7213
+ className: "lc-ov-kpis",
7214
+ children: [
7215
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7216
+ className: "lc-stat lc-ov-kpi",
7217
+ children: [
7218
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7219
+ className: "lc-stat-label",
7220
+ children: t("ov.kpi.sessions")
7221
+ }),
7222
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7223
+ className: "lc-stat-value",
7224
+ children: kpi.sessions
7225
+ }),
7226
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7227
+ className: "lc-stat-sub",
7228
+ children: t("ov.kpi.ofTotal", { n: kpi.listed })
7229
+ })
7230
+ ]
7231
+ }),
7232
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7233
+ className: "lc-stat lc-ov-kpi",
7234
+ children: [
7235
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7236
+ className: "lc-stat-label",
7237
+ children: t("ov.kpi.tokens")
7238
+ }),
7239
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7240
+ className: "lc-stat-value",
7241
+ children: fmt(kpi.tokens)
7242
+ }),
7243
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
7244
+ className: "lc-stat-sub",
7245
+ children: [
7246
+ t("stats.turns"),
7247
+ " ",
7248
+ fmt(kpi.turns)
7249
+ ]
7250
+ })
7251
+ ]
7252
+ }),
7253
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7254
+ className: "lc-stat lc-ov-kpi",
7255
+ children: [
7256
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7257
+ className: "lc-stat-label",
7258
+ children: t("stats.cost")
7259
+ }),
7260
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7261
+ className: "lc-stat-value",
7262
+ children: kpi.cost === null ? "—" : formatCost(kpi.cost, currency)
7263
+ }),
7264
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7265
+ className: "lc-stat-sub",
7266
+ children: t("ov.kpi.sessionsSub", { n: kpi.costSessions })
7267
+ })
7268
+ ]
7269
+ }),
7270
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7271
+ className: "lc-stat lc-ov-kpi",
7272
+ children: [
7273
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7274
+ className: "lc-stat-label",
7275
+ children: t("stats.cacheHit")
7276
+ }),
7277
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7278
+ className: "lc-stat-value",
7279
+ children: kpi.cacheHit === null ? "—" : kpi.cacheHit + "%"
7280
+ }),
7281
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7282
+ className: "lc-stat-sub",
7283
+ children: t("ov.kpi.sessionsSub", { n: kpi.usageSessions })
7284
+ })
7285
+ ]
7286
+ }),
7287
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7288
+ className: "lc-stat lc-ov-kpi",
7289
+ children: [
7290
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7291
+ className: "lc-stat-label",
7292
+ children: t("stats.toolCalls")
7293
+ }),
7294
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7295
+ className: "lc-stat-value",
7296
+ children: fmt(kpi.toolCalls)
7297
+ }),
7298
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7299
+ className: "lc-stat-sub",
7300
+ children: t("ov.kpi.toolSub", { dur: fmtDuration(kpi.toolsMs) })
7301
+ })
7302
+ ]
7303
+ }),
7304
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7305
+ className: "lc-stat lc-ov-kpi",
7306
+ children: [
7307
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7308
+ className: "lc-stat-label",
7309
+ children: t("timing.total")
7310
+ }),
7311
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7312
+ className: "lc-stat-value",
7313
+ children: fmtDuration(kpi.wallMs)
7314
+ }),
7315
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7316
+ className: "lc-stat-sub",
7317
+ children: t("ov.kpi.wallSub", { n: fmt(kpi.calls) })
7318
+ })
7319
+ ]
7320
+ })
7321
+ ]
7322
+ }),
7323
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7324
+ className: "lc-card lc-ov-heat-card",
7325
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7326
+ className: "lc-card-title",
7327
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7328
+ className: "lc-card-title-text",
7329
+ children: t("ov.heat.title")
7330
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
7331
+ className: "lc-heat-ctl",
7332
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7333
+ className: "lc-card-sub",
7334
+ children: t("ov.heat.sub")
7335
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7336
+ className: "lc-gran",
7337
+ role: "group",
7338
+ "aria-label": t("ov.heat.metric"),
7339
+ children: METRICS.map((m) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
7340
+ type: "button",
7341
+ className: "lc-gran-btn" + (metric === m ? " lc-gran-on" : ""),
7342
+ onClick: () => {
7343
+ setMetric(m);
7344
+ },
7345
+ children: t("ov.heat.metric." + m)
7346
+ }, m))
7347
+ })]
7348
+ })]
7349
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Heatmap, {
7350
+ days,
7351
+ metric,
7352
+ selected: day,
7353
+ onSelect: setDay,
7354
+ today: todayKey()
7355
+ })]
7356
+ }),
7357
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
7358
+ type: "button",
7359
+ className: "lc-ov-settings",
7360
+ onClick: () => {
7361
+ openPluginSettings();
7362
+ close();
7363
+ },
7364
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
7365
+ className: "lc-ov-settings-label",
7366
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconSettings, { size: 14 }), t("plugin.settings")]
7172
7367
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7173
- className: "lc-card-sub",
7174
- children: t("ov.heat.sub")
7368
+ className: "lc-ov-settings-hint",
7369
+ children: t("plugin.settingsOpen")
7175
7370
  })]
7176
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Heatmap, {
7177
- days,
7178
- selected: day,
7179
- onSelect: setDay,
7180
- today: todayKey()
7181
- })]
7182
- })]
7371
+ })
7372
+ ]
7183
7373
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7184
7374
  className: "lc-ov-right",
7185
7375
  children: [
@@ -7317,114 +7507,6 @@ window.__ModuleLoader__.load({
7317
7507
  return cost === null ? "—" : formatCost(cost, currency);
7318
7508
  }
7319
7509
  //#endregion
7320
- //#region src/client/settingsJump.ts
7321
- /**
7322
- * Best-effort jump to this plugin's preferences. Two generations of chrome:
7323
- * - dsh 0.1.7+ (Config-form generation): the preferences live on the
7324
- * bundle's page of the Plugins main panel — the jump clicks the panel's
7325
- * sidebar entry (its shipped aria-label), then follows the page with a
7326
- * bounded poll for the bundle card's open control, found by the shipped,
7327
- * locale-independent `data-plugin-package` list identity: the card lists
7328
- * once the page's package load settles, and inside it the one button
7329
- * that is not the enable switch is the title that opens the page. A
7330
- * poll that never finds the card (still loading, plugin absent, or the
7331
- * page already open on the detail view — the list unmounts there)
7332
- * degrades to the card list, and every step stays silent.
7333
- * - older lines: Settings → Plugins → Plugin configuration — the settings
7334
- * panel keeps its open state inside the shell component (no plugin-facing
7335
- * open face exists), so the jump drives the real chrome: click the
7336
- * sidebar's settings trigger, then the Plugins section nav row, both
7337
- * found by their shipped attributes and labels.
7338
- * The last leg — the card itself — is ours: the module also carries a
7339
- * short-lived in-bundle expand request that the settings-section card
7340
- * consumes on mount, so that jump lands on the configuration already open.
7341
- * EVERY step is individually guarded: a shell that doesn't match (different
7342
- * layout, missing sidebar) degrades the whole jump to a silent no-op — this
7343
- * path must never throw into the caller's render.
7344
- */
7345
- let requestedAt = 0;
7346
- /** Raise a short-lived request for the plugin's settings card to mount expanded. */
7347
- function requestCardExpand(now = Date.now()) {
7348
- requestedAt = now;
7349
- }
7350
- /** Consume the request once; true only while it is still fresh (younger than maxAgeMs). */
7351
- function consumeCardExpand(now = Date.now(), maxAgeMs = 5e3) {
7352
- const fresh = requestedAt > 0 && now - requestedAt < maxAgeMs;
7353
- requestedAt = 0;
7354
- return fresh;
7355
- }
7356
- /**
7357
- * The shipped Plugins label in both locales — the main-panel entry's
7358
- * aria-label and the settings section's nav row text are the same word.
7359
- */
7360
- const PLUGIN_LABELS = /* @__PURE__ */ new Set(["Plugins", "插件"]);
7361
- /** The bundle card's shipped list identity (locale-independent). */
7362
- const PACKAGE_KEY = "dsh-context";
7363
- /** How long the card poll follows the panel: 40 ticks at the 100ms tick, enough for the page's package load. */
7364
- const POLL_TICKS = 40;
7365
- /** Buttons the jump may operate on, in document order. */
7366
- function buttonsOf(doc) {
7367
- return [...doc.querySelectorAll("button")];
7368
- }
7369
- /** The Plugins main-panel entry, matched by its shipped aria-label. */
7370
- function findPanelEntry(doc) {
7371
- return buttonsOf(doc).find((b) => PLUGIN_LABELS.has(b.getAttribute("aria-label") ?? ""));
7372
- }
7373
- /**
7374
- * The bundle card's open control: the one button inside the card that is not
7375
- * the enable switch (the primitives switch carries `role="switch"`); the
7376
- * title button's own aria-label is localized.
7377
- */
7378
- function findCardOpenControl(doc) {
7379
- const card = doc.querySelector(`[data-plugin-package="${PACKAGE_KEY}"]`);
7380
- if (card === null) return void 0;
7381
- const open = [...card.querySelectorAll("button")].filter((b) => b.getAttribute("role") !== "switch");
7382
- return open.length === 1 ? open[0] : void 0;
7383
- }
7384
- /** The sidebar's settings triggers: dialog semantics plus an expanded flag. */
7385
- function findTriggers(doc) {
7386
- return buttonsOf(doc).filter((b) => b.getAttribute("aria-haspopup") === "dialog" && b.hasAttribute("aria-expanded"));
7387
- }
7388
- /** The Plugins section's nav row, matched by its shipped label text. */
7389
- function findSectionRow(doc) {
7390
- return buttonsOf(doc).find((b) => PLUGIN_LABELS.has(b.textContent.trim()));
7391
- }
7392
- function openPluginSettings(doc = document, schedule = (run, ms) => {
7393
- window.setTimeout(run, ms);
7394
- }) {
7395
- try {
7396
- const panel = findPanelEntry(doc);
7397
- if (panel !== void 0) {
7398
- panel.click();
7399
- const poll = (left) => {
7400
- try {
7401
- const open = findCardOpenControl(doc);
7402
- if (open !== void 0) {
7403
- open.click();
7404
- return;
7405
- }
7406
- } catch {}
7407
- if (left > 0) schedule(() => {
7408
- poll(left - 1);
7409
- }, 100);
7410
- };
7411
- schedule(() => {
7412
- poll(POLL_TICKS);
7413
- }, 200);
7414
- return;
7415
- }
7416
- const triggers = findTriggers(doc);
7417
- if (triggers.find((b) => b.getAttribute("aria-expanded") === "true") === void 0 && triggers.length === 0) return;
7418
- triggers.find((b) => b.getAttribute("aria-expanded") !== "true")?.click();
7419
- requestCardExpand();
7420
- schedule(() => {
7421
- try {
7422
- findSectionRow(doc)?.click();
7423
- } catch {}
7424
- }, 80);
7425
- } catch {}
7426
- }
7427
- //#endregion
7428
7510
  //#region src/client/components/settingsCard.tsx
7429
7511
  /**
7430
7512
  * The dsh-context preference cards — two seats over the same six rows. The
@@ -7436,7 +7518,7 @@ window.__ModuleLoader__.load({
7436
7518
  * `dsh-context` namespace and render nothing while it is unavailable (a
7437
7519
  * deployment without the Host half, or a remote browser, shows no trace).
7438
7520
  * The settings-section card mounts expanded when the Plugin Info card's
7439
- * "Open preferences" jump left a fresh expand request (settingsJump.ts),
7521
+ * "Open plugin settings" jump left a fresh expand request (settingsJump.ts),
7440
7522
  * scrolling itself into view.
7441
7523
  */
7442
7524
  function PrefRow(props) {
@@ -9904,7 +9986,7 @@ window.__ModuleLoader__.load({
9904
9986
  return function PluginInfo() {
9905
9987
  const [latest, setLatest] = (0, react.useState)(null);
9906
9988
  (0, react.useEffect)(() => {
9907
- if ("0.55.0".includes("-dev")) return;
9989
+ if ("0.56.1".includes("-dev")) return;
9908
9990
  let on = true;
9909
9991
  fetchLatestVersion().then((v) => {
9910
9992
  if (on && v) setLatest(v);
@@ -9913,8 +9995,8 @@ window.__ModuleLoader__.load({
9913
9995
  on = false;
9914
9996
  };
9915
9997
  }, []);
9916
- const update = latest !== null && isNewerVersion(latest, "0.55.0") ? latest : null;
9917
- const nameText = "dsh-context (v0.55.0)";
9998
+ const update = latest !== null && isNewerVersion(latest, "0.56.1") ? latest : null;
9999
+ const nameText = "dsh-context (v0.56.1)";
9918
10000
  const nameValue = [nameText];
9919
10001
  if (update) nameValue.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9920
10002
  className: "lc-pi-update",
@@ -11045,8 +11127,9 @@ window.__ModuleLoader__.load({
11045
11127
  * Scroll an element's nearest scrollable ancestor so the element tops that
11046
11128
  * scrollport. The jump's landing reveal needs this host-agnostic: the
11047
11129
  * conversation tab scrolls the shared `[data-conversation-scroll]` container
11048
- * while the right Sidebar scrolls dockkit's pane body (a CSS-module class,
11049
- * no stable attribute of its own), so the walk takes whichever ancestor
11130
+ * while the right Sidebar's scroller differs per generation (dockkit's pane
11131
+ * body — a CSS-module class with no stable attribute — on the 0.1.5 line, the
11132
+ * tab root itself on the 0.1.7 line), so the walk takes whichever ancestor
11050
11133
  * actually scrolls — the rect delta lands the anchor flush regardless of the
11051
11134
  * container's current position. `document.body` ends the walk: the page
11052
11135
  * itself never scrolls. False — never a throw — when no ancestor scrolls (the
@@ -11704,7 +11787,7 @@ window.__ModuleLoader__.load({
11704
11787
  }
11705
11788
  //#endregion
11706
11789
  //#region \0dsh-global-css:/home/runner/work/dsh-context/dsh-context/src/client/styles/base.css.mjs
11707
- 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{height:auto;padding:12px;overflow:visible}.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{align-items:center;gap:6px;margin-left:auto;display:flex}.lc-trend-ctl .lc-gran{margin-left:0}.lc-trend-adaptive{flex:none;margin-left:0}.lc-gran-btn{color:var(--dsw-alias-label-secondary);cursor:pointer;transition:color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);background:0 0;border:0;border-radius:5px;padding:3px 8px;font-family:inherit;font-size:11px;line-height:1}.lc-gran-btn:hover{color:var(--dsw-alias-label-primary)}.lc-gran-on,.lc-gran-on:hover{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground)}.lc-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}";
11790
+ 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-adaptive{flex:none;margin-left:0}.lc-gran-btn{color:var(--dsw-alias-label-secondary);cursor:pointer;transition:color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);background:0 0;border:0;border-radius:5px;padding:3px 8px;font-family:inherit;font-size:11px;line-height:1}.lc-gran-btn:hover{color:var(--dsw-alias-label-primary)}.lc-gran-on,.lc-gran-on:hover{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground)}.lc-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}";
11708
11791
  const tagId$14 = "dsh-context/base.css";
11709
11792
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$14) + "]") === null) {
11710
11793
  const tag = document.createElement("style");
@@ -11858,7 +11941,7 @@ window.__ModuleLoader__.load({
11858
11941
  }
11859
11942
  //#endregion
11860
11943
  //#region \0dsh-global-css:/home/runner/work/dsh-context/dsh-context/src/client/styles/overview.css.mjs
11861
- 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);max-height:min(86vh,900px);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-body{flex:auto;grid-template-columns:minmax(0,3fr) minmax(0,7fr);gap:10px;min-height:0;display:grid}.lc-ov-left{scrollbar-gutter:stable;flex-direction:column;gap:10px;min-height:0;padding-right:8px;display:flex;overflow-y:auto}.lc-ov-right{scrollbar-gutter:stable;min-height:0;padding-right:8px;overflow-y:auto}@container lc-ov (width<=932px){.lc-ov-card{overflow-y:auto}.lc-ov-body{display:block}.lc-ov-left{margin-bottom:12px}.lc-ov-left,.lc-ov-right{min-height:auto;padding-right:0;overflow:visible}.lc-ov-heat-card{flex:none}}.lc-ov-left>.lc-card{box-sizing:border-box;min-width:0;margin-bottom:0}.lc-ov-kpis{flex:none;grid-template-rows:repeat(3,1fr);grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;display:grid}.lc-ov-kpi{align-items:center;padding:10px 8px}.lc-ov-kpi .lc-stat-value{font-size:20px}.lc-ov-heat-card{flex-direction:column;flex:1 0 auto;display:flex}.lc-heat{flex:1;justify-content:center;align-items:center;gap:4px;display:flex}.lc-heat-wds,.lc-heat-col{padding-top:13px}.lc-heat-wds{flex-direction:column;gap:3px;display:flex}.lc-heat-wd{width:10px;height:20px;color:var(--dsw-alias-label-secondary);text-align:center;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:13px;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-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}";
11944
+ 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-body{flex:auto;grid-template-columns:minmax(0,3fr) minmax(0,7fr);gap:10px;min-height:0;display:grid}.lc-ov-left{scrollbar-gutter:stable;flex-direction:column;gap:10px;min-height:0;padding-right:8px;display:flex;overflow-y:auto}.lc-ov-right{scrollbar-gutter:stable;min-height:0;padding-right:8px;overflow-y:auto}@container lc-ov (width<=932px){.lc-ov-card{overflow-y:auto}.lc-ov-body{display:block}.lc-ov-left{margin-bottom:12px}.lc-ov-left,.lc-ov-right{min-height:auto;padding-right:0;overflow:visible}.lc-ov-heat-card{flex:none}}.lc-ov-left>.lc-card{box-sizing:border-box;min-width:0;margin-bottom:0}.lc-ov-kpis{flex:none;grid-template-rows:repeat(3,1fr);grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;display:grid}.lc-ov-kpi{align-items:center;padding:10px 8px}.lc-ov-kpi .lc-stat-value{font-size:20px}.lc-ov-heat-card{flex-direction:column;flex:1 0 auto;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}";
11862
11945
  const tagId = "dsh-context/overview.css";
11863
11946
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
11864
11947
  const tag = document.createElement("style");