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/README.md +2 -1
- package/lib/client.js +663 -426
- package/lib/index.d.ts +16 -0
- package/lib/index.js +152 -50
- package/package.json +14 -13
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": "
|
|
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": "每百万
|
|
64
|
-
"stats.
|
|
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": "
|
|
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.
|
|
446
|
-
"stats.costHit": "
|
|
447
|
-
"stats.costMiss": "
|
|
448
|
-
"stats.costWrite": "write",
|
|
449
|
-
"stats.costOut": "
|
|
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
|
|
1631
|
-
* Absent or non-record stays null (an older host serves no
|
|
1632
|
-
* heatmap renders its empty note). Per-day re-proved: a
|
|
1633
|
-
* wrong-typed figure drops just that entry, a
|
|
1634
|
-
*
|
|
1635
|
-
*
|
|
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
|
|
5593
|
-
* group wins, a tie refuses. Agreeing mirrors are noise;
|
|
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
|
|
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
|
-
|
|
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].
|
|
5625
|
+
return groups.length > 1 && groups[0].n === groups[1].n ? null : groups[0].cand;
|
|
5608
5626
|
}
|
|
5609
5627
|
/**
|
|
5610
|
-
* Pick one candidate
|
|
5611
|
-
*
|
|
5612
|
-
*
|
|
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
|
|
5619
|
-
if (
|
|
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
|
|
5625
|
-
if (
|
|
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
|
|
5630
|
-
if (
|
|
5647
|
+
const cand = majorityCandidate(prefixed);
|
|
5648
|
+
if (cand !== null) return cand;
|
|
5631
5649
|
}
|
|
5632
|
-
return cands.length === 1 ? cands[0]
|
|
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
|
|
5647
|
-
if (
|
|
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
|
|
5667
|
-
* key first (the book is untrusted
|
|
5668
|
-
* by id SUFFIX — dsh spells some
|
|
5669
|
-
*
|
|
5670
|
-
* hypothetical `other-k3`) are
|
|
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
|
|
5673
|
-
if (Object.hasOwn(models, model)) return
|
|
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 =
|
|
5695
|
+
found = {
|
|
5696
|
+
mid: id,
|
|
5697
|
+
rate: models[id]
|
|
5698
|
+
};
|
|
5683
5699
|
}
|
|
5684
5700
|
return found;
|
|
5685
5701
|
}
|
|
5686
5702
|
/**
|
|
5687
|
-
*
|
|
5688
|
-
*
|
|
5689
|
-
*
|
|
5690
|
-
*
|
|
5691
|
-
*
|
|
5692
|
-
*
|
|
5693
|
-
*
|
|
5694
|
-
|
|
5695
|
-
|
|
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
|
|
5698
|
-
|
|
5699
|
-
|
|
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:
|
|
5838
|
+
/** Price-list figure: always two decimals (the tooltip's `¥ XX.XX` rate format). */
|
|
5787
5839
|
function formatPriceRate(amount, currency) {
|
|
5788
|
-
return
|
|
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
|
|
6490
|
-
* counts toward a day only when its own entry
|
|
6491
|
-
* the day filter's predicate, so the cell's
|
|
6492
|
-
* zeroed entry is skipped whole.
|
|
6493
|
-
*
|
|
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
|
|
6497
|
-
const byKey =
|
|
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)
|
|
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
|
|
7627
|
-
*
|
|
7628
|
-
*
|
|
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)(
|
|
7770
|
-
|
|
7771
|
-
|
|
7772
|
-
|
|
7773
|
-
|
|
7774
|
-
|
|
7775
|
-
|
|
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.
|
|
7794
|
-
className: "lc-stat-
|
|
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
|
-
|
|
7805
|
-
|
|
7806
|
-
|
|
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.
|
|
7839
|
-
className: "lc-stat-
|
|
7840
|
-
children:
|
|
7841
|
-
|
|
7842
|
-
|
|
7843
|
-
|
|
7844
|
-
|
|
7845
|
-
|
|
7846
|
-
|
|
7847
|
-
|
|
7848
|
-
|
|
7849
|
-
|
|
7850
|
-
|
|
7851
|
-
|
|
7852
|
-
|
|
7853
|
-
|
|
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.
|
|
7856
|
-
className: "lc-stat-
|
|
7857
|
-
children:
|
|
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.
|
|
7860
|
-
className: "lc-stat-
|
|
7861
|
-
children:
|
|
7862
|
-
|
|
7863
|
-
|
|
7864
|
-
|
|
7865
|
-
|
|
7866
|
-
|
|
7867
|
-
|
|
7868
|
-
|
|
7869
|
-
|
|
7870
|
-
|
|
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.
|
|
7873
|
-
className: "lc-stat-
|
|
7874
|
-
children:
|
|
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.
|
|
7877
|
-
className: "lc-stat-
|
|
7878
|
-
children:
|
|
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
|
-
|
|
7885
|
-
|
|
7886
|
-
|
|
7887
|
-
|
|
7888
|
-
|
|
7889
|
-
|
|
7890
|
-
|
|
7891
|
-
|
|
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-
|
|
8127
|
+
className: "lc-ov-left",
|
|
7894
8128
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7895
|
-
className: "lc-card-
|
|
7896
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.
|
|
7897
|
-
className: "lc-card-title
|
|
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-
|
|
7903
|
-
children: t("ov.heat.
|
|
7904
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.
|
|
7905
|
-
className: "lc-
|
|
7906
|
-
|
|
7907
|
-
|
|
7908
|
-
|
|
7909
|
-
|
|
7910
|
-
className: "lc-gran
|
|
7911
|
-
|
|
7912
|
-
|
|
7913
|
-
|
|
7914
|
-
|
|
7915
|
-
|
|
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
|
-
|
|
7941
|
-
|
|
7942
|
-
|
|
7943
|
-
|
|
7944
|
-
|
|
7945
|
-
|
|
7946
|
-
|
|
7947
|
-
|
|
7948
|
-
|
|
7949
|
-
|
|
7950
|
-
|
|
7951
|
-
|
|
7952
|
-
|
|
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-
|
|
8192
|
+
className: "lc-ov-day-chip",
|
|
8193
|
+
title: t("ov.list.dayClear"),
|
|
7980
8194
|
onClick: () => {
|
|
7981
|
-
|
|
8195
|
+
setDay(null);
|
|
7982
8196
|
},
|
|
7983
|
-
children: t("ov.list.
|
|
7984
|
-
},
|
|
7985
|
-
|
|
7986
|
-
|
|
7987
|
-
|
|
7988
|
-
|
|
7989
|
-
|
|
7990
|
-
|
|
7991
|
-
|
|
7992
|
-
|
|
7993
|
-
|
|
7994
|
-
|
|
7995
|
-
|
|
7996
|
-
|
|
7997
|
-
|
|
7998
|
-
|
|
7999
|
-
|
|
8000
|
-
|
|
8001
|
-
|
|
8002
|
-
|
|
8003
|
-
|
|
8004
|
-
|
|
8005
|
-
|
|
8006
|
-
|
|
8007
|
-
|
|
8008
|
-
|
|
8009
|
-
|
|
8010
|
-
|
|
8011
|
-
|
|
8012
|
-
|
|
8013
|
-
|
|
8014
|
-
|
|
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-
|
|
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
|
-
|
|
8232
|
+
setGroup(null);
|
|
8038
8233
|
},
|
|
8039
|
-
children: "
|
|
8040
|
-
|
|
8041
|
-
|
|
8042
|
-
|
|
8043
|
-
|
|
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-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
10560
|
-
const nameText = "dsh-context (v0.
|
|
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
|
|
11027
|
-
*
|
|
11028
|
-
*
|
|
11029
|
-
*
|
|
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
|
|
11045
|
-
if (
|
|
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
|
-
|
|
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 =
|
|
11122
|
-
const
|
|
11123
|
-
|
|
11124
|
-
|
|
11125
|
-
className: "lc-stat-tip-
|
|
11126
|
-
children:
|
|
11127
|
-
|
|
11128
|
-
|
|
11129
|
-
|
|
11130
|
-
|
|
11131
|
-
|
|
11132
|
-
|
|
11133
|
-
|
|
11134
|
-
|
|
11135
|
-
|
|
11136
|
-
|
|
11137
|
-
|
|
11138
|
-
|
|
11139
|
-
|
|
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
|
-
},
|
|
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 = [
|
|
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) =>
|
|
11171
|
-
|
|
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-
|
|
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");
|