dsh-context 0.57.0 → 0.59.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/lib/client.js +743 -400
- package/lib/index.d.ts +16 -0
- package/lib/index.js +158 -53
- package/package.json +15 -14
package/lib/client.js
CHANGED
|
@@ -354,9 +354,15 @@ window.__ModuleLoader__.load({
|
|
|
354
354
|
"ov.kpi.ofTotal": "共 {n} 个",
|
|
355
355
|
"ov.kpi.tokens": "累计消耗",
|
|
356
356
|
"ov.kpi.sessionsSub": "含 {n} 个会话",
|
|
357
|
+
"ov.kpi.pricedSub": "已计价 {n}/{total} 个会话",
|
|
357
358
|
"ov.kpi.toolSub": "工具执行 {dur}",
|
|
358
359
|
"ov.kpi.wallSub": "模型调用 {n}",
|
|
359
360
|
"ov.stats.empty": "统计范围内暂无 Token 用量",
|
|
361
|
+
"ov.usage.title": "近 7 天用量",
|
|
362
|
+
"ov.usage.tokens": "Token",
|
|
363
|
+
"ov.usage.cost": "费用(仅含支持计价映射的模型)",
|
|
364
|
+
"ov.usage.costTip": "费用",
|
|
365
|
+
"ov.usage.empty": "近 7 天暂无用量 — 会话产生模型请求后,这里会显示每日 Token 与费用",
|
|
360
366
|
"balance.title": "DeepSeek 余额",
|
|
361
367
|
"balance.tip.granted": "赠送余额",
|
|
362
368
|
"balance.tip.toppedUp": "充值余额",
|
|
@@ -734,9 +740,15 @@ window.__ModuleLoader__.load({
|
|
|
734
740
|
"ov.kpi.ofTotal": "of {n} total",
|
|
735
741
|
"ov.kpi.tokens": "Tokens Used",
|
|
736
742
|
"ov.kpi.sessionsSub": "across {n} sessions",
|
|
743
|
+
"ov.kpi.pricedSub": "{n} of {total} sessions priced",
|
|
737
744
|
"ov.kpi.toolSub": "tool runs {dur}",
|
|
738
745
|
"ov.kpi.wallSub": "{n} model calls",
|
|
739
746
|
"ov.stats.empty": "No billed tokens in this range",
|
|
747
|
+
"ov.usage.title": "Last 7 Days",
|
|
748
|
+
"ov.usage.tokens": "Tokens",
|
|
749
|
+
"ov.usage.cost": "Cost (price-mapped models only)",
|
|
750
|
+
"ov.usage.costTip": "Cost",
|
|
751
|
+
"ov.usage.empty": "No usage in the last 7 days — daily tokens and cost appear once sessions make model requests",
|
|
740
752
|
"balance.title": "DeepSeek balance",
|
|
741
753
|
"balance.tip.granted": "Granted balance",
|
|
742
754
|
"balance.tip.toppedUp": "Topped-up balance",
|
|
@@ -1625,12 +1637,13 @@ window.__ModuleLoader__.load({
|
|
|
1625
1637
|
}
|
|
1626
1638
|
/**
|
|
1627
1639
|
* Narrow a delivered `contextActivity` value (the per-day ledger the Context
|
|
1628
|
-
* Overview's heatmap
|
|
1629
|
-
* Absent or non-record stays null (an older host serves no
|
|
1630
|
-
* heatmap renders its empty note). Per-day re-proved: a
|
|
1631
|
-
* wrong-typed figure drops just that entry, a
|
|
1632
|
-
*
|
|
1633
|
-
*
|
|
1640
|
+
* Overview's heatmap and usage chart read off each session-list row) to a
|
|
1641
|
+
* render-safe shape. Absent or non-record stays null (an older host serves no
|
|
1642
|
+
* such key — the heatmap renders its empty note). Per-day re-proved: a
|
|
1643
|
+
* malformed key or a wrong-typed figure drops just that entry, a malformed
|
|
1644
|
+
* pricing record drops just the fee (the day's tokens survive), a hostile day
|
|
1645
|
+
* record can never produce a NaN cell, and a well-formed payload passes
|
|
1646
|
+
* through untouched (reference-stable for the selector equality).
|
|
1634
1647
|
*/
|
|
1635
1648
|
function activityOf$1(value) {
|
|
1636
1649
|
const data = asRecord(value);
|
|
@@ -1647,9 +1660,13 @@ window.__ModuleLoader__.load({
|
|
|
1647
1660
|
dirty = true;
|
|
1648
1661
|
continue;
|
|
1649
1662
|
}
|
|
1663
|
+
const proved = costOf(entry.cost);
|
|
1664
|
+
const cost = proved !== void 0 && Object.keys(proved).length > 0 ? proved : void 0;
|
|
1665
|
+
if (entry.cost !== void 0 && cost === void 0) dirty = true;
|
|
1650
1666
|
days[key] = {
|
|
1651
1667
|
tokens,
|
|
1652
|
-
requests
|
|
1668
|
+
requests,
|
|
1669
|
+
...cost !== void 0 ? { cost } : {}
|
|
1653
1670
|
};
|
|
1654
1671
|
}
|
|
1655
1672
|
return dirty ? { days } : data;
|
|
@@ -2906,6 +2923,7 @@ window.__ModuleLoader__.load({
|
|
|
2906
2923
|
const BAR_W = 14;
|
|
2907
2924
|
const BAR_GAP = 2;
|
|
2908
2925
|
const STAGGER_CAP = 20;
|
|
2926
|
+
const STEP_FLAG_EVERY = 5;
|
|
2909
2927
|
const TURN_FILLS = ["color-mix(in srgb, var(--color-neutral-500) 12%, transparent)", "color-mix(in srgb, var(--color-neutral-500) 26%, transparent)"];
|
|
2910
2928
|
const LABEL_OVERHANG = 48;
|
|
2911
2929
|
const LABEL_GAP = 2;
|
|
@@ -2962,62 +2980,73 @@ window.__ModuleLoader__.load({
|
|
|
2962
2980
|
onMouseEnter: () => {
|
|
2963
2981
|
props.onHover(req.seq);
|
|
2964
2982
|
},
|
|
2965
|
-
children: [
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
2983
|
+
children: [
|
|
2984
|
+
props.flag !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2985
|
+
className: "lc-step-flag",
|
|
2986
|
+
"aria-hidden": "true",
|
|
2987
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2988
|
+
className: "lc-step-flag-label",
|
|
2989
|
+
children: props.flag
|
|
2990
|
+
})
|
|
2991
|
+
}) : null,
|
|
2992
|
+
marker !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2993
|
+
className: "lc-bar-marker",
|
|
2994
|
+
title: "✂ " + (markerAt !== null ? markerAt + " — " : "") + eventLabel(marker),
|
|
2995
|
+
children: "✂"
|
|
2996
|
+
}) : null,
|
|
2997
|
+
diverge ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2998
|
+
className: "lc-bar-up animate-lc-bar-in motion-reduce:animate-none",
|
|
2999
|
+
style: {
|
|
3000
|
+
bottom: `${props.downPx}px`,
|
|
3001
|
+
...enterStyle
|
|
3002
|
+
},
|
|
3003
|
+
children: CATS.map((c) => {
|
|
3004
|
+
const d = req[c.key] || 0;
|
|
3005
|
+
if (d <= 0) return null;
|
|
3006
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3007
|
+
"data-cat": c.key,
|
|
3008
|
+
className: "lc-cat-seg",
|
|
3009
|
+
style: {
|
|
3010
|
+
height: `${Math.max(1, Math.round(d * props.deltaScale))}px`,
|
|
3011
|
+
background: c.color
|
|
3012
|
+
}
|
|
3013
|
+
}, c.key);
|
|
3014
|
+
})
|
|
3015
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3016
|
+
className: "lc-bar-down animate-lc-bar-in motion-reduce:animate-none",
|
|
3017
|
+
style: {
|
|
3018
|
+
top: `${props.upPx}px`,
|
|
3019
|
+
...enterStyle
|
|
3020
|
+
},
|
|
3021
|
+
children: CATS.map((c) => {
|
|
3022
|
+
const d = req[c.key] || 0;
|
|
3023
|
+
if (d >= 0) return null;
|
|
3024
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3025
|
+
"data-cat": c.key,
|
|
3026
|
+
className: "lc-cat-seg",
|
|
3027
|
+
style: {
|
|
3028
|
+
height: `${Math.max(1, Math.round(-d * props.deltaScale))}px`,
|
|
3029
|
+
background: c.color
|
|
3030
|
+
}
|
|
3031
|
+
}, c.key);
|
|
3032
|
+
})
|
|
3033
|
+
})] }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3034
|
+
className: "lc-bar-stack animate-lc-bar-in motion-reduce:animate-none",
|
|
3035
|
+
style: enterStyle,
|
|
3036
|
+
children: CATS.map((c) => {
|
|
3037
|
+
const v = req[c.key] || 0;
|
|
3038
|
+
if (!v) return null;
|
|
3039
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3040
|
+
"data-cat": c.key,
|
|
3041
|
+
className: "lc-cat-seg",
|
|
3042
|
+
style: {
|
|
3043
|
+
height: `${Math.max(1, Math.round(v / props.maxTotal * CHART_H))}px`,
|
|
3044
|
+
background: c.color
|
|
3045
|
+
}
|
|
3046
|
+
}, c.key);
|
|
3047
|
+
})
|
|
3019
3048
|
})
|
|
3020
|
-
|
|
3049
|
+
]
|
|
3021
3050
|
});
|
|
3022
3051
|
});
|
|
3023
3052
|
return function TrendChart(props) {
|
|
@@ -3371,6 +3400,7 @@ window.__ModuleLoader__.load({
|
|
|
3371
3400
|
selected: props.selectedSeq === req.seq,
|
|
3372
3401
|
hovered: props.hoveredSeq === req.seq,
|
|
3373
3402
|
inTurn: props.activeTurn !== null && (req.turn ?? 0) === props.activeTurn,
|
|
3403
|
+
flag: props.granularity === "step" && (i + 1) % STEP_FLAG_EVERY === 0 ? i + 1 : null,
|
|
3374
3404
|
maxTotal,
|
|
3375
3405
|
upPx: delta ? upPx : void 0,
|
|
3376
3406
|
downPx: delta ? downPx : void 0,
|
|
@@ -5489,11 +5519,14 @@ window.__ModuleLoader__.load({
|
|
|
5489
5519
|
* The provider-id seam between dsh request envelopes and the models.dev
|
|
5490
5520
|
* registry: client/cost.ts resolves price-book branches through it, and
|
|
5491
5521
|
* host/fold.ts uses the DeepSeek resolution to split the session-cost totals
|
|
5492
|
-
* into peak/off-peak periods. Only the renames live here —
|
|
5493
|
-
*
|
|
5522
|
+
* into peak/off-peak periods. Only the renames live here — a dsh route key
|
|
5523
|
+
* that is not a registry id (user-declared gateways, `claude`/`codex`
|
|
5524
|
+
* subscriptions, org-prefixed catalogs) passes through and prices through
|
|
5525
|
+
* the model-side resolution index instead (client/cost.ts).
|
|
5494
5526
|
*/
|
|
5495
5527
|
const MODELS_DEV_PROVIDER_IDS = {
|
|
5496
5528
|
"deepseek-official": "deepseek",
|
|
5529
|
+
"deepseek-account": "deepseek",
|
|
5497
5530
|
"kimi-coding": "moonshotai",
|
|
5498
5531
|
"minimax-cn": "minimax",
|
|
5499
5532
|
"zai-coding-cn": "zhipuai"
|
|
@@ -5516,6 +5549,120 @@ window.__ModuleLoader__.load({
|
|
|
5516
5549
|
function toCurrency(usd, currency) {
|
|
5517
5550
|
return currency === "cny" ? usd / USD_PER_CNY : usd;
|
|
5518
5551
|
}
|
|
5552
|
+
/** Rate equality within the registry's float noise (sync drift prints 0.125000…003). */
|
|
5553
|
+
function sameRate(a, b) {
|
|
5554
|
+
const close = (x, y) => Math.abs(x - y) <= 1e-9 * Math.max(1, Math.abs(x));
|
|
5555
|
+
return close(a.hit, b.hit) && close(a.miss, b.miss) && close(a.write, b.write) && close(a.out, b.out);
|
|
5556
|
+
}
|
|
5557
|
+
/** One proven candidate rate off a built book branch, or null. */
|
|
5558
|
+
function rateOfEntry(value) {
|
|
5559
|
+
const v = value;
|
|
5560
|
+
if (v === null || typeof v !== "object") return null;
|
|
5561
|
+
const r = v;
|
|
5562
|
+
const num = (x) => typeof x === "number" && Number.isFinite(x);
|
|
5563
|
+
return num(r.hit) && num(r.miss) && num(r.write) && num(r.out) ? {
|
|
5564
|
+
hit: r.hit,
|
|
5565
|
+
miss: r.miss,
|
|
5566
|
+
write: r.write,
|
|
5567
|
+
out: r.out
|
|
5568
|
+
} : null;
|
|
5569
|
+
}
|
|
5570
|
+
/**
|
|
5571
|
+
* Build the resolution index over a proven book. `npmOf` carries each
|
|
5572
|
+
* provider's registry `npm` package (null when absent) — the vendor signal:
|
|
5573
|
+
* a provider whose package is `@ai-sdk/<its own id>` is the model's first
|
|
5574
|
+
* party, while mirrors and gateways ride `@ai-sdk/openai-compatible` or
|
|
5575
|
+
* someone else's package. Suffix tails are indexed alongside exact ids so a
|
|
5576
|
+
* short dsh spelling (`k3`) resolves book-wide too.
|
|
5577
|
+
*/
|
|
5578
|
+
function priceIndexOf(prices, npmOf) {
|
|
5579
|
+
const byModel = /* @__PURE__ */ new Map();
|
|
5580
|
+
const push = (key, cand) => {
|
|
5581
|
+
const list = byModel.get(key);
|
|
5582
|
+
if (list === void 0) byModel.set(key, [cand]);
|
|
5583
|
+
else if (!list.some((c) => c.pid === cand.pid && sameRate(c.rate, cand.rate))) list.push(cand);
|
|
5584
|
+
};
|
|
5585
|
+
for (const pid of Object.keys(prices)) {
|
|
5586
|
+
const branch = branchOf(prices, pid);
|
|
5587
|
+
if (branch === null) continue;
|
|
5588
|
+
const npm = npmOf[pid];
|
|
5589
|
+
const primary = typeof npm === "string" && npm.startsWith("@ai-sdk/") && npm.slice(8) === pid;
|
|
5590
|
+
for (const mid of Object.keys(branch)) {
|
|
5591
|
+
const rate = rateOfEntry(branch[mid]);
|
|
5592
|
+
if (rate === null) continue;
|
|
5593
|
+
const lower = mid.toLowerCase();
|
|
5594
|
+
const cand = {
|
|
5595
|
+
pid,
|
|
5596
|
+
rate,
|
|
5597
|
+
primary
|
|
5598
|
+
};
|
|
5599
|
+
push(lower, cand);
|
|
5600
|
+
const parts = lower.split("-");
|
|
5601
|
+
for (let i = 1; i < parts.length; i++) push(parts.slice(i).join("-"), cand);
|
|
5602
|
+
}
|
|
5603
|
+
}
|
|
5604
|
+
return { byModel };
|
|
5605
|
+
}
|
|
5606
|
+
/**
|
|
5607
|
+
* The rate shared by a candidate group, or null: the largest equal-rate
|
|
5608
|
+
* group wins, a tie refuses. Agreeing mirrors are noise; disagreeing ones
|
|
5609
|
+
* price nothing rather than guess.
|
|
5610
|
+
*/
|
|
5611
|
+
function majorityRate(cands) {
|
|
5612
|
+
const groups = [];
|
|
5613
|
+
for (const c of cands) {
|
|
5614
|
+
const g = groups.find((g) => sameRate(g.rate, c.rate));
|
|
5615
|
+
if (g === void 0) groups.push({
|
|
5616
|
+
rate: c.rate,
|
|
5617
|
+
n: 1
|
|
5618
|
+
});
|
|
5619
|
+
else g.n++;
|
|
5620
|
+
}
|
|
5621
|
+
groups.sort((a, b) => b.n - a.n);
|
|
5622
|
+
return groups.length > 1 && groups[0].n === groups[1].n ? null : groups[0].rate;
|
|
5623
|
+
}
|
|
5624
|
+
/**
|
|
5625
|
+
* Pick one candidate group's rate: the model's own vendor (unique or
|
|
5626
|
+
* unanimous), then a provider the model id itself names (`deepseek-v4-flash`
|
|
5627
|
+
* under `deepseek`), then a lone carrier. Everything else prices null.
|
|
5628
|
+
*/
|
|
5629
|
+
function resolveCandidates(lower, cands, org) {
|
|
5630
|
+
if (org !== null) {
|
|
5631
|
+
const named = cands.filter((c) => c.pid === org || org.startsWith(c.pid + "-") || org.length >= 4 && org.startsWith(c.pid));
|
|
5632
|
+
if (named.length > 0) {
|
|
5633
|
+
const rate = majorityRate(named);
|
|
5634
|
+
if (rate !== null) return rate;
|
|
5635
|
+
}
|
|
5636
|
+
}
|
|
5637
|
+
const primaries = cands.filter((c) => c.primary);
|
|
5638
|
+
if (primaries.length > 0) {
|
|
5639
|
+
const rate = majorityRate(primaries);
|
|
5640
|
+
if (rate !== null) return rate;
|
|
5641
|
+
}
|
|
5642
|
+
const prefixed = cands.filter((c) => lower.startsWith(c.pid + "-") || lower.startsWith(c.pid + "/"));
|
|
5643
|
+
if (prefixed.length > 0) {
|
|
5644
|
+
const rate = majorityRate(prefixed);
|
|
5645
|
+
if (rate !== null) return rate;
|
|
5646
|
+
}
|
|
5647
|
+
return cands.length === 1 ? cands[0].rate : null;
|
|
5648
|
+
}
|
|
5649
|
+
/**
|
|
5650
|
+
* Resolve a model id book-wide: the full id first, then its last `/`-segment
|
|
5651
|
+
* (an org-prefixed dialect whose exact spelling no registry provider lists).
|
|
5652
|
+
* Null when every tier refuses.
|
|
5653
|
+
*/
|
|
5654
|
+
function resolveRate(index, model) {
|
|
5655
|
+
const lower = model.toLowerCase();
|
|
5656
|
+
const slash = lower.lastIndexOf("/");
|
|
5657
|
+
const org = slash > 0 ? lower.slice(0, slash) : null;
|
|
5658
|
+
for (const key of slash > 0 ? [lower, lower.slice(slash + 1)] : [lower]) {
|
|
5659
|
+
const cands = index.byModel.get(key);
|
|
5660
|
+
if (cands === void 0) continue;
|
|
5661
|
+
const rate = resolveCandidates(key, cands, org);
|
|
5662
|
+
if (rate !== null) return rate;
|
|
5663
|
+
}
|
|
5664
|
+
return null;
|
|
5665
|
+
}
|
|
5519
5666
|
/** One rate triple at the doubled peak rate (the tooltip's `peak | off` pair). */
|
|
5520
5667
|
function peakOf(rate) {
|
|
5521
5668
|
return {
|
|
@@ -5555,22 +5702,16 @@ window.__ModuleLoader__.load({
|
|
|
5555
5702
|
* The book's rates for one folded (provider, model) bucket, or null when
|
|
5556
5703
|
* the book cannot price it: the dsh provider id resolves through
|
|
5557
5704
|
* modelsDevProviderOf (unmapped ids pass through) and prices by model id —
|
|
5558
|
-
* exact, case-insensitive, or suffix
|
|
5559
|
-
* falls back to
|
|
5560
|
-
*
|
|
5561
|
-
|
|
5562
|
-
|
|
5563
|
-
|
|
5564
|
-
|
|
5705
|
+
* exact, case-insensitive, or suffix. A provider the book does not carry
|
|
5706
|
+
* falls back to the model-side resolution index, which names the vendor
|
|
5707
|
+
* from data (org segment, own-vendor SDK, id prefix, lone carrier) — never
|
|
5708
|
+
* from a per-model hardcode.
|
|
5709
|
+
*/
|
|
5710
|
+
function priceOf(book, provider, model) {
|
|
5711
|
+
if (book === null || book === void 0) return null;
|
|
5712
|
+
const direct = branchOf(book.prices, modelsDevProviderOf(provider));
|
|
5565
5713
|
if (direct !== null) return lookup(direct, model);
|
|
5566
|
-
|
|
5567
|
-
for (const models of Object.values(prices)) {
|
|
5568
|
-
const rate = lookup(models, model);
|
|
5569
|
-
if (rate === null) continue;
|
|
5570
|
-
if (found !== null) return null;
|
|
5571
|
-
found = rate;
|
|
5572
|
-
}
|
|
5573
|
-
return found;
|
|
5714
|
+
return resolveRate(book.index, model);
|
|
5574
5715
|
}
|
|
5575
5716
|
/**
|
|
5576
5717
|
* Price the session's cumulative billed-token totals. Cache reads bill at
|
|
@@ -5581,8 +5722,8 @@ window.__ModuleLoader__.load({
|
|
|
5581
5722
|
* Null when nothing was priced (no usage folded, no book yet, or no model
|
|
5582
5723
|
* the book prices), so the cell can show a dash.
|
|
5583
5724
|
*/
|
|
5584
|
-
function estimateSessionCost(usage,
|
|
5585
|
-
if (usage === null || usage === void 0 ||
|
|
5725
|
+
function estimateSessionCost(usage, book, currency) {
|
|
5726
|
+
if (usage === null || usage === void 0 || book === null || book === void 0) return null;
|
|
5586
5727
|
let total = 0;
|
|
5587
5728
|
let any = false;
|
|
5588
5729
|
for (const provider of Object.keys(usage)) {
|
|
@@ -5590,7 +5731,7 @@ window.__ModuleLoader__.load({
|
|
|
5590
5731
|
if (models === null) continue;
|
|
5591
5732
|
const deepseek = isDeepSeekProvider(provider);
|
|
5592
5733
|
for (const model of Object.keys(models)) {
|
|
5593
|
-
const rate = priceOf(
|
|
5734
|
+
const rate = priceOf(book, provider, model);
|
|
5594
5735
|
const periods = asRecord(models[model]);
|
|
5595
5736
|
if (rate === null || periods === null) continue;
|
|
5596
5737
|
for (const period of ["peak", "off"]) {
|
|
@@ -5662,7 +5803,7 @@ window.__ModuleLoader__.load({
|
|
|
5662
5803
|
return formatCost(amount, currency).replace(/0+$/, "").replace(/\.$/, "");
|
|
5663
5804
|
}
|
|
5664
5805
|
//#endregion
|
|
5665
|
-
//#region node_modules/.pnpm/@opencode-ai+models@0.0.
|
|
5806
|
+
//#region node_modules/.pnpm/@opencode-ai+models@0.0.87/node_modules/@opencode-ai/models/dist/error.js
|
|
5666
5807
|
/**
|
|
5667
5808
|
* The only error thrown by the models.dev client.
|
|
5668
5809
|
*
|
|
@@ -5679,7 +5820,7 @@ window.__ModuleLoader__.load({
|
|
|
5679
5820
|
}
|
|
5680
5821
|
};
|
|
5681
5822
|
//#endregion
|
|
5682
|
-
//#region node_modules/.pnpm/@opencode-ai+models@0.0.
|
|
5823
|
+
//#region node_modules/.pnpm/@opencode-ai+models@0.0.87/node_modules/@opencode-ai/models/dist/client.js
|
|
5683
5824
|
/**
|
|
5684
5825
|
* Creates a stateless models.dev client. Every method performs exactly one
|
|
5685
5826
|
* `GET` and nothing is ever cached — callers who want caching should wrap
|
|
@@ -5696,7 +5837,11 @@ window.__ModuleLoader__.load({
|
|
|
5696
5837
|
for (const [key, value] of new Headers(requestOptions?.headers)) headers.set(key, value);
|
|
5697
5838
|
let response;
|
|
5698
5839
|
try {
|
|
5699
|
-
|
|
5840
|
+
const url = new URL(path, base);
|
|
5841
|
+
const modelTypes = requestOptions?.modelTypes;
|
|
5842
|
+
if (modelTypes === "all") url.searchParams.set("type", "all");
|
|
5843
|
+
else if (modelTypes && modelTypes.length > 0) url.searchParams.set("type", modelTypes.join(","));
|
|
5844
|
+
response = await fetch(url, {
|
|
5700
5845
|
method: "GET",
|
|
5701
5846
|
headers,
|
|
5702
5847
|
signal: requestOptions?.signal
|
|
@@ -5741,10 +5886,12 @@ window.__ModuleLoader__.load({
|
|
|
5741
5886
|
* re-proves every field at the boundary — a non-conforming provider/model/
|
|
5742
5887
|
* cost entry drops whole. The book keeps EVERY provider that prices (keyed
|
|
5743
5888
|
* by the registry's own provider id), so a dsh provider id outside the
|
|
5744
|
-
* rename table still prices by direct passthrough
|
|
5745
|
-
*
|
|
5746
|
-
*
|
|
5747
|
-
*
|
|
5889
|
+
* rename table still prices by direct passthrough, and carries each
|
|
5890
|
+
* provider's `npm` package into the model-side resolution index
|
|
5891
|
+
* (cost.ts `priceIndexOf`) so unknown provider ids price by model id alone.
|
|
5892
|
+
* One fetch per page load, kicked on first subscribe; a failure degrades to
|
|
5893
|
+
* a visible state the cost cell notes, with a backed-off automatic retry —
|
|
5894
|
+
* never a spinner, and never an unhandled rejection.
|
|
5748
5895
|
*/
|
|
5749
5896
|
/** One finite non-negative registry figure, or null. */
|
|
5750
5897
|
function rateOf(value) {
|
|
@@ -5752,18 +5899,23 @@ window.__ModuleLoader__.load({
|
|
|
5752
5899
|
}
|
|
5753
5900
|
/**
|
|
5754
5901
|
* Extract the whole registry's per-model USD rates from a delivered
|
|
5755
|
-
* providers payload (`/api.json`), keyed by the registry's provider ids
|
|
5756
|
-
*
|
|
5757
|
-
*
|
|
5902
|
+
* providers payload (`/api.json`), keyed by the registry's provider ids,
|
|
5903
|
+
* with the resolution index built over it. Any shape failure skips just
|
|
5904
|
+
* that entry; a payload that is not a record at all returns null (the store
|
|
5905
|
+
* treats it as a failed fetch and retries).
|
|
5758
5906
|
*/
|
|
5759
5907
|
function pricesBookOf(value) {
|
|
5760
5908
|
const data = asRecord(value);
|
|
5761
5909
|
if (data === null || Array.isArray(data)) return null;
|
|
5762
5910
|
const book = {};
|
|
5911
|
+
const npmOf = {};
|
|
5763
5912
|
for (const providerId of Object.keys(data)) {
|
|
5764
5913
|
const provider = asRecord(data[providerId]);
|
|
5765
|
-
|
|
5914
|
+
if (provider === null) continue;
|
|
5915
|
+
const modelList = asRecord(provider.models);
|
|
5766
5916
|
if (modelList === null) continue;
|
|
5917
|
+
const npm = provider.npm;
|
|
5918
|
+
npmOf[providerId] = typeof npm === "string" ? npm : null;
|
|
5767
5919
|
const models = {};
|
|
5768
5920
|
for (const id of Object.keys(modelList)) {
|
|
5769
5921
|
const model = asRecord(modelList[id]);
|
|
@@ -5781,14 +5933,17 @@ window.__ModuleLoader__.load({
|
|
|
5781
5933
|
}
|
|
5782
5934
|
if (Object.keys(models).length > 0) book[providerId] = models;
|
|
5783
5935
|
}
|
|
5784
|
-
return
|
|
5936
|
+
return {
|
|
5937
|
+
prices: book,
|
|
5938
|
+
index: priceIndexOf(book, npmOf)
|
|
5939
|
+
};
|
|
5785
5940
|
}
|
|
5786
5941
|
const defaultLoader = () => make().providers();
|
|
5787
5942
|
/** The retry backoff base; each consecutive failure doubles the wait, capped at 3 doublings. */
|
|
5788
5943
|
const RETRY_BASE_MS = 3e4;
|
|
5789
5944
|
let loader = defaultLoader;
|
|
5790
5945
|
let snap = {
|
|
5791
|
-
|
|
5946
|
+
book: null,
|
|
5792
5947
|
failed: false
|
|
5793
5948
|
};
|
|
5794
5949
|
let inFlight = false;
|
|
@@ -5812,7 +5967,7 @@ window.__ModuleLoader__.load({
|
|
|
5812
5967
|
const book = pricesBookOf(await loader());
|
|
5813
5968
|
if (book !== null) {
|
|
5814
5969
|
snap = {
|
|
5815
|
-
|
|
5970
|
+
book,
|
|
5816
5971
|
failed: false
|
|
5817
5972
|
};
|
|
5818
5973
|
failures = 0;
|
|
@@ -5824,7 +5979,7 @@ window.__ModuleLoader__.load({
|
|
|
5824
5979
|
for (const fn of listeners) fn();
|
|
5825
5980
|
}
|
|
5826
5981
|
function kick() {
|
|
5827
|
-
if (snap.
|
|
5982
|
+
if (snap.book !== null || inFlight || timer !== null) return;
|
|
5828
5983
|
fire();
|
|
5829
5984
|
}
|
|
5830
5985
|
/** The useSyncExternalStore seam: subscribing also kicks the first fetch. */
|
|
@@ -6307,7 +6462,7 @@ window.__ModuleLoader__.load({
|
|
|
6307
6462
|
total
|
|
6308
6463
|
};
|
|
6309
6464
|
}
|
|
6310
|
-
function kpisOf(rows, listed,
|
|
6465
|
+
function kpisOf(rows, listed, book, currency) {
|
|
6311
6466
|
const usage = mergeCostUsage(...rows.map((row) => row.timeline?.cost));
|
|
6312
6467
|
const totals = usageTotalsOf(usage);
|
|
6313
6468
|
let turns = 0;
|
|
@@ -6319,7 +6474,7 @@ window.__ModuleLoader__.load({
|
|
|
6319
6474
|
let usageSessions = 0;
|
|
6320
6475
|
for (const row of rows) {
|
|
6321
6476
|
const cost = row.timeline?.cost;
|
|
6322
|
-
if (estimateSessionCost(cost,
|
|
6477
|
+
if (estimateSessionCost(cost, book, currency) !== null) costSessions++;
|
|
6323
6478
|
if (usageTotalsOf(cost) !== null) usageSessions++;
|
|
6324
6479
|
turns += turnsOf(row.timeline);
|
|
6325
6480
|
const timing = row.timeline?.timing;
|
|
@@ -6333,7 +6488,7 @@ window.__ModuleLoader__.load({
|
|
|
6333
6488
|
listed,
|
|
6334
6489
|
tokens: totals?.total ?? 0,
|
|
6335
6490
|
turns,
|
|
6336
|
-
cost: estimateSessionCost(usage,
|
|
6491
|
+
cost: estimateSessionCost(usage, book, currency),
|
|
6337
6492
|
costSessions,
|
|
6338
6493
|
cacheHit: totals === null ? null : cacheHitPercent(totals.cacheRead, totals.input + totals.cacheRead + totals.cacheWrite),
|
|
6339
6494
|
usageSessions,
|
|
@@ -6346,33 +6501,44 @@ window.__ModuleLoader__.load({
|
|
|
6346
6501
|
};
|
|
6347
6502
|
}
|
|
6348
6503
|
/**
|
|
6349
|
-
* Merge every row's daily ledger into one — the heatmap's
|
|
6350
|
-
* counts toward a day only when its own entry
|
|
6351
|
-
* the day filter's predicate, so the cell's
|
|
6352
|
-
* zeroed entry is skipped whole.
|
|
6353
|
-
*
|
|
6504
|
+
* Merge every row's daily ledger into one — the heatmap's and the usage
|
|
6505
|
+
* chart's data. A session counts toward a day only when its own entry
|
|
6506
|
+
* carries activity, mirroring the day filter's predicate, so the cell's
|
|
6507
|
+
* tooltip previews the click; a zeroed entry is skipped whole. Each day's
|
|
6508
|
+
* pricing records merge into one SessionCostUsage and price off the SAME
|
|
6509
|
+
* book/estimator the KPI band's cost cell rides (null fee on anything
|
|
6510
|
+
* unpriced). The merged record stays small even over long histories.
|
|
6354
6511
|
*/
|
|
6355
|
-
function aggregateDays(rows) {
|
|
6356
|
-
const
|
|
6357
|
-
const byKey =
|
|
6512
|
+
function aggregateDays(rows, book, currency) {
|
|
6513
|
+
const merged = {};
|
|
6514
|
+
const byKey = merged;
|
|
6358
6515
|
for (const row of rows) {
|
|
6359
6516
|
if (row.activity === null) continue;
|
|
6360
6517
|
for (const key of Object.keys(row.activity.days)) {
|
|
6361
6518
|
const entry = row.activity.days[key];
|
|
6362
6519
|
if (entry.tokens <= 0 && entry.requests <= 0) continue;
|
|
6363
6520
|
const prev = byKey[key];
|
|
6364
|
-
if (prev === void 0)
|
|
6521
|
+
if (prev === void 0) merged[key] = {
|
|
6365
6522
|
tokens: entry.tokens,
|
|
6366
6523
|
requests: entry.requests,
|
|
6367
|
-
sessions: 1
|
|
6524
|
+
sessions: 1,
|
|
6525
|
+
fees: entry.cost !== void 0 ? [entry.cost] : []
|
|
6368
6526
|
};
|
|
6369
6527
|
else {
|
|
6370
6528
|
prev.tokens += entry.tokens;
|
|
6371
6529
|
prev.requests += entry.requests;
|
|
6372
6530
|
prev.sessions++;
|
|
6531
|
+
if (entry.cost !== void 0) prev.fees.push(entry.cost);
|
|
6373
6532
|
}
|
|
6374
6533
|
}
|
|
6375
6534
|
}
|
|
6535
|
+
const days = {};
|
|
6536
|
+
for (const [key, day] of Object.entries(merged)) days[key] = {
|
|
6537
|
+
tokens: day.tokens,
|
|
6538
|
+
requests: day.requests,
|
|
6539
|
+
sessions: day.sessions,
|
|
6540
|
+
cost: estimateSessionCost(mergeCostUsage(...day.fees), book, currency)
|
|
6541
|
+
};
|
|
6376
6542
|
return days;
|
|
6377
6543
|
}
|
|
6378
6544
|
/**
|
|
@@ -7151,6 +7317,166 @@ window.__ModuleLoader__.load({
|
|
|
7151
7317
|
};
|
|
7152
7318
|
}
|
|
7153
7319
|
//#endregion
|
|
7320
|
+
//#region src/client/components/overviewUsage.tsx
|
|
7321
|
+
/**
|
|
7322
|
+
* The Context Insights panel's first-row usage chart — the RIGHT half of the
|
|
7323
|
+
* KPI row. Seven day columns ending today, each pairing two bars priced off
|
|
7324
|
+
* the merged daily ledger (overview.ts aggregateDays): billed TOKENS (the
|
|
7325
|
+
* heatmap's own blue) and the day's estimated COST (green). The fee rides
|
|
7326
|
+
* the same per-day pricing records the host fold books at each turn's
|
|
7327
|
+
* initiation, priced by the same book and estimator as the KPI band's cost
|
|
7328
|
+
* cell — never a whole session's spend dumped on the day it was last
|
|
7329
|
+
* active. The two series scale on their OWN window maxima (a $2 week must
|
|
7330
|
+
* not flatten under a 169M-token week), so each bar reads as a share of its
|
|
7331
|
+
* series' peak; the tooltip carries the exact figures. The window is fixed
|
|
7332
|
+
* to the last 7 days — the range selector above scopes the KPI figures, not
|
|
7333
|
+
* this calendar.
|
|
7334
|
+
*
|
|
7335
|
+
* The plot is framed like a chart: hairline gridlines at 0/25/50/75/100% of
|
|
7336
|
+
* each series' own peak, a solid baseline at 0, and a tick rail on each
|
|
7337
|
+
* side — TOKENS on the left, COST on the right, computed from the same
|
|
7338
|
+
* maxima the bars scale to. The cost rail reads '—' until some day actually
|
|
7339
|
+
* prices.
|
|
7340
|
+
*/
|
|
7341
|
+
/** The chart's window: today and the six days before it, oldest first. */
|
|
7342
|
+
function usageWindowOf(today) {
|
|
7343
|
+
const columns = [];
|
|
7344
|
+
for (let d = -6; d <= 0; d++) {
|
|
7345
|
+
const key = shiftDayKey(today, d);
|
|
7346
|
+
if (key === null) return [];
|
|
7347
|
+
columns.push(key);
|
|
7348
|
+
}
|
|
7349
|
+
return columns;
|
|
7350
|
+
}
|
|
7351
|
+
/** The shared gridline/tick positions, in percent of each series' peak. */
|
|
7352
|
+
const TICKS = [
|
|
7353
|
+
0,
|
|
7354
|
+
25,
|
|
7355
|
+
50,
|
|
7356
|
+
75,
|
|
7357
|
+
100
|
|
7358
|
+
];
|
|
7359
|
+
function makeOverviewUsage(kit) {
|
|
7360
|
+
const { t, fmt } = kit;
|
|
7361
|
+
return function OverviewUsage(props) {
|
|
7362
|
+
const window = usageWindowOf(props.today);
|
|
7363
|
+
const byKey = props.days;
|
|
7364
|
+
const columns = window.map((key) => ({
|
|
7365
|
+
key,
|
|
7366
|
+
entry: byKey[key]
|
|
7367
|
+
}));
|
|
7368
|
+
const empty = columns.every((c) => c.entry === void 0 || c.entry.tokens <= 0 && c.entry.cost === null);
|
|
7369
|
+
let maxTokens = 0;
|
|
7370
|
+
let maxCost = 0;
|
|
7371
|
+
for (const c of columns) {
|
|
7372
|
+
if (c.entry === void 0) continue;
|
|
7373
|
+
if (c.entry.tokens > maxTokens) maxTokens = c.entry.tokens;
|
|
7374
|
+
if (c.entry.cost !== null && c.entry.cost > maxCost) maxCost = c.entry.cost;
|
|
7375
|
+
}
|
|
7376
|
+
const heightOf = (value, max) => max <= 0 || value <= 0 ? "0%" : `${Math.max(4, Math.round(value / max * 100))}%`;
|
|
7377
|
+
const tickOf = (percent) => fmt(Math.round(maxTokens * percent / 100));
|
|
7378
|
+
const costTickOf = (percent) => {
|
|
7379
|
+
if (maxCost <= 0) return "—";
|
|
7380
|
+
return percent === 0 ? "0" : formatCost(maxCost * percent / 100, props.currency);
|
|
7381
|
+
};
|
|
7382
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7383
|
+
className: "lc-card lc-ov-usage",
|
|
7384
|
+
children: [
|
|
7385
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
7386
|
+
className: "lc-card-title",
|
|
7387
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
7388
|
+
className: "lc-card-title-text",
|
|
7389
|
+
children: t("ov.usage.title")
|
|
7390
|
+
})
|
|
7391
|
+
}),
|
|
7392
|
+
empty || window.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
7393
|
+
className: "lc-empty",
|
|
7394
|
+
children: t("ov.usage.empty")
|
|
7395
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7396
|
+
className: "lc-ov-usage-plot",
|
|
7397
|
+
role: "group",
|
|
7398
|
+
"aria-label": t("ov.usage.title"),
|
|
7399
|
+
children: [
|
|
7400
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
7401
|
+
className: "lc-ov-usage-rail lc-ov-usage-rail-l",
|
|
7402
|
+
"aria-hidden": "true",
|
|
7403
|
+
children: TICKS.map((p) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
7404
|
+
className: "lc-ov-usage-tick",
|
|
7405
|
+
style: { top: `${100 - p}%` },
|
|
7406
|
+
children: tickOf(p)
|
|
7407
|
+
}, p))
|
|
7408
|
+
}),
|
|
7409
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7410
|
+
className: "lc-ov-usage-grid",
|
|
7411
|
+
children: [TICKS.map((p) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
7412
|
+
className: "lc-ov-usage-line" + (p === 0 ? " lc-ov-usage-line-0" : ""),
|
|
7413
|
+
style: { bottom: `${p}%` },
|
|
7414
|
+
"aria-hidden": "true"
|
|
7415
|
+
}, p)), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
7416
|
+
className: "lc-ov-usage-cols",
|
|
7417
|
+
children: columns.map((c) => {
|
|
7418
|
+
const tokens = c.entry?.tokens ?? 0;
|
|
7419
|
+
const cost = c.entry?.cost ?? null;
|
|
7420
|
+
const label = `${c.key}\n${t("ov.usage.tokens")} ${fmt(tokens)}\n${t("ov.usage.costTip")} ${cost === null ? "—" : formatCost(cost, props.currency)}`;
|
|
7421
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
7422
|
+
label,
|
|
7423
|
+
side: "top",
|
|
7424
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
7425
|
+
className: "lc-ov-usage-col",
|
|
7426
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7427
|
+
className: "lc-ov-usage-bars",
|
|
7428
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
7429
|
+
className: "lc-ov-usage-bar lc-ov-usage-tokens",
|
|
7430
|
+
style: { height: heightOf(tokens, maxTokens) }
|
|
7431
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
7432
|
+
className: "lc-ov-usage-bar lc-ov-usage-cost",
|
|
7433
|
+
style: { height: cost === null ? "0%" : heightOf(cost, maxCost) }
|
|
7434
|
+
})]
|
|
7435
|
+
})
|
|
7436
|
+
})
|
|
7437
|
+
}, c.key);
|
|
7438
|
+
})
|
|
7439
|
+
})]
|
|
7440
|
+
}),
|
|
7441
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
7442
|
+
className: "lc-ov-usage-rail lc-ov-usage-rail-r",
|
|
7443
|
+
"aria-hidden": "true",
|
|
7444
|
+
children: TICKS.map((p) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
7445
|
+
className: "lc-ov-usage-tick",
|
|
7446
|
+
style: { top: `${100 - p}%` },
|
|
7447
|
+
children: costTickOf(p)
|
|
7448
|
+
}, p))
|
|
7449
|
+
})
|
|
7450
|
+
]
|
|
7451
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
7452
|
+
className: "lc-ov-usage-days",
|
|
7453
|
+
"aria-hidden": "true",
|
|
7454
|
+
children: columns.map((c) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
7455
|
+
className: "lc-ov-usage-day",
|
|
7456
|
+
children: c.key.slice(5)
|
|
7457
|
+
}, c.key))
|
|
7458
|
+
})] }),
|
|
7459
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7460
|
+
className: "lc-ov-usage-key",
|
|
7461
|
+
"aria-hidden": "true",
|
|
7462
|
+
children: [
|
|
7463
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: "lc-ov-usage-swatch lc-ov-usage-tokens" }),
|
|
7464
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
7465
|
+
className: "lc-ov-usage-key-label",
|
|
7466
|
+
children: t("ov.usage.tokens")
|
|
7467
|
+
}),
|
|
7468
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: "lc-ov-usage-swatch lc-ov-usage-cost" }),
|
|
7469
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
7470
|
+
className: "lc-ov-usage-key-label",
|
|
7471
|
+
children: t("ov.usage.cost")
|
|
7472
|
+
})
|
|
7473
|
+
]
|
|
7474
|
+
})
|
|
7475
|
+
]
|
|
7476
|
+
});
|
|
7477
|
+
};
|
|
7478
|
+
}
|
|
7479
|
+
//#endregion
|
|
7154
7480
|
//#region src/client/components/statsTiming.tsx
|
|
7155
7481
|
/**
|
|
7156
7482
|
* The Timing card: where the session's ACTIVE time went. The donut splits
|
|
@@ -7483,9 +7809,12 @@ window.__ModuleLoader__.load({
|
|
|
7483
7809
|
* projection values), so the panel draws every session's insight without
|
|
7484
7810
|
* opening one log.
|
|
7485
7811
|
*
|
|
7486
|
-
* The panel's first row is the KPI metrics band
|
|
7487
|
-
*
|
|
7488
|
-
*
|
|
7812
|
+
* The panel's first row is a 1:1 column pair: the KPI metrics band (the
|
|
7813
|
+
* range's six figures — sessions, billed tokens, cost, cache hit, tool
|
|
7814
|
+
* calls, active time — three per row) beside the last-7-days usage chart
|
|
7815
|
+
* (each day's billed tokens and estimated cost as a bar pair, folded off
|
|
7816
|
+
* the merged daily ledger). Below it, the aggregate stats row folds the
|
|
7817
|
+
* same range's
|
|
7489
7818
|
* sessions into the two donut cards the per-session Context tab opens with —
|
|
7490
7819
|
* Token Stats (the composition-split billed volume) and Timing Stats (the
|
|
7491
7820
|
* summed totals). The body is then a 3:7 column pair: the insight column (the
|
|
@@ -7516,6 +7845,7 @@ window.__ModuleLoader__.load({
|
|
|
7516
7845
|
const Donut = makeDonut(kit);
|
|
7517
7846
|
const OverviewTokens = makeOverviewTokens(kit, Donut);
|
|
7518
7847
|
const StatsTiming = makeStatsTiming(kit, Donut);
|
|
7848
|
+
const OverviewUsage = makeOverviewUsage(kit);
|
|
7519
7849
|
const ErrorBoundary = makeErrorBoundary(t);
|
|
7520
7850
|
/** The display currency follows the active locale (zh → CNY), read per render — the slot outlet re-renders on a locale switch. */
|
|
7521
7851
|
function activeCurrency() {
|
|
@@ -7524,7 +7854,7 @@ window.__ModuleLoader__.load({
|
|
|
7524
7854
|
}
|
|
7525
7855
|
function OverviewBody(props) {
|
|
7526
7856
|
const open = (0, react.useSyncExternalStore)(overviewStore.subscribe, overviewStore.getSnapshot);
|
|
7527
|
-
const {
|
|
7857
|
+
const { book } = useModelPrices();
|
|
7528
7858
|
const snapshot = sessionsSnapshotOf(props);
|
|
7529
7859
|
const wsSnapshot = workspacesSnapshotOf(props);
|
|
7530
7860
|
const [range, setRange] = (0, react.useState)("30d");
|
|
@@ -7576,8 +7906,8 @@ window.__ModuleLoader__.load({
|
|
|
7576
7906
|
}] : counts;
|
|
7577
7907
|
const visible = sortRows(group === null ? scoped : scoped.filter((row) => inGroup(row, group, groups)), sort);
|
|
7578
7908
|
const paged = pageOf(visible, page);
|
|
7579
|
-
const kpi = kpisOf(ranged, allRows.length,
|
|
7580
|
-
const days = aggregateDays(allRows);
|
|
7909
|
+
const kpi = kpisOf(ranged, allRows.length, book, currency);
|
|
7910
|
+
const days = aggregateDays(allRows, book, currency);
|
|
7581
7911
|
const openOne = (id) => {
|
|
7582
7912
|
openSessionVia(ctx, id);
|
|
7583
7913
|
overviewStore.set(false);
|
|
@@ -7626,298 +7956,311 @@ window.__ModuleLoader__.load({
|
|
|
7626
7956
|
}), rows === null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
7627
7957
|
className: "lc-empty",
|
|
7628
7958
|
children: t("ov.unavailable")
|
|
7629
|
-
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(
|
|
7630
|
-
|
|
7631
|
-
|
|
7632
|
-
|
|
7633
|
-
|
|
7634
|
-
|
|
7635
|
-
|
|
7636
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
7637
|
-
className: "lc-stat-label",
|
|
7638
|
-
children: t("ov.kpi.sessions")
|
|
7639
|
-
}),
|
|
7640
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
7641
|
-
className: "lc-stat-value",
|
|
7642
|
-
children: kpi.sessions
|
|
7643
|
-
}),
|
|
7644
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
7645
|
-
className: "lc-stat-sub",
|
|
7646
|
-
children: t("ov.kpi.ofTotal", { n: kpi.listed })
|
|
7647
|
-
})
|
|
7648
|
-
]
|
|
7649
|
-
}),
|
|
7650
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7651
|
-
className: "lc-stat lc-ov-kpi",
|
|
7959
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7960
|
+
className: "lc-ov-scroll",
|
|
7961
|
+
children: [
|
|
7962
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7963
|
+
className: "lc-ov-first",
|
|
7964
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7965
|
+
className: "lc-ov-kpis",
|
|
7652
7966
|
children: [
|
|
7653
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
7654
|
-
className: "lc-stat-
|
|
7655
|
-
children: t("ov.kpi.tokens")
|
|
7656
|
-
}),
|
|
7657
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
7658
|
-
className: "lc-stat-value",
|
|
7659
|
-
children: fmt(kpi.tokens)
|
|
7660
|
-
}),
|
|
7661
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
7662
|
-
className: "lc-stat-sub",
|
|
7967
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7968
|
+
className: "lc-stat lc-ov-kpi",
|
|
7663
7969
|
children: [
|
|
7664
|
-
|
|
7665
|
-
|
|
7666
|
-
|
|
7970
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
7971
|
+
className: "lc-stat-label",
|
|
7972
|
+
children: t("ov.kpi.sessions")
|
|
7973
|
+
}),
|
|
7974
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
7975
|
+
className: "lc-stat-value",
|
|
7976
|
+
children: kpi.sessions
|
|
7977
|
+
}),
|
|
7978
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
7979
|
+
className: "lc-stat-sub",
|
|
7980
|
+
children: t("ov.kpi.ofTotal", { n: kpi.listed })
|
|
7981
|
+
})
|
|
7667
7982
|
]
|
|
7668
|
-
})
|
|
7669
|
-
]
|
|
7670
|
-
}),
|
|
7671
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7672
|
-
className: "lc-stat lc-ov-kpi",
|
|
7673
|
-
children: [
|
|
7674
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
7675
|
-
className: "lc-stat-label",
|
|
7676
|
-
children: t("stats.cost")
|
|
7677
|
-
}),
|
|
7678
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
7679
|
-
className: "lc-stat-value",
|
|
7680
|
-
children: kpi.cost === null ? "—" : formatCost(kpi.cost, currency)
|
|
7681
|
-
}),
|
|
7682
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
7683
|
-
className: "lc-stat-sub",
|
|
7684
|
-
children: t("ov.kpi.sessionsSub", { n: kpi.costSessions })
|
|
7685
|
-
})
|
|
7686
|
-
]
|
|
7687
|
-
}),
|
|
7688
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7689
|
-
className: "lc-stat lc-ov-kpi",
|
|
7690
|
-
children: [
|
|
7691
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
7692
|
-
className: "lc-stat-label",
|
|
7693
|
-
children: t("stats.cacheHit")
|
|
7694
7983
|
}),
|
|
7695
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
7696
|
-
className: "lc-stat-
|
|
7697
|
-
children:
|
|
7698
|
-
|
|
7699
|
-
|
|
7700
|
-
|
|
7701
|
-
|
|
7702
|
-
|
|
7703
|
-
|
|
7704
|
-
|
|
7705
|
-
|
|
7706
|
-
|
|
7707
|
-
|
|
7708
|
-
|
|
7709
|
-
|
|
7710
|
-
|
|
7984
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7985
|
+
className: "lc-stat lc-ov-kpi",
|
|
7986
|
+
children: [
|
|
7987
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
7988
|
+
className: "lc-stat-label",
|
|
7989
|
+
children: t("ov.kpi.tokens")
|
|
7990
|
+
}),
|
|
7991
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
7992
|
+
className: "lc-stat-value",
|
|
7993
|
+
children: fmt(kpi.tokens)
|
|
7994
|
+
}),
|
|
7995
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
7996
|
+
className: "lc-stat-sub",
|
|
7997
|
+
children: [
|
|
7998
|
+
t("stats.turns"),
|
|
7999
|
+
" ",
|
|
8000
|
+
fmt(kpi.turns)
|
|
8001
|
+
]
|
|
8002
|
+
})
|
|
8003
|
+
]
|
|
7711
8004
|
}),
|
|
7712
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
7713
|
-
className: "lc-stat-
|
|
7714
|
-
children:
|
|
8005
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8006
|
+
className: "lc-stat lc-ov-kpi",
|
|
8007
|
+
children: [
|
|
8008
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8009
|
+
className: "lc-stat-label",
|
|
8010
|
+
children: t("stats.cost")
|
|
8011
|
+
}),
|
|
8012
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8013
|
+
className: "lc-stat-value",
|
|
8014
|
+
children: kpi.cost === null ? "—" : formatCost(kpi.cost, currency)
|
|
8015
|
+
}),
|
|
8016
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8017
|
+
className: "lc-stat-sub",
|
|
8018
|
+
children: t("ov.kpi.pricedSub", {
|
|
8019
|
+
n: kpi.costSessions,
|
|
8020
|
+
total: kpi.sessions
|
|
8021
|
+
})
|
|
8022
|
+
})
|
|
8023
|
+
]
|
|
7715
8024
|
}),
|
|
7716
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
7717
|
-
className: "lc-stat-
|
|
7718
|
-
children:
|
|
7719
|
-
|
|
7720
|
-
|
|
7721
|
-
|
|
7722
|
-
|
|
7723
|
-
|
|
7724
|
-
|
|
7725
|
-
|
|
7726
|
-
|
|
7727
|
-
|
|
8025
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8026
|
+
className: "lc-stat lc-ov-kpi",
|
|
8027
|
+
children: [
|
|
8028
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8029
|
+
className: "lc-stat-label",
|
|
8030
|
+
children: t("stats.cacheHit")
|
|
8031
|
+
}),
|
|
8032
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8033
|
+
className: "lc-stat-value",
|
|
8034
|
+
children: kpi.cacheHit === null ? "—" : kpi.cacheHit + "%"
|
|
8035
|
+
}),
|
|
8036
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8037
|
+
className: "lc-stat-sub",
|
|
8038
|
+
children: t("ov.kpi.sessionsSub", { n: kpi.usageSessions })
|
|
8039
|
+
})
|
|
8040
|
+
]
|
|
7728
8041
|
}),
|
|
7729
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
7730
|
-
className: "lc-stat-
|
|
7731
|
-
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.toolCalls")
|
|
8048
|
+
}),
|
|
8049
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8050
|
+
className: "lc-stat-value",
|
|
8051
|
+
children: fmt(kpi.toolCalls)
|
|
8052
|
+
}),
|
|
8053
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8054
|
+
className: "lc-stat-sub",
|
|
8055
|
+
children: t("ov.kpi.toolSub", { dur: fmtDuration(kpi.toolsMs) })
|
|
8056
|
+
})
|
|
8057
|
+
]
|
|
7732
8058
|
}),
|
|
7733
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
7734
|
-
className: "lc-stat-
|
|
7735
|
-
children:
|
|
8059
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8060
|
+
className: "lc-stat lc-ov-kpi",
|
|
8061
|
+
children: [
|
|
8062
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8063
|
+
className: "lc-stat-label",
|
|
8064
|
+
children: t("timing.total")
|
|
8065
|
+
}),
|
|
8066
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8067
|
+
className: "lc-stat-value",
|
|
8068
|
+
children: fmtDuration(kpi.wallMs)
|
|
8069
|
+
}),
|
|
8070
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8071
|
+
className: "lc-stat-sub",
|
|
8072
|
+
children: t("ov.kpi.wallSub", { n: fmt(kpi.calls) })
|
|
8073
|
+
})
|
|
8074
|
+
]
|
|
7736
8075
|
})
|
|
7737
8076
|
]
|
|
7738
|
-
})
|
|
7739
|
-
|
|
7740
|
-
|
|
7741
|
-
|
|
7742
|
-
|
|
7743
|
-
|
|
7744
|
-
|
|
7745
|
-
|
|
7746
|
-
|
|
7747
|
-
|
|
7748
|
-
|
|
8077
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(OverviewUsage, {
|
|
8078
|
+
days,
|
|
8079
|
+
currency,
|
|
8080
|
+
today: todayKey()
|
|
8081
|
+
})]
|
|
8082
|
+
}),
|
|
8083
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8084
|
+
className: "lc-ov-stats",
|
|
8085
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(OverviewTokens, { tokens: kpi.tokenParts }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StatsTiming, { timing: kpi.timing })]
|
|
8086
|
+
}),
|
|
8087
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8088
|
+
className: "lc-ov-body",
|
|
7749
8089
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7750
|
-
className: "lc-
|
|
8090
|
+
className: "lc-ov-left",
|
|
7751
8091
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7752
|
-
className: "lc-card-
|
|
7753
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.
|
|
7754
|
-
className: "lc-card-title
|
|
7755
|
-
children: t("ov.heat.title")
|
|
7756
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
7757
|
-
className: "lc-heat-ctl",
|
|
8092
|
+
className: "lc-card lc-ov-heat-card",
|
|
8093
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8094
|
+
className: "lc-card-title",
|
|
7758
8095
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
7759
|
-
className: "lc-card-
|
|
7760
|
-
children: t("ov.heat.
|
|
7761
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.
|
|
7762
|
-
className: "lc-
|
|
7763
|
-
|
|
7764
|
-
|
|
7765
|
-
|
|
7766
|
-
|
|
7767
|
-
className: "lc-gran
|
|
7768
|
-
|
|
7769
|
-
|
|
7770
|
-
|
|
7771
|
-
|
|
7772
|
-
|
|
8096
|
+
className: "lc-card-title-text",
|
|
8097
|
+
children: t("ov.heat.title")
|
|
8098
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
8099
|
+
className: "lc-heat-ctl",
|
|
8100
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8101
|
+
className: "lc-card-sub",
|
|
8102
|
+
children: t("ov.heat.sub")
|
|
8103
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8104
|
+
className: "lc-gran",
|
|
8105
|
+
role: "group",
|
|
8106
|
+
"aria-label": t("ov.heat.metric"),
|
|
8107
|
+
children: METRICS.map((m) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
8108
|
+
type: "button",
|
|
8109
|
+
className: "lc-gran-btn" + (metric === m ? " lc-gran-on" : ""),
|
|
8110
|
+
onClick: () => {
|
|
8111
|
+
setMetric(m);
|
|
8112
|
+
},
|
|
8113
|
+
children: t("ov.heat.metric." + m)
|
|
8114
|
+
}, m))
|
|
8115
|
+
})]
|
|
7773
8116
|
})]
|
|
8117
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Heatmap, {
|
|
8118
|
+
days,
|
|
8119
|
+
metric,
|
|
8120
|
+
selected: day,
|
|
8121
|
+
onSelect: setDay,
|
|
8122
|
+
today: todayKey()
|
|
8123
|
+
})]
|
|
8124
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
8125
|
+
type: "button",
|
|
8126
|
+
className: "lc-ov-settings",
|
|
8127
|
+
onClick: () => {
|
|
8128
|
+
openPluginSettings();
|
|
8129
|
+
close();
|
|
8130
|
+
},
|
|
8131
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
8132
|
+
className: "lc-ov-settings-label",
|
|
8133
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconSettings, { size: 14 }), t("plugin.settings")]
|
|
8134
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8135
|
+
className: "lc-ov-settings-hint",
|
|
8136
|
+
children: t("plugin.settingsOpen")
|
|
7774
8137
|
})]
|
|
7775
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Heatmap, {
|
|
7776
|
-
days,
|
|
7777
|
-
metric,
|
|
7778
|
-
selected: day,
|
|
7779
|
-
onSelect: setDay,
|
|
7780
|
-
today: todayKey()
|
|
7781
|
-
})]
|
|
7782
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
7783
|
-
type: "button",
|
|
7784
|
-
className: "lc-ov-settings",
|
|
7785
|
-
onClick: () => {
|
|
7786
|
-
openPluginSettings();
|
|
7787
|
-
close();
|
|
7788
|
-
},
|
|
7789
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
7790
|
-
className: "lc-ov-settings-label",
|
|
7791
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconSettings, { size: 14 }), t("plugin.settings")]
|
|
7792
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
7793
|
-
className: "lc-ov-settings-hint",
|
|
7794
|
-
children: t("plugin.settingsOpen")
|
|
7795
8138
|
})]
|
|
7796
|
-
})
|
|
7797
|
-
|
|
7798
|
-
|
|
7799
|
-
|
|
7800
|
-
|
|
7801
|
-
|
|
7802
|
-
|
|
7803
|
-
|
|
7804
|
-
|
|
7805
|
-
|
|
7806
|
-
|
|
7807
|
-
|
|
7808
|
-
|
|
7809
|
-
|
|
7810
|
-
|
|
7811
|
-
day !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
7812
|
-
type: "button",
|
|
7813
|
-
className: "lc-ov-day-chip",
|
|
7814
|
-
title: t("ov.list.dayClear"),
|
|
7815
|
-
onClick: () => {
|
|
7816
|
-
setDay(null);
|
|
7817
|
-
},
|
|
7818
|
-
children: [t("ov.list.dayFilter", { day }), " ×"]
|
|
7819
|
-
}),
|
|
7820
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
7821
|
-
className: "lc-ov-search",
|
|
7822
|
-
type: "search",
|
|
7823
|
-
value: query,
|
|
7824
|
-
placeholder: t("ov.list.search"),
|
|
7825
|
-
"aria-label": t("ov.list.search"),
|
|
7826
|
-
onChange: (ev) => {
|
|
7827
|
-
setQuery(ev.target.value);
|
|
7828
|
-
}
|
|
7829
|
-
}),
|
|
7830
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
7831
|
-
className: "lc-gran",
|
|
7832
|
-
role: "group",
|
|
7833
|
-
"aria-label": t("ov.list.sortLabel"),
|
|
7834
|
-
children: SORTS.map((s) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
8139
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8140
|
+
className: "lc-ov-right",
|
|
8141
|
+
children: [
|
|
8142
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8143
|
+
className: "lc-ov-list-head",
|
|
8144
|
+
children: [
|
|
8145
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8146
|
+
className: "lc-ov-list-title",
|
|
8147
|
+
children: t("ov.list.title")
|
|
8148
|
+
}),
|
|
8149
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8150
|
+
className: "lc-ov-list-count",
|
|
8151
|
+
children: visible.length
|
|
8152
|
+
}),
|
|
8153
|
+
day !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
7835
8154
|
type: "button",
|
|
7836
|
-
className: "lc-
|
|
8155
|
+
className: "lc-ov-day-chip",
|
|
8156
|
+
title: t("ov.list.dayClear"),
|
|
7837
8157
|
onClick: () => {
|
|
7838
|
-
|
|
8158
|
+
setDay(null);
|
|
7839
8159
|
},
|
|
7840
|
-
children: t("ov.list.
|
|
7841
|
-
},
|
|
7842
|
-
|
|
7843
|
-
|
|
7844
|
-
|
|
7845
|
-
|
|
7846
|
-
|
|
7847
|
-
|
|
7848
|
-
|
|
7849
|
-
|
|
7850
|
-
|
|
7851
|
-
|
|
7852
|
-
|
|
7853
|
-
|
|
7854
|
-
|
|
7855
|
-
|
|
7856
|
-
|
|
7857
|
-
|
|
7858
|
-
|
|
7859
|
-
|
|
7860
|
-
|
|
7861
|
-
|
|
7862
|
-
|
|
7863
|
-
|
|
7864
|
-
|
|
7865
|
-
|
|
7866
|
-
|
|
7867
|
-
|
|
7868
|
-
|
|
7869
|
-
|
|
7870
|
-
|
|
7871
|
-
|
|
7872
|
-
className: "lc-empty",
|
|
7873
|
-
children: t(allRows.length === 0 ? "ov.list.empty" : "ov.list.noMatch")
|
|
7874
|
-
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
7875
|
-
className: "lc-ov-grid",
|
|
7876
|
-
children: paged.items.map((row) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(OverviewCard, {
|
|
7877
|
-
row,
|
|
7878
|
-
...groups?.[row.id] !== void 0 ? { group: groups[row.id] } : {},
|
|
7879
|
-
costLabel: cardCostOf(row, prices, currency),
|
|
7880
|
-
now,
|
|
7881
|
-
onOpen: openOne
|
|
7882
|
-
}, row.id))
|
|
7883
|
-
}), paged.count > 1 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7884
|
-
className: "lc-ov-pager",
|
|
7885
|
-
role: "navigation",
|
|
7886
|
-
"aria-label": t("ov.list.pager"),
|
|
7887
|
-
children: [
|
|
7888
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
8160
|
+
children: [t("ov.list.dayFilter", { day }), " ×"]
|
|
8161
|
+
}),
|
|
8162
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
8163
|
+
className: "lc-ov-search",
|
|
8164
|
+
type: "search",
|
|
8165
|
+
value: query,
|
|
8166
|
+
placeholder: t("ov.list.search"),
|
|
8167
|
+
"aria-label": t("ov.list.search"),
|
|
8168
|
+
onChange: (ev) => {
|
|
8169
|
+
setQuery(ev.target.value);
|
|
8170
|
+
}
|
|
8171
|
+
}),
|
|
8172
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8173
|
+
className: "lc-gran",
|
|
8174
|
+
role: "group",
|
|
8175
|
+
"aria-label": t("ov.list.sortLabel"),
|
|
8176
|
+
children: SORTS.map((s) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
8177
|
+
type: "button",
|
|
8178
|
+
className: "lc-gran-btn" + (sort === s ? " lc-gran-on" : ""),
|
|
8179
|
+
onClick: () => {
|
|
8180
|
+
setSort(s);
|
|
8181
|
+
},
|
|
8182
|
+
children: t("ov.list.sort." + s)
|
|
8183
|
+
}, s))
|
|
8184
|
+
})
|
|
8185
|
+
]
|
|
8186
|
+
}),
|
|
8187
|
+
chips.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8188
|
+
className: "lc-ov-groups",
|
|
8189
|
+
role: "group",
|
|
8190
|
+
"aria-label": t("ov.group.label"),
|
|
8191
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
7889
8192
|
type: "button",
|
|
7890
|
-
className: "lc-ov-
|
|
7891
|
-
disabled: paged.index === 0,
|
|
7892
|
-
"aria-label": t("ov.list.prev"),
|
|
8193
|
+
className: "lc-ov-chip" + (group === null ? " lc-ov-chip-on" : ""),
|
|
7893
8194
|
onClick: () => {
|
|
7894
|
-
|
|
8195
|
+
setGroup(null);
|
|
7895
8196
|
},
|
|
7896
|
-
children: "
|
|
7897
|
-
|
|
7898
|
-
|
|
7899
|
-
|
|
7900
|
-
|
|
7901
|
-
n: paged.index + 1,
|
|
7902
|
-
total: paged.count
|
|
7903
|
-
})
|
|
7904
|
-
}),
|
|
7905
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
8197
|
+
children: [t("ov.range.all"), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8198
|
+
className: "lc-ov-chip-n",
|
|
8199
|
+
children: scoped.length
|
|
8200
|
+
})]
|
|
8201
|
+
}), chips.map((c) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
7906
8202
|
type: "button",
|
|
7907
|
-
className: "lc-ov-
|
|
7908
|
-
disabled: paged.index === paged.count - 1,
|
|
7909
|
-
"aria-label": t("ov.list.next"),
|
|
8203
|
+
className: "lc-ov-chip" + (group === c.key ? " lc-ov-chip-on" : ""),
|
|
7910
8204
|
onClick: () => {
|
|
7911
|
-
|
|
8205
|
+
setGroup(group === c.key ? null : c.key);
|
|
7912
8206
|
},
|
|
7913
|
-
children: "
|
|
7914
|
-
|
|
7915
|
-
|
|
7916
|
-
|
|
7917
|
-
|
|
7918
|
-
|
|
7919
|
-
|
|
7920
|
-
|
|
8207
|
+
children: [c.key === "__ungrouped__" ? t("ov.group.ungrouped") : c.key, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8208
|
+
className: "lc-ov-chip-n",
|
|
8209
|
+
children: c.count
|
|
8210
|
+
})]
|
|
8211
|
+
}, c.key))]
|
|
8212
|
+
}),
|
|
8213
|
+
visible.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8214
|
+
className: "lc-empty",
|
|
8215
|
+
children: t(allRows.length === 0 ? "ov.list.empty" : "ov.list.noMatch")
|
|
8216
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8217
|
+
className: "lc-ov-grid",
|
|
8218
|
+
children: paged.items.map((row) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(OverviewCard, {
|
|
8219
|
+
row,
|
|
8220
|
+
...groups?.[row.id] !== void 0 ? { group: groups[row.id] } : {},
|
|
8221
|
+
costLabel: cardCostOf(row, book, currency),
|
|
8222
|
+
now,
|
|
8223
|
+
onOpen: openOne
|
|
8224
|
+
}, row.id))
|
|
8225
|
+
}), paged.count > 1 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8226
|
+
className: "lc-ov-pager",
|
|
8227
|
+
role: "navigation",
|
|
8228
|
+
"aria-label": t("ov.list.pager"),
|
|
8229
|
+
children: [
|
|
8230
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
8231
|
+
type: "button",
|
|
8232
|
+
className: "lc-ov-pager-btn",
|
|
8233
|
+
disabled: paged.index === 0,
|
|
8234
|
+
"aria-label": t("ov.list.prev"),
|
|
8235
|
+
onClick: () => {
|
|
8236
|
+
setPage(paged.index - 1);
|
|
8237
|
+
},
|
|
8238
|
+
children: "‹"
|
|
8239
|
+
}),
|
|
8240
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8241
|
+
className: "lc-ov-pager-n",
|
|
8242
|
+
children: t("ov.list.page", {
|
|
8243
|
+
n: paged.index + 1,
|
|
8244
|
+
total: paged.count
|
|
8245
|
+
})
|
|
8246
|
+
}),
|
|
8247
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
8248
|
+
type: "button",
|
|
8249
|
+
className: "lc-ov-pager-btn",
|
|
8250
|
+
disabled: paged.index === paged.count - 1,
|
|
8251
|
+
"aria-label": t("ov.list.next"),
|
|
8252
|
+
onClick: () => {
|
|
8253
|
+
setPage(paged.index + 1);
|
|
8254
|
+
},
|
|
8255
|
+
children: "›"
|
|
8256
|
+
})
|
|
8257
|
+
]
|
|
8258
|
+
})] })
|
|
8259
|
+
]
|
|
8260
|
+
})]
|
|
8261
|
+
})
|
|
8262
|
+
]
|
|
8263
|
+
})]
|
|
7921
8264
|
})
|
|
7922
8265
|
});
|
|
7923
8266
|
}
|
|
@@ -7926,9 +8269,9 @@ window.__ModuleLoader__.load({
|
|
|
7926
8269
|
};
|
|
7927
8270
|
}
|
|
7928
8271
|
/** One card's priced cost label, or the dash (no book yet, nothing billed, unpriceable model). */
|
|
7929
|
-
function cardCostOf(row,
|
|
8272
|
+
function cardCostOf(row, book, currency) {
|
|
7930
8273
|
if (row.timeline?.cost === void 0) return "—";
|
|
7931
|
-
const cost = estimateSessionCost(row.timeline.cost,
|
|
8274
|
+
const cost = estimateSessionCost(row.timeline.cost, book, currency);
|
|
7932
8275
|
return cost === null ? "—" : formatCost(cost, currency);
|
|
7933
8276
|
}
|
|
7934
8277
|
//#endregion
|
|
@@ -10296,7 +10639,7 @@ window.__ModuleLoader__.load({
|
|
|
10296
10639
|
});
|
|
10297
10640
|
}
|
|
10298
10641
|
//#endregion
|
|
10299
|
-
//#region node_modules/.pnpm/simple-icons@16.
|
|
10642
|
+
//#region node_modules/.pnpm/simple-icons@16.32.0/node_modules/simple-icons/index.mjs
|
|
10300
10643
|
const c = "<svg role=\"img\" viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\"><title>";
|
|
10301
10644
|
const t = "</title><path d=\"";
|
|
10302
10645
|
const a = "\"/></svg>";
|
|
@@ -10404,7 +10747,7 @@ window.__ModuleLoader__.load({
|
|
|
10404
10747
|
return function PluginInfo() {
|
|
10405
10748
|
const [latest, setLatest] = (0, react.useState)(null);
|
|
10406
10749
|
(0, react.useEffect)(() => {
|
|
10407
|
-
if ("0.
|
|
10750
|
+
if ("0.59.0".includes("-dev")) return;
|
|
10408
10751
|
let on = true;
|
|
10409
10752
|
fetchLatestVersion().then((v) => {
|
|
10410
10753
|
if (on && v) setLatest(v);
|
|
@@ -10413,8 +10756,8 @@ window.__ModuleLoader__.load({
|
|
|
10413
10756
|
on = false;
|
|
10414
10757
|
};
|
|
10415
10758
|
}, []);
|
|
10416
|
-
const update = latest !== null && isNewerVersion(latest, "0.
|
|
10417
|
-
const nameText = "dsh-context (v0.
|
|
10759
|
+
const update = latest !== null && isNewerVersion(latest, "0.59.0") ? latest : null;
|
|
10760
|
+
const nameText = "dsh-context (v0.59.0)";
|
|
10418
10761
|
const nameValue = [nameText];
|
|
10419
10762
|
if (update) nameValue.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
10420
10763
|
className: "lc-pi-update",
|
|
@@ -10887,8 +11230,8 @@ window.__ModuleLoader__.load({
|
|
|
10887
11230
|
* with an off-peak bucket (DeepSeek's period-based list) shows the
|
|
10888
11231
|
* peak | off-peak pair.
|
|
10889
11232
|
*/
|
|
10890
|
-
function priceRowsOf(usage,
|
|
10891
|
-
if (usage === void 0 ||
|
|
11233
|
+
function priceRowsOf(usage, book) {
|
|
11234
|
+
if (usage === void 0 || book === null) return [];
|
|
10892
11235
|
const rows = [];
|
|
10893
11236
|
const multi = Object.keys(usage).length > 1;
|
|
10894
11237
|
for (const provider of Object.keys(usage)) {
|
|
@@ -10898,7 +11241,7 @@ window.__ModuleLoader__.load({
|
|
|
10898
11241
|
reaches here; the guard stays for the helper's own contract. */
|
|
10899
11242
|
if (models === null) continue;
|
|
10900
11243
|
for (const model of Object.keys(models)) {
|
|
10901
|
-
const rate = priceOf(
|
|
11244
|
+
const rate = priceOf(book, provider, model);
|
|
10902
11245
|
if (rate === null) continue;
|
|
10903
11246
|
const periods = asRecord(models[model]);
|
|
10904
11247
|
const deepseek = isDeepSeekProvider(provider);
|
|
@@ -10964,18 +11307,18 @@ window.__ModuleLoader__.load({
|
|
|
10964
11307
|
const { t, fmt } = kit;
|
|
10965
11308
|
return function StatsContext(props) {
|
|
10966
11309
|
const currency = props.locale === "zh" ? "cny" : "usd";
|
|
10967
|
-
const {
|
|
11310
|
+
const { book, failed } = useModelPrices();
|
|
10968
11311
|
const subUsage = useSubagentCost(props.sessionId);
|
|
10969
11312
|
const usage = mergeCostUsage(props.cost, subUsage) ?? void 0;
|
|
10970
|
-
const cost = estimateSessionCost(usage,
|
|
10971
|
-
const subCost = estimateSessionCost(subUsage,
|
|
11313
|
+
const cost = estimateSessionCost(usage, book, currency);
|
|
11314
|
+
const subCost = estimateSessionCost(subUsage, book, currency);
|
|
10972
11315
|
const fmtRate = (usd) => formatPriceRate(toCurrency(usd, currency), currency);
|
|
10973
|
-
const rows = priceRowsOf(usage,
|
|
11316
|
+
const rows = priceRowsOf(usage, book);
|
|
10974
11317
|
const deepseek = usage !== void 0 && Object.keys(usage).some((p) => isDeepSeekProvider(p));
|
|
10975
11318
|
const subDeepseek = subUsage !== null && Object.keys(subUsage).some((p) => isDeepSeekProvider(p));
|
|
10976
11319
|
const anyPair = rows.some((r) => r.offRate !== void 0);
|
|
10977
|
-
const unpriced = rows.length === 0 && usage !== void 0 && Object.keys(usage).length > 0 && (failed ||
|
|
10978
|
-
const subUnpriced = subUsage !== null && priceRowsOf(subUsage,
|
|
11320
|
+
const unpriced = rows.length === 0 && usage !== void 0 && Object.keys(usage).length > 0 && (failed || book !== null);
|
|
11321
|
+
const subUnpriced = subUsage !== null && priceRowsOf(subUsage, book).length === 0 && (failed || book !== null);
|
|
10979
11322
|
const costTip = [
|
|
10980
11323
|
t("stats.costTip") + (deepseek ? " " + t("stats.costTipDeepseek") : ""),
|
|
10981
11324
|
rows.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
@@ -12021,7 +12364,7 @@ window.__ModuleLoader__.load({
|
|
|
12021
12364
|
}
|
|
12022
12365
|
//#endregion
|
|
12023
12366
|
//#region \0dsh-global-css:/home/runner/work/dsh-context/dsh-context/src/client/styles/trendChart.css.mjs
|
|
12024
|
-
const css$9 = ".lc-chartrow{align-items:stretch;gap:6px;display:flex}.lc-axis{box-sizing:border-box;width:40px;height:150px;color:var(--dsw-alias-label-secondary);padding-top:18px;font-size:11px;position:relative}.lc-axis span{line-height:1;position:absolute;right:0}.lc-axis-top{top:13px}.lc-axis-q3{top:41px}.lc-axis-mid{top:69px}.lc-axis-q1{top:97px}.lc-axis-bot{top:125px}.lc-chart-wrap{flex:1;min-width:0;position:relative}.lc-chart-scroll{overscroll-behavior-x:contain;scrollbar-gutter:stable;padding-bottom:var(--dsh-scrollbar-width,8px);overflow:auto hidden}.lc-chart{box-sizing:border-box;align-items:flex-end;gap:2px;width:max-content;min-width:100%;height:130px;padding
|
|
12367
|
+
const css$9 = ".lc-chartrow{align-items:stretch;gap:6px;display:flex}.lc-axis{box-sizing:border-box;width:40px;height:150px;color:var(--dsw-alias-label-secondary);padding-top:18px;font-size:11px;position:relative}.lc-axis span{line-height:1;position:absolute;right:0}.lc-axis-top{top:13px}.lc-axis-q3{top:41px}.lc-axis-mid{top:69px}.lc-axis-q1{top:97px}.lc-axis-bot{top:125px}.lc-chart-wrap{flex:1;min-width:0;position:relative}.lc-chart-scroll{overscroll-behavior-x:contain;scrollbar-gutter:stable;padding-bottom:var(--dsh-scrollbar-width,8px);overflow:auto hidden}.lc-chart{box-sizing:border-box;align-items:flex-end;gap:2px;width:max-content;min-width:100%;height:130px;padding:18px 2px 0;display:flex;position:relative}.lc-grid{border-top:1px dashed var(--dsw-alias-border-l2);pointer-events:none;position:absolute;left:0;right:0}.lc-grid-top{top:18px}.lc-grid-q3{top:46px}.lc-grid-mid{top:74px}.lc-grid-q1{top:102px}.lc-grid-zero{border-top-style:solid;border-top-color:color-mix(in srgb, var(--color-neutral-500) 50%, transparent);top:130px}.lc-bar{cursor:pointer;outline-offset:1px;width:14px;height:100%;transition:opacity var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), background-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), outline-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);border-radius:2px;outline:1px dashed #0000;flex:none;align-items:flex-end;display:flex;position:relative}.lc-chart-dim .lc-bar{opacity:.35}.lc-chart-dim .lc-bar-in-turn{opacity:1}.lc-chart-dim .lc-turn{opacity:.35}.lc-chart-dim .lc-turn-on{opacity:1}.lc-chart-tip{z-index:5;box-sizing:border-box;overflow-wrap:break-word;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);max-width:100%;color:var(--dsw-alias-label-primary);pointer-events:none;border-radius:6px;flex-direction:column;gap:2px;padding:3px 8px;font-size:12px;display:flex;position:absolute;bottom:calc(100% + 4px);left:0;box-shadow:0 2px 8px #0000002e}.lc-chart-tip span+span{color:var(--dsw-alias-label-secondary)}.lc-bar-hovered{outline-color:var(--dsw-alias-brand-primary)}.lc-bar-selected{outline:2px solid var(--dsw-alias-label-primary);outline-offset:1px}.lc-bar-in-turn{background:color-mix(in srgb, var(--color-neutral-500) 14%, transparent)}.lc-bar-stack{flex-direction:column-reverse;width:100%;display:flex}.lc-bar-stack>div{width:100%}.lc-bar-stack,.lc-bar-up,.lc-bar-down{transform-origin:50% 100%}.lc-bar-down{transform-origin:50% 0}.lc-bar-stack>div:first-child{border-radius:0 0 2px 2px}.lc-bar-stack>div:last-child{border-radius:2px 2px 0 0}.lc-bar-stack>div:only-child{border-radius:2px}.lc-bar-up,.lc-bar-down{width:100%;display:flex;position:absolute;left:0}.lc-bar-up{flex-direction:column-reverse}.lc-bar-down{flex-direction:column}.lc-bar-up>div,.lc-bar-down>div{width:100%}.lc-bar-up>div:last-child{border-radius:2px 2px 0 0}.lc-bar-down>div:last-child{border-radius:0 0 2px 2px}.lc-cat-seg{transition:filter var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), opacity var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out)}.lc-chart[data-catdim] .lc-cat-seg{opacity:.35}.lc-chart[data-catdim=system] .lc-cat-seg[data-cat=system],.lc-chart[data-catdim=tools] .lc-cat-seg[data-cat=tools],.lc-chart[data-catdim=user] .lc-cat-seg[data-cat=user],.lc-chart[data-catdim=inject] .lc-cat-seg[data-cat=inject],.lc-chart[data-catdim=skill] .lc-cat-seg[data-cat=skill],.lc-chart[data-catdim=assistant] .lc-cat-seg[data-cat=assistant],.lc-chart[data-catdim=tool] .lc-cat-seg[data-cat=tool]{opacity:1;filter:brightness(1.18)}.lc-bar-marker{color:var(--dsw-alias-state-warn-primary);font-size:11px;position:absolute;top:-16px;left:50%;transform:translate(-50%)}.lc-step-flag{background:color-mix(in srgb, var(--color-neutral-500) 45%, transparent);pointer-events:none;width:1px;position:absolute;top:-17px;bottom:0;right:-1px}.lc-step-flag-label{box-sizing:border-box;border:1px solid color-mix(in srgb, var(--color-neutral-500) 45%, transparent);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-secondary);white-space:nowrap;border-radius:3px;padding:1px 3px;font-size:9px;font-weight:600;line-height:1;position:absolute;top:0;right:0}.lc-turns{box-sizing:border-box;gap:2px;width:max-content;min-width:100%;margin-top:4px;padding:0 2px;display:flex;overflow:hidden}.lc-turn{box-sizing:border-box;text-align:center;color:var(--dsw-alias-label-secondary);white-space:nowrap;cursor:pointer;height:14px;transition:filter var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), opacity var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);border-radius:3px;flex:none;font-size:10px;font-weight:600;line-height:14px}.lc-turn-on{filter:brightness(1.35);color:var(--dsw-alias-label-primary)}.lc-turn-label{display:inline-block}";
|
|
12025
12368
|
const tagId$9 = "dsh-context/trendChart.css";
|
|
12026
12369
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$9) + "]") === null) {
|
|
12027
12370
|
const tag = document.createElement("style");
|
|
@@ -12120,7 +12463,7 @@ window.__ModuleLoader__.load({
|
|
|
12120
12463
|
}
|
|
12121
12464
|
//#endregion
|
|
12122
12465
|
//#region \0dsh-global-css:/home/runner/work/dsh-context/dsh-context/src/client/styles/overview.css.mjs
|
|
12123
|
-
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}";
|
|
12466
|
+
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}";
|
|
12124
12467
|
const tagId = "dsh-context/overview.css";
|
|
12125
12468
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
12126
12469
|
const tag = document.createElement("style");
|