dsh-context 0.58.0 → 0.59.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
@@ -56,15 +56,16 @@ window.__ModuleLoader__.load({
56
56
  "stats.cacheHit": "缓存命中",
57
57
  "stats.cacheHitTip": "整个会话累计的缓存读取占计费输入的比例。",
58
58
  "stats.cost": "费用",
59
- "stats.costTip": "估算当前 Agent 与其所有子 Agent 的累计费用:单价取自 models.dev 刊例价,人民币按 1 元 = 0.15 美元换算,仅供参考。",
59
+ "stats.costTip": "估算的费用,含当前智能体及所有子智能体,仅供参考。",
60
60
  "stats.costTipDeepseek": "DeepSeek 高峰时段(北京时间工作日 9:00–12:00、14:00–18:00)按挂牌价计费,其余时段半价。",
61
+ "stats.costTipCny": "人民币按 1 元 = 0.15 美元换算。",
61
62
  "stats.subCost": "子 Agent 费用",
62
63
  "stats.subCostTip": "所有子 Agent 会话各自累计费用(同口径估算)的合计,不含当前 Agent 自身。",
63
- "stats.costPriceHead": "每百万 tokens 价格:",
64
- "stats.costPriceHeadPair": "每百万 tokens 价格(高峰|空闲):",
65
- "stats.costHit": "命中",
66
- "stats.costMiss": "未命中",
67
- "stats.costWrite": "写入",
64
+ "stats.costPriceHead": "每百万 Token 价格:",
65
+ "stats.costPriceBy": "按 {p} · {m} 在 models.dev 的刊登价格如上。",
66
+ "stats.costHit": "缓存输入",
67
+ "stats.costMiss": "未缓存输入",
68
+ "stats.costWrite": "缓存写入",
68
69
  "stats.costOut": "输出",
69
70
  "stats.costUnavailable": "模型价格暂不可用(自动重试中),费用暂无法估算。",
70
71
  "timing.title": "耗时统计",
@@ -358,6 +359,11 @@ window.__ModuleLoader__.load({
358
359
  "ov.kpi.toolSub": "工具执行 {dur}",
359
360
  "ov.kpi.wallSub": "模型调用 {n}",
360
361
  "ov.stats.empty": "统计范围内暂无 Token 用量",
362
+ "ov.usage.title": "近 7 天用量",
363
+ "ov.usage.tokens": "Token",
364
+ "ov.usage.cost": "费用(仅含支持计价映射的模型)",
365
+ "ov.usage.costTip": "费用",
366
+ "ov.usage.empty": "近 7 天暂无用量 — 会话产生模型请求后,这里会显示每日 Token 与费用",
361
367
  "balance.title": "DeepSeek 余额",
362
368
  "balance.tip.granted": "赠送余额",
363
369
  "balance.tip.toppedUp": "充值余额",
@@ -437,16 +443,17 @@ window.__ModuleLoader__.load({
437
443
  "stats.cacheHit": "Cache Hit",
438
444
  "stats.cacheHitTip": "Cumulative cache-read share of billed input across the session.",
439
445
  "stats.cost": "Cost",
440
- "stats.costTip": "Estimates the cumulative cost of this agent and all its subagents: rates come from the models.dev list prices; the CNY display converts at 1 CNY = 0.15 USD. Prices are for reference only.",
446
+ "stats.costTip": "Estimated cost for this agent and all its subagents, for reference only.",
441
447
  "stats.costTipDeepseek": "DeepSeek bills peak windows (Beijing Time weekdays 09:00–12:00, 14:00–18:00) at list price; all other hours are half price.",
448
+ "stats.costTipCny": "The CNY display converts at 1 CNY = 0.15 USD.",
442
449
  "stats.subCost": "Subagent Cost",
443
450
  "stats.subCostTip": "Summed estimates of every subagent session’s own cumulative cost (same basis); the current agent is not included.",
444
451
  "stats.costPriceHead": "Per-1M-token rates:",
445
- "stats.costPriceHeadPair": "Per-1M-token rates (peak|off-peak):",
446
- "stats.costHit": "hit",
447
- "stats.costMiss": "miss",
448
- "stats.costWrite": "write",
449
- "stats.costOut": "output",
452
+ "stats.costPriceBy": "Priced as listed on models.dev for {p} · {m}.",
453
+ "stats.costHit": "Cache input",
454
+ "stats.costMiss": "Uncached input",
455
+ "stats.costWrite": "Cache write",
456
+ "stats.costOut": "Output",
450
457
  "stats.costUnavailable": "Model prices are unavailable (retrying automatically) — the cost cannot be estimated yet.",
451
458
  "timing.title": "Timing Stats",
452
459
  "timing.total": "Active Time",
@@ -739,6 +746,11 @@ window.__ModuleLoader__.load({
739
746
  "ov.kpi.toolSub": "tool runs {dur}",
740
747
  "ov.kpi.wallSub": "{n} model calls",
741
748
  "ov.stats.empty": "No billed tokens in this range",
749
+ "ov.usage.title": "Last 7 Days",
750
+ "ov.usage.tokens": "Tokens",
751
+ "ov.usage.cost": "Cost (price-mapped models only)",
752
+ "ov.usage.costTip": "Cost",
753
+ "ov.usage.empty": "No usage in the last 7 days — daily tokens and cost appear once sessions make model requests",
742
754
  "balance.title": "DeepSeek balance",
743
755
  "balance.tip.granted": "Granted balance",
744
756
  "balance.tip.toppedUp": "Topped-up balance",
@@ -1627,12 +1639,13 @@ window.__ModuleLoader__.load({
1627
1639
  }
1628
1640
  /**
1629
1641
  * Narrow a delivered `contextActivity` value (the per-day ledger the Context
1630
- * Overview's heatmap reads off each session-list row) to a render-safe shape.
1631
- * Absent or non-record stays null (an older host serves no such key — the
1632
- * heatmap renders its empty note). Per-day re-proved: a malformed key or a
1633
- * wrong-typed figure drops just that entry, a hostile day record can never
1634
- * produce a NaN cell, and a well-formed payload passes through untouched
1635
- * (reference-stable for the selector equality).
1642
+ * Overview's heatmap and usage chart read off each session-list row) to a
1643
+ * render-safe shape. Absent or non-record stays null (an older host serves no
1644
+ * such key — the heatmap renders its empty note). Per-day re-proved: a
1645
+ * malformed key or a wrong-typed figure drops just that entry, a malformed
1646
+ * pricing record drops just the fee (the day's tokens survive), a hostile day
1647
+ * record can never produce a NaN cell, and a well-formed payload passes
1648
+ * through untouched (reference-stable for the selector equality).
1636
1649
  */
1637
1650
  function activityOf$1(value) {
1638
1651
  const data = asRecord(value);
@@ -1649,9 +1662,13 @@ window.__ModuleLoader__.load({
1649
1662
  dirty = true;
1650
1663
  continue;
1651
1664
  }
1665
+ const proved = costOf(entry.cost);
1666
+ const cost = proved !== void 0 && Object.keys(proved).length > 0 ? proved : void 0;
1667
+ if (entry.cost !== void 0 && cost === void 0) dirty = true;
1652
1668
  days[key] = {
1653
1669
  tokens,
1654
- requests
1670
+ requests,
1671
+ ...cost !== void 0 ? { cost } : {}
1655
1672
  };
1656
1673
  }
1657
1674
  return dirty ? { days } : data;
@@ -5578,6 +5595,7 @@ window.__ModuleLoader__.load({
5578
5595
  const lower = mid.toLowerCase();
5579
5596
  const cand = {
5580
5597
  pid,
5598
+ mid,
5581
5599
  rate,
5582
5600
  primary
5583
5601
  };
@@ -5589,47 +5607,47 @@ window.__ModuleLoader__.load({
5589
5607
  return { byModel };
5590
5608
  }
5591
5609
  /**
5592
- * The rate shared by a candidate group, or null: the largest equal-rate
5593
- * group wins, a tie refuses. Agreeing mirrors are noise; disagreeing ones
5594
- * price nothing rather than guess.
5610
+ * The candidate carrying the rate shared by a candidate group, or null: the
5611
+ * largest equal-rate group wins, a tie refuses. Agreeing mirrors are noise;
5612
+ * disagreeing ones price nothing rather than guess.
5595
5613
  */
5596
- function majorityRate(cands) {
5614
+ function majorityCandidate(cands) {
5597
5615
  const groups = [];
5598
5616
  for (const c of cands) {
5599
- const g = groups.find((g) => sameRate(g.rate, c.rate));
5617
+ const g = groups.find((g) => sameRate(g.cand.rate, c.rate));
5600
5618
  if (g === void 0) groups.push({
5601
- rate: c.rate,
5619
+ cand: c,
5602
5620
  n: 1
5603
5621
  });
5604
5622
  else g.n++;
5605
5623
  }
5606
5624
  groups.sort((a, b) => b.n - a.n);
5607
- return groups.length > 1 && groups[0].n === groups[1].n ? null : groups[0].rate;
5625
+ return groups.length > 1 && groups[0].n === groups[1].n ? null : groups[0].cand;
5608
5626
  }
5609
5627
  /**
5610
- * Pick one candidate group's rate: the model's own vendor (unique or
5611
- * unanimous), then a provider the model id itself names (`deepseek-v4-flash`
5612
- * under `deepseek`), then a lone carrier. Everything else prices null.
5628
+ * Pick one candidate: the model's own vendor (unique or unanimous), then a
5629
+ * provider the model id itself names (`deepseek-v4-flash` under `deepseek`),
5630
+ * then a lone carrier. Everything else prices null.
5613
5631
  */
5614
5632
  function resolveCandidates(lower, cands, org) {
5615
5633
  if (org !== null) {
5616
5634
  const named = cands.filter((c) => c.pid === org || org.startsWith(c.pid + "-") || org.length >= 4 && org.startsWith(c.pid));
5617
5635
  if (named.length > 0) {
5618
- const rate = majorityRate(named);
5619
- if (rate !== null) return rate;
5636
+ const cand = majorityCandidate(named);
5637
+ if (cand !== null) return cand;
5620
5638
  }
5621
5639
  }
5622
5640
  const primaries = cands.filter((c) => c.primary);
5623
5641
  if (primaries.length > 0) {
5624
- const rate = majorityRate(primaries);
5625
- if (rate !== null) return rate;
5642
+ const cand = majorityCandidate(primaries);
5643
+ if (cand !== null) return cand;
5626
5644
  }
5627
5645
  const prefixed = cands.filter((c) => lower.startsWith(c.pid + "-") || lower.startsWith(c.pid + "/"));
5628
5646
  if (prefixed.length > 0) {
5629
- const rate = majorityRate(prefixed);
5630
- if (rate !== null) return rate;
5647
+ const cand = majorityCandidate(prefixed);
5648
+ if (cand !== null) return cand;
5631
5649
  }
5632
- return cands.length === 1 ? cands[0].rate : null;
5650
+ return cands.length === 1 ? cands[0] : null;
5633
5651
  }
5634
5652
  /**
5635
5653
  * Resolve a model id book-wide: the full id first, then its last `/`-segment
@@ -5643,34 +5661,29 @@ window.__ModuleLoader__.load({
5643
5661
  for (const key of slash > 0 ? [lower, lower.slice(slash + 1)] : [lower]) {
5644
5662
  const cands = index.byModel.get(key);
5645
5663
  if (cands === void 0) continue;
5646
- const rate = resolveCandidates(key, cands, org);
5647
- if (rate !== null) return rate;
5664
+ const cand = resolveCandidates(key, cands, org);
5665
+ if (cand !== null) return cand;
5648
5666
  }
5649
5667
  return null;
5650
5668
  }
5651
- /** One rate triple at the doubled peak rate (the tooltip's `peak | off` pair). */
5652
- function peakOf(rate) {
5653
- return {
5654
- hit: rate.hit * PEAK_FACTOR,
5655
- miss: rate.miss * PEAK_FACTOR,
5656
- write: rate.write * PEAK_FACTOR,
5657
- out: rate.out * PEAK_FACTOR
5658
- };
5659
- }
5660
5669
  /** One book branch (a provider's models), as far as runtime can prove it. */
5661
5670
  function branchOf(book, id) {
5662
5671
  const v = book[id];
5663
5672
  return v !== null && typeof v === "object" ? v : null;
5664
5673
  }
5665
5674
  /**
5666
- * One branch's model id → rates, as far as runtime can prove it: exact own
5667
- * key first (the book is untrusted wire data), then case-insensitively, then
5668
- * by id SUFFIX — dsh spells some models short (`k3`) where the registry
5669
- * namespaces them (`kimi-k3`). Several suffix candidates (e.g. `k3` vs a
5670
- * hypothetical `other-k3`) are ambiguous and price nothing.
5675
+ * One branch's lookup hit — the registry's own model id and its rates, as
5676
+ * far as runtime can prove it: exact own key first (the book is untrusted
5677
+ * wire data), then case-insensitively, then by id SUFFIX — dsh spells some
5678
+ * models short (`k3`) where the registry namespaces them (`kimi-k3`).
5679
+ * Several suffix candidates (e.g. `k3` vs a hypothetical `other-k3`) are
5680
+ * ambiguous and price nothing.
5671
5681
  */
5672
- function lookup(models, model) {
5673
- if (Object.hasOwn(models, model)) return models[model];
5682
+ function lookupFace(models, model) {
5683
+ if (Object.hasOwn(models, model)) return {
5684
+ mid: model,
5685
+ rate: models[model]
5686
+ };
5674
5687
  const m = model.toLowerCase();
5675
5688
  let found = null;
5676
5689
  let seen = null;
@@ -5679,24 +5692,63 @@ window.__ModuleLoader__.load({
5679
5692
  if (lower !== m && !lower.endsWith("-" + m)) continue;
5680
5693
  if (seen !== null && seen !== lower) return null;
5681
5694
  seen = lower;
5682
- found = models[id];
5695
+ found = {
5696
+ mid: id,
5697
+ rate: models[id]
5698
+ };
5683
5699
  }
5684
5700
  return found;
5685
5701
  }
5686
5702
  /**
5687
- * The book's rates for one folded (provider, model) bucket, or null when
5688
- * the book cannot price it: the dsh provider id resolves through
5689
- * modelsDevProviderOf (unmapped ids pass through) and prices by model id —
5690
- * exact, case-insensitive, or suffix. A provider the book does not carry
5691
- * falls back to the model-side resolution index, which names the vendor
5692
- * from data (org segment, own-vendor SDK, id prefix, lone carrier) — never
5693
- * from a per-model hardcode.
5694
- */
5695
- function priceOf(book, provider, model) {
5703
+ * One billed model's price: the USD rates plus the registry face — the
5704
+ * models.dev provider id and branch model id spelling — they resolved from
5705
+ * (what the stats board prints as the listing source).
5706
+ *
5707
+ * Resolution: the dsh provider id goes through modelsDevProviderOf (unmapped
5708
+ * ids pass through) and prices by model id — exact, case-insensitive, or
5709
+ * suffix. A provider the book does not carry falls back to the model-side
5710
+ * resolution index, which names the vendor from data (org segment, own-vendor
5711
+ * SDK, id prefix, lone carrier) — never from a per-model hardcode. The one
5712
+ * vendor-level seam: a `deepseek-` model id prices from DeepSeek's own
5713
+ * registry branch first — its listing is the first-party price book (cache
5714
+ * rates included), while the model-side tiers can hand the same id to a
5715
+ * self-named hosting provider whose flat listing bills cache hits as plain
5716
+ * input (azure's `deepseek-v4-pro`, issue #93) — the same specialness the
5717
+ * peak/off-peak split already grants DeepSeek.
5718
+ */
5719
+ function priceFaceOf(book, provider, model) {
5696
5720
  if (book === null || book === void 0) return null;
5697
- const direct = branchOf(book.prices, modelsDevProviderOf(provider));
5698
- if (direct !== null) return lookup(direct, model);
5699
- return resolveRate(book.index, model);
5721
+ const registryPid = modelsDevProviderOf(provider);
5722
+ const direct = branchOf(book.prices, registryPid);
5723
+ if (direct !== null) {
5724
+ const found = lookupFace(direct, model);
5725
+ return found === null ? null : {
5726
+ pid: registryPid,
5727
+ mid: found.mid,
5728
+ rate: found.rate
5729
+ };
5730
+ }
5731
+ if (model.toLowerCase().startsWith("deepseek-")) {
5732
+ const firstParty = branchOf(book.prices, "deepseek");
5733
+ if (firstParty !== null) {
5734
+ const official = lookupFace(firstParty, model);
5735
+ if (official !== null) return {
5736
+ pid: "deepseek",
5737
+ mid: official.mid,
5738
+ rate: official.rate
5739
+ };
5740
+ }
5741
+ }
5742
+ const cand = resolveRate(book.index, model);
5743
+ return cand === null ? null : {
5744
+ pid: cand.pid,
5745
+ mid: cand.mid,
5746
+ rate: cand.rate
5747
+ };
5748
+ }
5749
+ /** The book's rates for one folded (provider, model) bucket ({@link priceFaceOf} without the face). */
5750
+ function priceOf(book, provider, model) {
5751
+ return priceFaceOf(book, provider, model)?.rate ?? null;
5700
5752
  }
5701
5753
  /**
5702
5754
  * Price the session's cumulative billed-token totals. Cache reads bill at
@@ -5783,9 +5835,9 @@ window.__ModuleLoader__.load({
5783
5835
  function formatCost(amount, currency) {
5784
5836
  return (currency === "cny" ? "¥" : "$") + (amount >= 1 ? amount.toFixed(2) : amount.toPrecision(2));
5785
5837
  }
5786
- /** Price-list figure: the same money format as formatCost, trailing zeros trimmed (¥3.00 → ¥3, $0.0070 → $0.007). */
5838
+ /** Price-list figure: always two decimals (the tooltip's `¥ XX.XX` rate format). */
5787
5839
  function formatPriceRate(amount, currency) {
5788
- return formatCost(amount, currency).replace(/0+$/, "").replace(/\.$/, "");
5840
+ return (currency === "cny" ? "¥" : "$") + amount.toFixed(2);
5789
5841
  }
5790
5842
  //#endregion
5791
5843
  //#region node_modules/.pnpm/@opencode-ai+models@0.0.87/node_modules/@opencode-ai/models/dist/error.js
@@ -6486,33 +6538,44 @@ window.__ModuleLoader__.load({
6486
6538
  };
6487
6539
  }
6488
6540
  /**
6489
- * Merge every row's daily ledger into one — the heatmap's data. A session
6490
- * counts toward a day only when its own entry carries activity, mirroring
6491
- * the day filter's predicate, so the cell's tooltip previews the click; a
6492
- * zeroed entry is skipped whole. The merged record stays small even over
6493
- * long histories.
6541
+ * Merge every row's daily ledger into one — the heatmap's and the usage
6542
+ * chart's data. A session counts toward a day only when its own entry
6543
+ * carries activity, mirroring the day filter's predicate, so the cell's
6544
+ * tooltip previews the click; a zeroed entry is skipped whole. Each day's
6545
+ * pricing records merge into one SessionCostUsage and price off the SAME
6546
+ * book/estimator the KPI band's cost cell rides (null fee on anything
6547
+ * unpriced). The merged record stays small even over long histories.
6494
6548
  */
6495
- function aggregateDays(rows) {
6496
- const days = {};
6497
- const byKey = days;
6549
+ function aggregateDays(rows, book, currency) {
6550
+ const merged = {};
6551
+ const byKey = merged;
6498
6552
  for (const row of rows) {
6499
6553
  if (row.activity === null) continue;
6500
6554
  for (const key of Object.keys(row.activity.days)) {
6501
6555
  const entry = row.activity.days[key];
6502
6556
  if (entry.tokens <= 0 && entry.requests <= 0) continue;
6503
6557
  const prev = byKey[key];
6504
- if (prev === void 0) days[key] = {
6558
+ if (prev === void 0) merged[key] = {
6505
6559
  tokens: entry.tokens,
6506
6560
  requests: entry.requests,
6507
- sessions: 1
6561
+ sessions: 1,
6562
+ fees: entry.cost !== void 0 ? [entry.cost] : []
6508
6563
  };
6509
6564
  else {
6510
6565
  prev.tokens += entry.tokens;
6511
6566
  prev.requests += entry.requests;
6512
6567
  prev.sessions++;
6568
+ if (entry.cost !== void 0) prev.fees.push(entry.cost);
6513
6569
  }
6514
6570
  }
6515
6571
  }
6572
+ const days = {};
6573
+ for (const [key, day] of Object.entries(merged)) days[key] = {
6574
+ tokens: day.tokens,
6575
+ requests: day.requests,
6576
+ sessions: day.sessions,
6577
+ cost: estimateSessionCost(mergeCostUsage(...day.fees), book, currency)
6578
+ };
6516
6579
  return days;
6517
6580
  }
6518
6581
  /**
@@ -7291,6 +7354,166 @@ window.__ModuleLoader__.load({
7291
7354
  };
7292
7355
  }
7293
7356
  //#endregion
7357
+ //#region src/client/components/overviewUsage.tsx
7358
+ /**
7359
+ * The Context Insights panel's first-row usage chart — the RIGHT half of the
7360
+ * KPI row. Seven day columns ending today, each pairing two bars priced off
7361
+ * the merged daily ledger (overview.ts aggregateDays): billed TOKENS (the
7362
+ * heatmap's own blue) and the day's estimated COST (green). The fee rides
7363
+ * the same per-day pricing records the host fold books at each turn's
7364
+ * initiation, priced by the same book and estimator as the KPI band's cost
7365
+ * cell — never a whole session's spend dumped on the day it was last
7366
+ * active. The two series scale on their OWN window maxima (a $2 week must
7367
+ * not flatten under a 169M-token week), so each bar reads as a share of its
7368
+ * series' peak; the tooltip carries the exact figures. The window is fixed
7369
+ * to the last 7 days — the range selector above scopes the KPI figures, not
7370
+ * this calendar.
7371
+ *
7372
+ * The plot is framed like a chart: hairline gridlines at 0/25/50/75/100% of
7373
+ * each series' own peak, a solid baseline at 0, and a tick rail on each
7374
+ * side — TOKENS on the left, COST on the right, computed from the same
7375
+ * maxima the bars scale to. The cost rail reads '—' until some day actually
7376
+ * prices.
7377
+ */
7378
+ /** The chart's window: today and the six days before it, oldest first. */
7379
+ function usageWindowOf(today) {
7380
+ const columns = [];
7381
+ for (let d = -6; d <= 0; d++) {
7382
+ const key = shiftDayKey(today, d);
7383
+ if (key === null) return [];
7384
+ columns.push(key);
7385
+ }
7386
+ return columns;
7387
+ }
7388
+ /** The shared gridline/tick positions, in percent of each series' peak. */
7389
+ const TICKS = [
7390
+ 0,
7391
+ 25,
7392
+ 50,
7393
+ 75,
7394
+ 100
7395
+ ];
7396
+ function makeOverviewUsage(kit) {
7397
+ const { t, fmt } = kit;
7398
+ return function OverviewUsage(props) {
7399
+ const window = usageWindowOf(props.today);
7400
+ const byKey = props.days;
7401
+ const columns = window.map((key) => ({
7402
+ key,
7403
+ entry: byKey[key]
7404
+ }));
7405
+ const empty = columns.every((c) => c.entry === void 0 || c.entry.tokens <= 0 && c.entry.cost === null);
7406
+ let maxTokens = 0;
7407
+ let maxCost = 0;
7408
+ for (const c of columns) {
7409
+ if (c.entry === void 0) continue;
7410
+ if (c.entry.tokens > maxTokens) maxTokens = c.entry.tokens;
7411
+ if (c.entry.cost !== null && c.entry.cost > maxCost) maxCost = c.entry.cost;
7412
+ }
7413
+ const heightOf = (value, max) => max <= 0 || value <= 0 ? "0%" : `${Math.max(4, Math.round(value / max * 100))}%`;
7414
+ const tickOf = (percent) => fmt(Math.round(maxTokens * percent / 100));
7415
+ const costTickOf = (percent) => {
7416
+ if (maxCost <= 0) return "—";
7417
+ return percent === 0 ? "0" : formatCost(maxCost * percent / 100, props.currency);
7418
+ };
7419
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7420
+ className: "lc-card lc-ov-usage",
7421
+ children: [
7422
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7423
+ className: "lc-card-title",
7424
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7425
+ className: "lc-card-title-text",
7426
+ children: t("ov.usage.title")
7427
+ })
7428
+ }),
7429
+ empty || window.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7430
+ className: "lc-empty",
7431
+ children: t("ov.usage.empty")
7432
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7433
+ className: "lc-ov-usage-plot",
7434
+ role: "group",
7435
+ "aria-label": t("ov.usage.title"),
7436
+ children: [
7437
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7438
+ className: "lc-ov-usage-rail lc-ov-usage-rail-l",
7439
+ "aria-hidden": "true",
7440
+ children: TICKS.map((p) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7441
+ className: "lc-ov-usage-tick",
7442
+ style: { top: `${100 - p}%` },
7443
+ children: tickOf(p)
7444
+ }, p))
7445
+ }),
7446
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7447
+ className: "lc-ov-usage-grid",
7448
+ children: [TICKS.map((p) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7449
+ className: "lc-ov-usage-line" + (p === 0 ? " lc-ov-usage-line-0" : ""),
7450
+ style: { bottom: `${p}%` },
7451
+ "aria-hidden": "true"
7452
+ }, p)), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7453
+ className: "lc-ov-usage-cols",
7454
+ children: columns.map((c) => {
7455
+ const tokens = c.entry?.tokens ?? 0;
7456
+ const cost = c.entry?.cost ?? null;
7457
+ const label = `${c.key}\n${t("ov.usage.tokens")} ${fmt(tokens)}\n${t("ov.usage.costTip")} ${cost === null ? "—" : formatCost(cost, props.currency)}`;
7458
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
7459
+ label,
7460
+ side: "top",
7461
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7462
+ className: "lc-ov-usage-col",
7463
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7464
+ className: "lc-ov-usage-bars",
7465
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7466
+ className: "lc-ov-usage-bar lc-ov-usage-tokens",
7467
+ style: { height: heightOf(tokens, maxTokens) }
7468
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7469
+ className: "lc-ov-usage-bar lc-ov-usage-cost",
7470
+ style: { height: cost === null ? "0%" : heightOf(cost, maxCost) }
7471
+ })]
7472
+ })
7473
+ })
7474
+ }, c.key);
7475
+ })
7476
+ })]
7477
+ }),
7478
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7479
+ className: "lc-ov-usage-rail lc-ov-usage-rail-r",
7480
+ "aria-hidden": "true",
7481
+ children: TICKS.map((p) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7482
+ className: "lc-ov-usage-tick",
7483
+ style: { top: `${100 - p}%` },
7484
+ children: costTickOf(p)
7485
+ }, p))
7486
+ })
7487
+ ]
7488
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7489
+ className: "lc-ov-usage-days",
7490
+ "aria-hidden": "true",
7491
+ children: columns.map((c) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7492
+ className: "lc-ov-usage-day",
7493
+ children: c.key.slice(5)
7494
+ }, c.key))
7495
+ })] }),
7496
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7497
+ className: "lc-ov-usage-key",
7498
+ "aria-hidden": "true",
7499
+ children: [
7500
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: "lc-ov-usage-swatch lc-ov-usage-tokens" }),
7501
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7502
+ className: "lc-ov-usage-key-label",
7503
+ children: t("ov.usage.tokens")
7504
+ }),
7505
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: "lc-ov-usage-swatch lc-ov-usage-cost" }),
7506
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7507
+ className: "lc-ov-usage-key-label",
7508
+ children: t("ov.usage.cost")
7509
+ })
7510
+ ]
7511
+ })
7512
+ ]
7513
+ });
7514
+ };
7515
+ }
7516
+ //#endregion
7294
7517
  //#region src/client/components/statsTiming.tsx
7295
7518
  /**
7296
7519
  * The Timing card: where the session's ACTIVE time went. The donut splits
@@ -7623,9 +7846,12 @@ window.__ModuleLoader__.load({
7623
7846
  * projection values), so the panel draws every session's insight without
7624
7847
  * opening one log.
7625
7848
  *
7626
- * The panel's first row is the KPI metrics band: the range's six figures
7627
- * (sessions, billed tokens, cost, cache hit, tool calls, active time) in one
7628
- * full-width line. Below it, the aggregate stats row folds the same range's
7849
+ * The panel's first row is a 1:1 column pair: the KPI metrics band (the
7850
+ * range's six figures — sessions, billed tokens, cost, cache hit, tool
7851
+ * calls, active time — three per row) beside the last-7-days usage chart
7852
+ * (each day's billed tokens and estimated cost as a bar pair, folded off
7853
+ * the merged daily ledger). Below it, the aggregate stats row folds the
7854
+ * same range's
7629
7855
  * sessions into the two donut cards the per-session Context tab opens with —
7630
7856
  * Token Stats (the composition-split billed volume) and Timing Stats (the
7631
7857
  * summed totals). The body is then a 3:7 column pair: the insight column (the
@@ -7656,6 +7882,7 @@ window.__ModuleLoader__.load({
7656
7882
  const Donut = makeDonut(kit);
7657
7883
  const OverviewTokens = makeOverviewTokens(kit, Donut);
7658
7884
  const StatsTiming = makeStatsTiming(kit, Donut);
7885
+ const OverviewUsage = makeOverviewUsage(kit);
7659
7886
  const ErrorBoundary = makeErrorBoundary(t);
7660
7887
  /** The display currency follows the active locale (zh → CNY), read per render — the slot outlet re-renders on a locale switch. */
7661
7888
  function activeCurrency() {
@@ -7717,7 +7944,7 @@ window.__ModuleLoader__.load({
7717
7944
  const visible = sortRows(group === null ? scoped : scoped.filter((row) => inGroup(row, group, groups)), sort);
7718
7945
  const paged = pageOf(visible, page);
7719
7946
  const kpi = kpisOf(ranged, allRows.length, book, currency);
7720
- const days = aggregateDays(allRows);
7947
+ const days = aggregateDays(allRows, book, currency);
7721
7948
  const openOne = (id) => {
7722
7949
  openSessionVia(ctx, id);
7723
7950
  overviewStore.set(false);
@@ -7766,301 +7993,311 @@ window.__ModuleLoader__.load({
7766
7993
  }), rows === null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7767
7994
  className: "lc-empty",
7768
7995
  children: t("ov.unavailable")
7769
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
7770
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7771
- className: "lc-ov-kpis",
7772
- children: [
7773
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7774
- className: "lc-stat lc-ov-kpi",
7775
- children: [
7776
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7777
- className: "lc-stat-label",
7778
- children: t("ov.kpi.sessions")
7779
- }),
7780
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7781
- className: "lc-stat-value",
7782
- children: kpi.sessions
7783
- }),
7784
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7785
- className: "lc-stat-sub",
7786
- children: t("ov.kpi.ofTotal", { n: kpi.listed })
7787
- })
7788
- ]
7789
- }),
7790
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7791
- className: "lc-stat lc-ov-kpi",
7996
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7997
+ className: "lc-ov-scroll",
7998
+ children: [
7999
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8000
+ className: "lc-ov-first",
8001
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8002
+ className: "lc-ov-kpis",
7792
8003
  children: [
7793
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7794
- className: "lc-stat-label",
7795
- children: t("ov.kpi.tokens")
7796
- }),
7797
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7798
- className: "lc-stat-value",
7799
- children: fmt(kpi.tokens)
7800
- }),
7801
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
7802
- className: "lc-stat-sub",
8004
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8005
+ className: "lc-stat lc-ov-kpi",
7803
8006
  children: [
7804
- t("stats.turns"),
7805
- " ",
7806
- fmt(kpi.turns)
8007
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8008
+ className: "lc-stat-label",
8009
+ children: t("ov.kpi.sessions")
8010
+ }),
8011
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8012
+ className: "lc-stat-value",
8013
+ children: kpi.sessions
8014
+ }),
8015
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8016
+ className: "lc-stat-sub",
8017
+ children: t("ov.kpi.ofTotal", { n: kpi.listed })
8018
+ })
7807
8019
  ]
7808
- })
7809
- ]
7810
- }),
7811
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7812
- className: "lc-stat lc-ov-kpi",
7813
- children: [
7814
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7815
- className: "lc-stat-label",
7816
- children: t("stats.cost")
7817
- }),
7818
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7819
- className: "lc-stat-value",
7820
- children: kpi.cost === null ? "—" : formatCost(kpi.cost, currency)
7821
- }),
7822
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7823
- className: "lc-stat-sub",
7824
- children: t("ov.kpi.pricedSub", {
7825
- n: kpi.costSessions,
7826
- total: kpi.sessions
7827
- })
7828
- })
7829
- ]
7830
- }),
7831
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7832
- className: "lc-stat lc-ov-kpi",
7833
- children: [
7834
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7835
- className: "lc-stat-label",
7836
- children: t("stats.cacheHit")
7837
8020
  }),
7838
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7839
- className: "lc-stat-value",
7840
- children: kpi.cacheHit === null ? "—" : kpi.cacheHit + "%"
7841
- }),
7842
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7843
- className: "lc-stat-sub",
7844
- children: t("ov.kpi.sessionsSub", { n: kpi.usageSessions })
7845
- })
7846
- ]
7847
- }),
7848
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7849
- className: "lc-stat lc-ov-kpi",
7850
- children: [
7851
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7852
- className: "lc-stat-label",
7853
- children: t("stats.toolCalls")
8021
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8022
+ className: "lc-stat lc-ov-kpi",
8023
+ children: [
8024
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8025
+ className: "lc-stat-label",
8026
+ children: t("ov.kpi.tokens")
8027
+ }),
8028
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8029
+ className: "lc-stat-value",
8030
+ children: fmt(kpi.tokens)
8031
+ }),
8032
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
8033
+ className: "lc-stat-sub",
8034
+ children: [
8035
+ t("stats.turns"),
8036
+ " ",
8037
+ fmt(kpi.turns)
8038
+ ]
8039
+ })
8040
+ ]
7854
8041
  }),
7855
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7856
- className: "lc-stat-value",
7857
- children: fmt(kpi.toolCalls)
8042
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8043
+ className: "lc-stat lc-ov-kpi",
8044
+ children: [
8045
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8046
+ className: "lc-stat-label",
8047
+ children: t("stats.cost")
8048
+ }),
8049
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8050
+ className: "lc-stat-value",
8051
+ children: kpi.cost === null ? "—" : formatCost(kpi.cost, currency)
8052
+ }),
8053
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8054
+ className: "lc-stat-sub",
8055
+ children: t("ov.kpi.pricedSub", {
8056
+ n: kpi.costSessions,
8057
+ total: kpi.sessions
8058
+ })
8059
+ })
8060
+ ]
7858
8061
  }),
7859
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7860
- className: "lc-stat-sub",
7861
- children: t("ov.kpi.toolSub", { dur: fmtDuration(kpi.toolsMs) })
7862
- })
7863
- ]
7864
- }),
7865
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7866
- className: "lc-stat lc-ov-kpi",
7867
- children: [
7868
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7869
- className: "lc-stat-label",
7870
- children: t("timing.total")
8062
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8063
+ className: "lc-stat lc-ov-kpi",
8064
+ children: [
8065
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8066
+ className: "lc-stat-label",
8067
+ children: t("stats.cacheHit")
8068
+ }),
8069
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8070
+ className: "lc-stat-value",
8071
+ children: kpi.cacheHit === null ? "—" : kpi.cacheHit + "%"
8072
+ }),
8073
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8074
+ className: "lc-stat-sub",
8075
+ children: t("ov.kpi.sessionsSub", { n: kpi.usageSessions })
8076
+ })
8077
+ ]
7871
8078
  }),
7872
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7873
- className: "lc-stat-value",
7874
- children: fmtDuration(kpi.wallMs)
8079
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8080
+ className: "lc-stat lc-ov-kpi",
8081
+ children: [
8082
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8083
+ className: "lc-stat-label",
8084
+ children: t("stats.toolCalls")
8085
+ }),
8086
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8087
+ className: "lc-stat-value",
8088
+ children: fmt(kpi.toolCalls)
8089
+ }),
8090
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8091
+ className: "lc-stat-sub",
8092
+ children: t("ov.kpi.toolSub", { dur: fmtDuration(kpi.toolsMs) })
8093
+ })
8094
+ ]
7875
8095
  }),
7876
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7877
- className: "lc-stat-sub",
7878
- children: t("ov.kpi.wallSub", { n: fmt(kpi.calls) })
8096
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8097
+ className: "lc-stat lc-ov-kpi",
8098
+ children: [
8099
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8100
+ className: "lc-stat-label",
8101
+ children: t("timing.total")
8102
+ }),
8103
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8104
+ className: "lc-stat-value",
8105
+ children: fmtDuration(kpi.wallMs)
8106
+ }),
8107
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8108
+ className: "lc-stat-sub",
8109
+ children: t("ov.kpi.wallSub", { n: fmt(kpi.calls) })
8110
+ })
8111
+ ]
7879
8112
  })
7880
8113
  ]
7881
- })
7882
- ]
7883
- }),
7884
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7885
- className: "lc-ov-stats",
7886
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(OverviewTokens, { tokens: kpi.tokenParts }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StatsTiming, { timing: kpi.timing })]
7887
- }),
7888
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7889
- className: "lc-ov-body",
7890
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7891
- className: "lc-ov-left",
8114
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(OverviewUsage, {
8115
+ days,
8116
+ currency,
8117
+ today: todayKey()
8118
+ })]
8119
+ }),
8120
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8121
+ className: "lc-ov-stats",
8122
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(OverviewTokens, { tokens: kpi.tokenParts }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StatsTiming, { timing: kpi.timing })]
8123
+ }),
8124
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8125
+ className: "lc-ov-body",
7892
8126
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7893
- className: "lc-card lc-ov-heat-card",
8127
+ className: "lc-ov-left",
7894
8128
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7895
- className: "lc-card-title",
7896
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7897
- className: "lc-card-title-text",
7898
- children: t("ov.heat.title")
7899
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
7900
- className: "lc-heat-ctl",
8129
+ className: "lc-card lc-ov-heat-card",
8130
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8131
+ className: "lc-card-title",
7901
8132
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7902
- className: "lc-card-sub",
7903
- children: t("ov.heat.sub")
7904
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7905
- className: "lc-gran",
7906
- role: "group",
7907
- "aria-label": t("ov.heat.metric"),
7908
- children: METRICS.map((m) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
7909
- type: "button",
7910
- className: "lc-gran-btn" + (metric === m ? " lc-gran-on" : ""),
7911
- onClick: () => {
7912
- setMetric(m);
7913
- },
7914
- children: t("ov.heat.metric." + m)
7915
- }, m))
8133
+ className: "lc-card-title-text",
8134
+ children: t("ov.heat.title")
8135
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
8136
+ className: "lc-heat-ctl",
8137
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8138
+ className: "lc-card-sub",
8139
+ children: t("ov.heat.sub")
8140
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
8141
+ className: "lc-gran",
8142
+ role: "group",
8143
+ "aria-label": t("ov.heat.metric"),
8144
+ children: METRICS.map((m) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
8145
+ type: "button",
8146
+ className: "lc-gran-btn" + (metric === m ? " lc-gran-on" : ""),
8147
+ onClick: () => {
8148
+ setMetric(m);
8149
+ },
8150
+ children: t("ov.heat.metric." + m)
8151
+ }, m))
8152
+ })]
7916
8153
  })]
8154
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Heatmap, {
8155
+ days,
8156
+ metric,
8157
+ selected: day,
8158
+ onSelect: setDay,
8159
+ today: todayKey()
8160
+ })]
8161
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
8162
+ type: "button",
8163
+ className: "lc-ov-settings",
8164
+ onClick: () => {
8165
+ openPluginSettings();
8166
+ close();
8167
+ },
8168
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
8169
+ className: "lc-ov-settings-label",
8170
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconSettings, { size: 14 }), t("plugin.settings")]
8171
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8172
+ className: "lc-ov-settings-hint",
8173
+ children: t("plugin.settingsOpen")
7917
8174
  })]
7918
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Heatmap, {
7919
- days,
7920
- metric,
7921
- selected: day,
7922
- onSelect: setDay,
7923
- today: todayKey()
7924
- })]
7925
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
7926
- type: "button",
7927
- className: "lc-ov-settings",
7928
- onClick: () => {
7929
- openPluginSettings();
7930
- close();
7931
- },
7932
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
7933
- className: "lc-ov-settings-label",
7934
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconSettings, { size: 14 }), t("plugin.settings")]
7935
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7936
- className: "lc-ov-settings-hint",
7937
- children: t("plugin.settingsOpen")
7938
8175
  })]
7939
- })]
7940
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7941
- className: "lc-ov-right",
7942
- children: [
7943
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7944
- className: "lc-ov-list-head",
7945
- children: [
7946
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7947
- className: "lc-ov-list-title",
7948
- children: t("ov.list.title")
7949
- }),
7950
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7951
- className: "lc-ov-list-count",
7952
- children: visible.length
7953
- }),
7954
- day !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
7955
- type: "button",
7956
- className: "lc-ov-day-chip",
7957
- title: t("ov.list.dayClear"),
7958
- onClick: () => {
7959
- setDay(null);
7960
- },
7961
- children: [t("ov.list.dayFilter", { day }), " ×"]
7962
- }),
7963
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
7964
- className: "lc-ov-search",
7965
- type: "search",
7966
- value: query,
7967
- placeholder: t("ov.list.search"),
7968
- "aria-label": t("ov.list.search"),
7969
- onChange: (ev) => {
7970
- setQuery(ev.target.value);
7971
- }
7972
- }),
7973
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7974
- className: "lc-gran",
7975
- role: "group",
7976
- "aria-label": t("ov.list.sortLabel"),
7977
- children: SORTS.map((s) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
8176
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8177
+ className: "lc-ov-right",
8178
+ children: [
8179
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8180
+ className: "lc-ov-list-head",
8181
+ children: [
8182
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8183
+ className: "lc-ov-list-title",
8184
+ children: t("ov.list.title")
8185
+ }),
8186
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8187
+ className: "lc-ov-list-count",
8188
+ children: visible.length
8189
+ }),
8190
+ day !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
7978
8191
  type: "button",
7979
- className: "lc-gran-btn" + (sort === s ? " lc-gran-on" : ""),
8192
+ className: "lc-ov-day-chip",
8193
+ title: t("ov.list.dayClear"),
7980
8194
  onClick: () => {
7981
- setSort(s);
8195
+ setDay(null);
7982
8196
  },
7983
- children: t("ov.list.sort." + s)
7984
- }, s))
7985
- })
7986
- ]
7987
- }),
7988
- chips.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7989
- className: "lc-ov-groups",
7990
- role: "group",
7991
- "aria-label": t("ov.group.label"),
7992
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
7993
- type: "button",
7994
- className: "lc-ov-chip" + (group === null ? " lc-ov-chip-on" : ""),
7995
- onClick: () => {
7996
- setGroup(null);
7997
- },
7998
- children: [t("ov.range.all"), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7999
- className: "lc-ov-chip-n",
8000
- children: scoped.length
8001
- })]
8002
- }), chips.map((c) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
8003
- type: "button",
8004
- className: "lc-ov-chip" + (group === c.key ? " lc-ov-chip-on" : ""),
8005
- onClick: () => {
8006
- setGroup(group === c.key ? null : c.key);
8007
- },
8008
- children: [c.key === "__ungrouped__" ? t("ov.group.ungrouped") : c.key, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8009
- className: "lc-ov-chip-n",
8010
- children: c.count
8011
- })]
8012
- }, c.key))]
8013
- }),
8014
- visible.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
8015
- className: "lc-empty",
8016
- children: t(allRows.length === 0 ? "ov.list.empty" : "ov.list.noMatch")
8017
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
8018
- className: "lc-ov-grid",
8019
- children: paged.items.map((row) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(OverviewCard, {
8020
- row,
8021
- ...groups?.[row.id] !== void 0 ? { group: groups[row.id] } : {},
8022
- costLabel: cardCostOf(row, book, currency),
8023
- now,
8024
- onOpen: openOne
8025
- }, row.id))
8026
- }), paged.count > 1 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8027
- className: "lc-ov-pager",
8028
- role: "navigation",
8029
- "aria-label": t("ov.list.pager"),
8030
- children: [
8031
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
8197
+ children: [t("ov.list.dayFilter", { day }), " ×"]
8198
+ }),
8199
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
8200
+ className: "lc-ov-search",
8201
+ type: "search",
8202
+ value: query,
8203
+ placeholder: t("ov.list.search"),
8204
+ "aria-label": t("ov.list.search"),
8205
+ onChange: (ev) => {
8206
+ setQuery(ev.target.value);
8207
+ }
8208
+ }),
8209
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
8210
+ className: "lc-gran",
8211
+ role: "group",
8212
+ "aria-label": t("ov.list.sortLabel"),
8213
+ children: SORTS.map((s) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
8214
+ type: "button",
8215
+ className: "lc-gran-btn" + (sort === s ? " lc-gran-on" : ""),
8216
+ onClick: () => {
8217
+ setSort(s);
8218
+ },
8219
+ children: t("ov.list.sort." + s)
8220
+ }, s))
8221
+ })
8222
+ ]
8223
+ }),
8224
+ chips.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8225
+ className: "lc-ov-groups",
8226
+ role: "group",
8227
+ "aria-label": t("ov.group.label"),
8228
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
8032
8229
  type: "button",
8033
- className: "lc-ov-pager-btn",
8034
- disabled: paged.index === 0,
8035
- "aria-label": t("ov.list.prev"),
8230
+ className: "lc-ov-chip" + (group === null ? " lc-ov-chip-on" : ""),
8036
8231
  onClick: () => {
8037
- setPage(paged.index - 1);
8232
+ setGroup(null);
8038
8233
  },
8039
- children: "‹"
8040
- }),
8041
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8042
- className: "lc-ov-pager-n",
8043
- children: t("ov.list.page", {
8044
- n: paged.index + 1,
8045
- total: paged.count
8046
- })
8047
- }),
8048
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
8234
+ children: [t("ov.range.all"), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8235
+ className: "lc-ov-chip-n",
8236
+ children: scoped.length
8237
+ })]
8238
+ }), chips.map((c) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
8049
8239
  type: "button",
8050
- className: "lc-ov-pager-btn",
8051
- disabled: paged.index === paged.count - 1,
8052
- "aria-label": t("ov.list.next"),
8240
+ className: "lc-ov-chip" + (group === c.key ? " lc-ov-chip-on" : ""),
8053
8241
  onClick: () => {
8054
- setPage(paged.index + 1);
8242
+ setGroup(group === c.key ? null : c.key);
8055
8243
  },
8056
- children: "›"
8057
- })
8058
- ]
8059
- })] })
8060
- ]
8061
- })]
8062
- })
8063
- ] })]
8244
+ children: [c.key === "__ungrouped__" ? t("ov.group.ungrouped") : c.key, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8245
+ className: "lc-ov-chip-n",
8246
+ children: c.count
8247
+ })]
8248
+ }, c.key))]
8249
+ }),
8250
+ visible.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
8251
+ className: "lc-empty",
8252
+ children: t(allRows.length === 0 ? "ov.list.empty" : "ov.list.noMatch")
8253
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
8254
+ className: "lc-ov-grid",
8255
+ children: paged.items.map((row) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(OverviewCard, {
8256
+ row,
8257
+ ...groups?.[row.id] !== void 0 ? { group: groups[row.id] } : {},
8258
+ costLabel: cardCostOf(row, book, currency),
8259
+ now,
8260
+ onOpen: openOne
8261
+ }, row.id))
8262
+ }), paged.count > 1 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8263
+ className: "lc-ov-pager",
8264
+ role: "navigation",
8265
+ "aria-label": t("ov.list.pager"),
8266
+ children: [
8267
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
8268
+ type: "button",
8269
+ className: "lc-ov-pager-btn",
8270
+ disabled: paged.index === 0,
8271
+ "aria-label": t("ov.list.prev"),
8272
+ onClick: () => {
8273
+ setPage(paged.index - 1);
8274
+ },
8275
+ children: "‹"
8276
+ }),
8277
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8278
+ className: "lc-ov-pager-n",
8279
+ children: t("ov.list.page", {
8280
+ n: paged.index + 1,
8281
+ total: paged.count
8282
+ })
8283
+ }),
8284
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
8285
+ type: "button",
8286
+ className: "lc-ov-pager-btn",
8287
+ disabled: paged.index === paged.count - 1,
8288
+ "aria-label": t("ov.list.next"),
8289
+ onClick: () => {
8290
+ setPage(paged.index + 1);
8291
+ },
8292
+ children: "›"
8293
+ })
8294
+ ]
8295
+ })] })
8296
+ ]
8297
+ })]
8298
+ })
8299
+ ]
8300
+ })]
8064
8301
  })
8065
8302
  });
8066
8303
  }
@@ -10439,7 +10676,7 @@ window.__ModuleLoader__.load({
10439
10676
  });
10440
10677
  }
10441
10678
  //#endregion
10442
- //#region node_modules/.pnpm/simple-icons@16.31.0/node_modules/simple-icons/index.mjs
10679
+ //#region node_modules/.pnpm/simple-icons@16.32.0/node_modules/simple-icons/index.mjs
10443
10680
  const c = "<svg role=\"img\" viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\"><title>";
10444
10681
  const t = "</title><path d=\"";
10445
10682
  const a = "\"/></svg>";
@@ -10547,7 +10784,7 @@ window.__ModuleLoader__.load({
10547
10784
  return function PluginInfo() {
10548
10785
  const [latest, setLatest] = (0, react.useState)(null);
10549
10786
  (0, react.useEffect)(() => {
10550
- if ("0.58.0".includes("-dev")) return;
10787
+ if ("0.59.1".includes("-dev")) return;
10551
10788
  let on = true;
10552
10789
  fetchLatestVersion().then((v) => {
10553
10790
  if (on && v) setLatest(v);
@@ -10556,8 +10793,8 @@ window.__ModuleLoader__.load({
10556
10793
  on = false;
10557
10794
  };
10558
10795
  }, []);
10559
- const update = latest !== null && isNewerVersion(latest, "0.58.0") ? latest : null;
10560
- const nameText = "dsh-context (v0.58.0)";
10796
+ const update = latest !== null && isNewerVersion(latest, "0.59.1") ? latest : null;
10797
+ const nameText = "dsh-context (v0.59.1)";
10561
10798
  const nameValue = [nameText];
10562
10799
  if (update) nameValue.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
10563
10800
  className: "lc-pi-update",
@@ -11022,18 +11259,22 @@ window.__ModuleLoader__.load({
11022
11259
  * and the caller derives them from the collections on the inline generation
11023
11260
  * (`countsOfRecords`). The card itself never touches the collections.
11024
11261
  */
11262
+ /** The four billed buckets of a price block, in display order, with their label keys. */
11263
+ const BANDS = [
11264
+ ["hit", "stats.costHit"],
11265
+ ["miss", "stats.costMiss"],
11266
+ ["write", "stats.costWrite"],
11267
+ ["out", "stats.costOut"]
11268
+ ];
11025
11269
  /**
11026
- * The rate rows for the models this session actually billed — the usage
11027
- * keys priced against the book, in fold order. Hostile branches skip;
11028
- * unpriced models drop (their buckets simply do not contribute). The label
11029
- * carries the provider only when the session billed more than one; a model
11030
- * with an off-peak bucket (DeepSeek's period-based list) shows the
11031
- * peak | off-peak pair.
11270
+ * The billed models' price blocks — the usage keys priced against the book,
11271
+ * in fold order, each carrying the registry face (models.dev provider id ·
11272
+ * model id) its rates resolved from. Hostile branches skip; unpriced models
11273
+ * drop (their buckets simply do not contribute).
11032
11274
  */
11033
11275
  function priceRowsOf(usage, book) {
11034
11276
  if (usage === void 0 || book === null) return [];
11035
11277
  const rows = [];
11036
- const multi = Object.keys(usage).length > 1;
11037
11278
  for (const provider of Object.keys(usage)) {
11038
11279
  const models = asRecord(usage[provider]);
11039
11280
  /* v8 ignore next 1 -- the fold's inputs are mergeCostUsage's own output
@@ -11041,16 +11282,11 @@ window.__ModuleLoader__.load({
11041
11282
  reaches here; the guard stays for the helper's own contract. */
11042
11283
  if (models === null) continue;
11043
11284
  for (const model of Object.keys(models)) {
11044
- const rate = priceOf(book, provider, model);
11045
- if (rate === null) continue;
11046
- const periods = asRecord(models[model]);
11047
- const deepseek = isDeepSeekProvider(provider);
11048
- const billedOff = deepseek && periods !== null && periods.off !== void 0;
11285
+ const face = priceFaceOf(book, provider, model);
11286
+ if (face === null) continue;
11049
11287
  rows.push({
11050
11288
  key: provider + "/" + model,
11051
- label: multi && provider !== "" ? `${model} · ${provider}` : model,
11052
- rate: deepseek ? peakOf(rate) : rate,
11053
- ...billedOff ? { offRate: rate } : {}
11289
+ face
11054
11290
  });
11055
11291
  }
11056
11292
  }
@@ -11114,62 +11350,50 @@ window.__ModuleLoader__.load({
11114
11350
  const subCost = estimateSessionCost(subUsage, book, currency);
11115
11351
  const fmtRate = (usd) => formatPriceRate(toCurrency(usd, currency), currency);
11116
11352
  const rows = priceRowsOf(usage, book);
11353
+ const subRows = priceRowsOf(subUsage ?? void 0, book);
11117
11354
  const deepseek = usage !== void 0 && Object.keys(usage).some((p) => isDeepSeekProvider(p));
11118
11355
  const subDeepseek = subUsage !== null && Object.keys(subUsage).some((p) => isDeepSeekProvider(p));
11119
- const anyPair = rows.some((r) => r.offRate !== void 0);
11120
11356
  const unpriced = rows.length === 0 && usage !== void 0 && Object.keys(usage).length > 0 && (failed || book !== null);
11121
- const subUnpriced = subUsage !== null && priceRowsOf(subUsage, book).length === 0 && (failed || book !== null);
11122
- const costTip = [
11123
- t("stats.costTip") + (deepseek ? " " + t("stats.costTipDeepseek") : ""),
11124
- rows.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
11125
- className: "lc-stat-tip-prices",
11126
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
11127
- className: "lc-stat-tip-head",
11128
- children: anyPair ? t("stats.costPriceHeadPair") : t("stats.costPriceHead")
11129
- }), rows.map((r) => {
11130
- const cells = [
11131
- [
11132
- t("stats.costHit"),
11133
- r.rate.hit,
11134
- r.offRate?.hit
11135
- ],
11136
- [
11137
- t("stats.costMiss"),
11138
- r.rate.miss,
11139
- r.offRate?.miss
11140
- ],
11141
- [
11142
- t("stats.costWrite"),
11143
- r.rate.write,
11144
- r.offRate?.write
11145
- ],
11146
- [
11147
- t("stats.costOut"),
11148
- r.rate.out,
11149
- r.offRate?.out
11150
- ]
11151
- ];
11152
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
11153
- className: "lc-stat-tip-row",
11154
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", {
11155
- className: "lc-stat-tip-model",
11156
- children: r.label
11157
- }), cells.map(([name, peak, off]) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
11158
- " · ",
11159
- name,
11160
- " ",
11161
- off === void 0 ? fmtRate(peak) : `${fmtRate(peak)}|${fmtRate(off)}`
11162
- ] }, name))]
11163
- }, r.key);
11357
+ const subUnpriced = subRows.length === 0 && subUsage !== null && (failed || book !== null);
11358
+ const pricesBlock = (blocks) => blocks.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
11359
+ className: "lc-stat-tip-prices",
11360
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
11361
+ className: "lc-stat-tip-head",
11362
+ children: t("stats.costPriceHead")
11363
+ }), blocks.map((r) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
11364
+ className: "lc-stat-tip-row",
11365
+ children: [BANDS.filter(([bucket]) => r.face.rate[bucket] > 0).map(([bucket, label]) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
11366
+ className: "lc-stat-tip-band",
11367
+ children: [
11368
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("i", { children: t(label) }),
11369
+ " ",
11370
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", { children: fmtRate(r.face.rate[bucket]) })
11371
+ ]
11372
+ }, bucket)), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
11373
+ className: "lc-stat-tip-by",
11374
+ children: t("stats.costPriceBy", {
11375
+ p: r.face.pid,
11376
+ m: r.face.mid
11377
+ })
11164
11378
  })]
11165
- }, "prices") : null,
11379
+ }, r.key))]
11380
+ }, "prices") : null;
11381
+ const notes = (deep) => [currency === "cny" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("stats.costTipCny") }, "cny") : null, deep ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("stats.costTipDeepseek") }, "peak") : null].filter((el) => el !== null);
11382
+ const costTip = [
11383
+ t("stats.costTip"),
11384
+ pricesBlock(rows),
11385
+ ...notes(deepseek),
11166
11386
  unpriced ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("stats.costUnavailable") }, "unavailable") : null
11167
11387
  ];
11168
- const subTip = [t("stats.subCostTip") + (subDeepseek ? " " + t("stats.costTipDeepseek") : ""), subUnpriced ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("stats.costUnavailable") }, "unavailable") : null];
11388
+ const subTip = [
11389
+ t("stats.subCostTip"),
11390
+ pricesBlock(subRows),
11391
+ ...notes(subDeepseek),
11392
+ subUnpriced ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("stats.costUnavailable") }, "unavailable") : null
11393
+ ];
11169
11394
  const hit = props.usage === null ? null : cacheHitPercent(numOf(props.usage.cacheReadTokens), numOf(props.usage.uncachedInputTokens) + numOf(props.usage.cacheReadTokens) + numOf(props.usage.cacheWriteTokens));
11170
- const cell = (label, value, tip) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
11171
- className: "lc-stat" + (tip === void 0 ? "" : " lc-stat-tipped group/tip"),
11172
- children: [
11395
+ const cell = (label, value, tip, href) => {
11396
+ const body = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
11173
11397
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
11174
11398
  className: "lc-stat-label",
11175
11399
  children: [label, tip !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("i", {
@@ -11187,8 +11411,21 @@ window.__ModuleLoader__.load({
11187
11411
  role: "tooltip",
11188
11412
  children: tip
11189
11413
  })
11190
- ]
11191
- });
11414
+ ] });
11415
+ const className = "lc-stat" + (tip === void 0 ? "" : " lc-stat-tipped group/tip");
11416
+ return href === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
11417
+ className,
11418
+ children: body
11419
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
11420
+ className,
11421
+ href,
11422
+ target: "_blank",
11423
+ rel: "noreferrer noopener",
11424
+ children: body
11425
+ });
11426
+ };
11427
+ const costPids = new Set(rows.map((r) => r.face.pid).filter((p) => p !== ""));
11428
+ const costHref = costPids.size === 1 ? "https://models.dev/providers/" + [...costPids][0] + "/" : void 0;
11192
11429
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
11193
11430
  className: "lc-card lc-col-stats flex-[3] min-w-[min(360px,100%)]",
11194
11431
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -11205,7 +11442,7 @@ window.__ModuleLoader__.load({
11205
11442
  cell(t("stats.humanInputs"), props.humanInputs ?? 0, t("stats.humanInputsTip")),
11206
11443
  cell(t("stats.toolCalls"), props.toolCalls ?? 0),
11207
11444
  cell(t("stats.cacheHit"), hit === null ? "—" : `${hit}%`, t("stats.cacheHitTip")),
11208
- cell(t("stats.cost"), cost === null ? "—" : formatCost(cost, currency), costTip),
11445
+ cell(t("stats.cost"), cost === null ? "—" : formatCost(cost, currency), costTip, costHref),
11209
11446
  cell(t("stats.subCost"), subCost === null ? "—" : formatCost(subCost, currency), subTip)
11210
11447
  ]
11211
11448
  })]
@@ -12120,7 +12357,7 @@ window.__ModuleLoader__.load({
12120
12357
  }
12121
12358
  //#endregion
12122
12359
  //#region \0dsh-global-css:/home/runner/work/dsh-context/dsh-context/src/client/styles/stats.css.mjs
12123
- 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}.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-model{color:var(--dsw-alias-label-primary)}.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}";
12360
+ 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}";
12124
12361
  const tagId$13 = "dsh-context/stats.css";
12125
12362
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$13) + "]") === null) {
12126
12363
  const tag = document.createElement("style");
@@ -12263,7 +12500,7 @@ window.__ModuleLoader__.load({
12263
12500
  }
12264
12501
  //#endregion
12265
12502
  //#region \0dsh-global-css:/home/runner/work/dsh-context/dsh-context/src/client/styles/overview.css.mjs
12266
- 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-kpis{flex:none;grid-template-columns:repeat(6,minmax(0,1fr));gap:10px;margin-bottom:10px;display:grid}.lc-ov-kpi{align-items:center;padding:10px 8px}.lc-ov-kpi .lc-stat-value{font-size:20px}@container lc-ov (width<=1000px){.lc-ov-kpis{grid-template-columns:repeat(3,minmax(0,1fr))}}@container lc-ov (width<=640px){.lc-ov-kpis{grid-template-columns:repeat(2,minmax(0,1fr))}}.lc-ov-stats{flex:none;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{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-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}";
12503
+ 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}";
12267
12504
  const tagId = "dsh-context/overview.css";
12268
12505
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
12269
12506
  const tag = document.createElement("style");